xref: /openbmc/qemu/hw/intc/i8259.c (revision 28ae3179fc52d2e4d870b635c4a412aab99759e7)
149ab747fSPaolo Bonzini /*
249ab747fSPaolo Bonzini  * QEMU 8259 interrupt controller emulation
349ab747fSPaolo Bonzini  *
449ab747fSPaolo Bonzini  * Copyright (c) 2003-2004 Fabrice Bellard
549ab747fSPaolo Bonzini  *
649ab747fSPaolo Bonzini  * Permission is hereby granted, free of charge, to any person obtaining a copy
749ab747fSPaolo Bonzini  * of this software and associated documentation files (the "Software"), to deal
849ab747fSPaolo Bonzini  * in the Software without restriction, including without limitation the rights
949ab747fSPaolo Bonzini  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1049ab747fSPaolo Bonzini  * copies of the Software, and to permit persons to whom the Software is
1149ab747fSPaolo Bonzini  * furnished to do so, subject to the following conditions:
1249ab747fSPaolo Bonzini  *
1349ab747fSPaolo Bonzini  * The above copyright notice and this permission notice shall be included in
1449ab747fSPaolo Bonzini  * all copies or substantial portions of the Software.
1549ab747fSPaolo Bonzini  *
1649ab747fSPaolo Bonzini  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1749ab747fSPaolo Bonzini  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1849ab747fSPaolo Bonzini  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1949ab747fSPaolo Bonzini  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2049ab747fSPaolo Bonzini  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2149ab747fSPaolo Bonzini  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2249ab747fSPaolo Bonzini  * THE SOFTWARE.
2349ab747fSPaolo Bonzini  */
2464552b6bSMarkus Armbruster 
2590191d07SPeter Maydell #include "qemu/osdep.h"
26852c27e2SPaolo Bonzini #include "hw/intc/i8259.h"
2764552b6bSMarkus Armbruster #include "hw/irq.h"
2849ab747fSPaolo Bonzini #include "hw/isa/isa.h"
2949ab747fSPaolo Bonzini #include "qemu/timer.h"
3003dd024fSPaolo Bonzini #include "qemu/log.h"
3149ab747fSPaolo Bonzini #include "hw/isa/i8259_internal.h"
320880a873SPeter Xu #include "trace.h"
33db1015e9SEduardo Habkost #include "qom/object.h"
3449ab747fSPaolo Bonzini 
3549ab747fSPaolo Bonzini /* debug PIC */
3649ab747fSPaolo Bonzini //#define DEBUG_PIC
3749ab747fSPaolo Bonzini 
3849ab747fSPaolo Bonzini //#define DEBUG_IRQ_LATENCY
3949ab747fSPaolo Bonzini 
40d1eebf4eSAndreas Färber #define TYPE_I8259 "isa-i8259"
41db1015e9SEduardo Habkost typedef struct PICClass PICClass;
428110fa1dSEduardo Habkost DECLARE_CLASS_CHECKERS(PICClass, PIC,
438110fa1dSEduardo Habkost                        TYPE_I8259)
44d2628b7dSAndreas Färber 
45d2628b7dSAndreas Färber /**
46d2628b7dSAndreas Färber  * PICClass:
47d2628b7dSAndreas Färber  * @parent_realize: The parent's realizefn.
48d2628b7dSAndreas Färber  */
49db1015e9SEduardo Habkost struct PICClass {
50d2628b7dSAndreas Färber     PICCommonClass parent_class;
51d2628b7dSAndreas Färber 
52d2628b7dSAndreas Färber     DeviceRealize parent_realize;
53db1015e9SEduardo Habkost };
54d1eebf4eSAndreas Färber 
5549ab747fSPaolo Bonzini #ifdef DEBUG_IRQ_LATENCY
5649ab747fSPaolo Bonzini static int64_t irq_time[16];
5749ab747fSPaolo Bonzini #endif
582aaf0ec7SBernhard Beschow PICCommonState *isa_pic;
5949ab747fSPaolo Bonzini static PICCommonState *slave_pic;
6049ab747fSPaolo Bonzini 
6149ab747fSPaolo Bonzini /* return the highest priority found in mask (highest = smallest
6249ab747fSPaolo Bonzini    number). Return 8 if no irq */
get_priority(PICCommonState * s,int mask)6349ab747fSPaolo Bonzini static int get_priority(PICCommonState *s, int mask)
6449ab747fSPaolo Bonzini {
6549ab747fSPaolo Bonzini     int priority;
6649ab747fSPaolo Bonzini 
6749ab747fSPaolo Bonzini     if (mask == 0) {
6849ab747fSPaolo Bonzini         return 8;
6949ab747fSPaolo Bonzini     }
7049ab747fSPaolo Bonzini     priority = 0;
7149ab747fSPaolo Bonzini     while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0) {
7249ab747fSPaolo Bonzini         priority++;
7349ab747fSPaolo Bonzini     }
7449ab747fSPaolo Bonzini     return priority;
7549ab747fSPaolo Bonzini }
7649ab747fSPaolo Bonzini 
7749ab747fSPaolo Bonzini /* return the pic wanted interrupt. return -1 if none */
pic_get_irq(PICCommonState * s)7849ab747fSPaolo Bonzini static int pic_get_irq(PICCommonState *s)
7949ab747fSPaolo Bonzini {
8049ab747fSPaolo Bonzini     int mask, cur_priority, priority;
8149ab747fSPaolo Bonzini 
8249ab747fSPaolo Bonzini     mask = s->irr & ~s->imr;
8349ab747fSPaolo Bonzini     priority = get_priority(s, mask);
8449ab747fSPaolo Bonzini     if (priority == 8) {
8549ab747fSPaolo Bonzini         return -1;
8649ab747fSPaolo Bonzini     }
8749ab747fSPaolo Bonzini     /* compute current priority. If special fully nested mode on the
8849ab747fSPaolo Bonzini        master, the IRQ coming from the slave is not taken into account
8949ab747fSPaolo Bonzini        for the priority computation. */
9049ab747fSPaolo Bonzini     mask = s->isr;
9149ab747fSPaolo Bonzini     if (s->special_mask) {
9249ab747fSPaolo Bonzini         mask &= ~s->imr;
9349ab747fSPaolo Bonzini     }
9449ab747fSPaolo Bonzini     if (s->special_fully_nested_mode && s->master) {
9549ab747fSPaolo Bonzini         mask &= ~(1 << 2);
9649ab747fSPaolo Bonzini     }
9749ab747fSPaolo Bonzini     cur_priority = get_priority(s, mask);
9849ab747fSPaolo Bonzini     if (priority < cur_priority) {
9949ab747fSPaolo Bonzini         /* higher priority found: an irq should be generated */
10049ab747fSPaolo Bonzini         return (priority + s->priority_add) & 7;
10149ab747fSPaolo Bonzini     } else {
10249ab747fSPaolo Bonzini         return -1;
10349ab747fSPaolo Bonzini     }
10449ab747fSPaolo Bonzini }
10549ab747fSPaolo Bonzini 
10649ab747fSPaolo Bonzini /* Update INT output. Must be called every time the output may have changed. */
pic_update_irq(PICCommonState * s)10749ab747fSPaolo Bonzini static void pic_update_irq(PICCommonState *s)
10849ab747fSPaolo Bonzini {
10949ab747fSPaolo Bonzini     int irq;
11049ab747fSPaolo Bonzini 
11149ab747fSPaolo Bonzini     irq = pic_get_irq(s);
11249ab747fSPaolo Bonzini     if (irq >= 0) {
1130880a873SPeter Xu         trace_pic_update_irq(s->master, s->imr, s->irr, s->priority_add);
11449ab747fSPaolo Bonzini         qemu_irq_raise(s->int_out[0]);
11549ab747fSPaolo Bonzini     } else {
11649ab747fSPaolo Bonzini         qemu_irq_lower(s->int_out[0]);
11749ab747fSPaolo Bonzini     }
11849ab747fSPaolo Bonzini }
11949ab747fSPaolo Bonzini 
12049ab747fSPaolo Bonzini /* set irq level. If an edge is detected, then the IRR is set to 1 */
pic_set_irq(void * opaque,int irq,int level)12149ab747fSPaolo Bonzini static void pic_set_irq(void *opaque, int irq, int level)
12249ab747fSPaolo Bonzini {
12349ab747fSPaolo Bonzini     PICCommonState *s = opaque;
12449ab747fSPaolo Bonzini     int mask = 1 << irq;
12549ab747fSPaolo Bonzini     int irq_index = s->master ? irq : irq + 8;
1260880a873SPeter Xu 
1270880a873SPeter Xu     trace_pic_set_irq(s->master, irq, level);
1281b23190aSPeter Xu     pic_stat_update_irq(irq_index, level);
129f260f736SPeter Xu 
13049ab747fSPaolo Bonzini #ifdef DEBUG_IRQ_LATENCY
13149ab747fSPaolo Bonzini     if (level) {
132bc72ad67SAlex Bligh         irq_time[irq_index] = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
13349ab747fSPaolo Bonzini     }
13449ab747fSPaolo Bonzini #endif
13549ab747fSPaolo Bonzini 
136ecb0e98bSDavid Woodhouse     if (s->ltim || (s->elcr & mask)) {
13749ab747fSPaolo Bonzini         /* level triggered */
13849ab747fSPaolo Bonzini         if (level) {
13949ab747fSPaolo Bonzini             s->irr |= mask;
14049ab747fSPaolo Bonzini             s->last_irr |= mask;
14149ab747fSPaolo Bonzini         } else {
14249ab747fSPaolo Bonzini             s->irr &= ~mask;
14349ab747fSPaolo Bonzini             s->last_irr &= ~mask;
14449ab747fSPaolo Bonzini         }
14549ab747fSPaolo Bonzini     } else {
14649ab747fSPaolo Bonzini         /* edge triggered */
14749ab747fSPaolo Bonzini         if (level) {
14849ab747fSPaolo Bonzini             if ((s->last_irr & mask) == 0) {
14949ab747fSPaolo Bonzini                 s->irr |= mask;
15049ab747fSPaolo Bonzini             }
15149ab747fSPaolo Bonzini             s->last_irr |= mask;
15249ab747fSPaolo Bonzini         } else {
15349ab747fSPaolo Bonzini             s->last_irr &= ~mask;
15449ab747fSPaolo Bonzini         }
15549ab747fSPaolo Bonzini     }
15649ab747fSPaolo Bonzini     pic_update_irq(s);
15749ab747fSPaolo Bonzini }
15849ab747fSPaolo Bonzini 
15949ab747fSPaolo Bonzini /* acknowledge interrupt 'irq' */
pic_intack(PICCommonState * s,int irq)16049ab747fSPaolo Bonzini static void pic_intack(PICCommonState *s, int irq)
16149ab747fSPaolo Bonzini {
16249ab747fSPaolo Bonzini     if (s->auto_eoi) {
16349ab747fSPaolo Bonzini         if (s->rotate_on_auto_eoi) {
16449ab747fSPaolo Bonzini             s->priority_add = (irq + 1) & 7;
16549ab747fSPaolo Bonzini         }
16649ab747fSPaolo Bonzini     } else {
16749ab747fSPaolo Bonzini         s->isr |= (1 << irq);
16849ab747fSPaolo Bonzini     }
16949ab747fSPaolo Bonzini     /* We don't clear a level sensitive interrupt here */
170ecb0e98bSDavid Woodhouse     if (!s->ltim && !(s->elcr & (1 << irq))) {
17149ab747fSPaolo Bonzini         s->irr &= ~(1 << irq);
17249ab747fSPaolo Bonzini     }
17349ab747fSPaolo Bonzini     pic_update_irq(s);
17449ab747fSPaolo Bonzini }
17549ab747fSPaolo Bonzini 
pic_read_irq(PICCommonState * s)1762aaf0ec7SBernhard Beschow int pic_read_irq(PICCommonState *s)
17749ab747fSPaolo Bonzini {
17852ad57a9SPhilippe Mathieu-Daudé     int irq, intno;
17949ab747fSPaolo Bonzini 
18049ab747fSPaolo Bonzini     irq = pic_get_irq(s);
18149ab747fSPaolo Bonzini     if (irq >= 0) {
18252ad57a9SPhilippe Mathieu-Daudé         int irq2;
18352ad57a9SPhilippe Mathieu-Daudé 
18449ab747fSPaolo Bonzini         if (irq == 2) {
18549ab747fSPaolo Bonzini             irq2 = pic_get_irq(slave_pic);
18649ab747fSPaolo Bonzini             if (irq2 >= 0) {
18749ab747fSPaolo Bonzini                 pic_intack(slave_pic, irq2);
18849ab747fSPaolo Bonzini             } else {
18949ab747fSPaolo Bonzini                 /* spurious IRQ on slave controller */
19049ab747fSPaolo Bonzini                 irq2 = 7;
19149ab747fSPaolo Bonzini             }
19249ab747fSPaolo Bonzini             intno = slave_pic->irq_base + irq2;
19352ad57a9SPhilippe Mathieu-Daudé             pic_intack(s, irq);
19452ad57a9SPhilippe Mathieu-Daudé             irq = irq2 + 8;
19549ab747fSPaolo Bonzini         } else {
19649ab747fSPaolo Bonzini             intno = s->irq_base + irq;
19749ab747fSPaolo Bonzini             pic_intack(s, irq);
19852ad57a9SPhilippe Mathieu-Daudé         }
19949ab747fSPaolo Bonzini     } else {
20049ab747fSPaolo Bonzini         /* spurious IRQ on host controller */
20149ab747fSPaolo Bonzini         irq = 7;
20249ab747fSPaolo Bonzini         intno = s->irq_base + irq;
20349ab747fSPaolo Bonzini     }
20449ab747fSPaolo Bonzini 
20549ab747fSPaolo Bonzini #ifdef DEBUG_IRQ_LATENCY
20649ab747fSPaolo Bonzini     printf("IRQ%d latency=%0.3fus\n",
20749ab747fSPaolo Bonzini            irq,
208bc72ad67SAlex Bligh            (double)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) -
20973bcb24dSRutuja Shah                     irq_time[irq]) * 1000000.0 / NANOSECONDS_PER_SECOND);
21049ab747fSPaolo Bonzini #endif
2110880a873SPeter Xu 
2120880a873SPeter Xu     trace_pic_interrupt(irq, intno);
21349ab747fSPaolo Bonzini     return intno;
21449ab747fSPaolo Bonzini }
21549ab747fSPaolo Bonzini 
pic_init_reset(PICCommonState * s)21649ab747fSPaolo Bonzini static void pic_init_reset(PICCommonState *s)
21749ab747fSPaolo Bonzini {
21849ab747fSPaolo Bonzini     pic_reset_common(s);
21949ab747fSPaolo Bonzini     pic_update_irq(s);
22049ab747fSPaolo Bonzini }
22149ab747fSPaolo Bonzini 
pic_reset(DeviceState * dev)22249ab747fSPaolo Bonzini static void pic_reset(DeviceState *dev)
22349ab747fSPaolo Bonzini {
22429bb5317SAndreas Färber     PICCommonState *s = PIC_COMMON(dev);
22549ab747fSPaolo Bonzini 
22649ab747fSPaolo Bonzini     s->elcr = 0;
227ecb0e98bSDavid Woodhouse     s->ltim = 0;
22849ab747fSPaolo Bonzini     pic_init_reset(s);
22949ab747fSPaolo Bonzini }
23049ab747fSPaolo Bonzini 
pic_ioport_write(void * opaque,hwaddr addr64,uint64_t val64,unsigned size)23149ab747fSPaolo Bonzini static void pic_ioport_write(void *opaque, hwaddr addr64,
23249ab747fSPaolo Bonzini                              uint64_t val64, unsigned size)
23349ab747fSPaolo Bonzini {
23449ab747fSPaolo Bonzini     PICCommonState *s = opaque;
23549ab747fSPaolo Bonzini     uint32_t addr = addr64;
23649ab747fSPaolo Bonzini     uint32_t val = val64;
23749ab747fSPaolo Bonzini     int priority, cmd, irq;
23849ab747fSPaolo Bonzini 
2390880a873SPeter Xu     trace_pic_ioport_write(s->master, addr, val);
2400880a873SPeter Xu 
24149ab747fSPaolo Bonzini     if (addr == 0) {
24249ab747fSPaolo Bonzini         if (val & 0x10) {
24349ab747fSPaolo Bonzini             pic_init_reset(s);
24449ab747fSPaolo Bonzini             s->init_state = 1;
24549ab747fSPaolo Bonzini             s->init4 = val & 1;
24649ab747fSPaolo Bonzini             s->single_mode = val & 2;
247ecb0e98bSDavid Woodhouse             s->ltim = val & 8;
24849ab747fSPaolo Bonzini         } else if (val & 0x08) {
24949ab747fSPaolo Bonzini             if (val & 0x04) {
25049ab747fSPaolo Bonzini                 s->poll = 1;
25149ab747fSPaolo Bonzini             }
25249ab747fSPaolo Bonzini             if (val & 0x02) {
25349ab747fSPaolo Bonzini                 s->read_reg_select = val & 1;
25449ab747fSPaolo Bonzini             }
25549ab747fSPaolo Bonzini             if (val & 0x40) {
25649ab747fSPaolo Bonzini                 s->special_mask = (val >> 5) & 1;
25749ab747fSPaolo Bonzini             }
25849ab747fSPaolo Bonzini         } else {
25949ab747fSPaolo Bonzini             cmd = val >> 5;
26049ab747fSPaolo Bonzini             switch (cmd) {
26149ab747fSPaolo Bonzini             case 0:
26249ab747fSPaolo Bonzini             case 4:
26349ab747fSPaolo Bonzini                 s->rotate_on_auto_eoi = cmd >> 2;
26449ab747fSPaolo Bonzini                 break;
26549ab747fSPaolo Bonzini             case 1: /* end of interrupt */
26649ab747fSPaolo Bonzini             case 5:
26749ab747fSPaolo Bonzini                 priority = get_priority(s, s->isr);
26849ab747fSPaolo Bonzini                 if (priority != 8) {
26949ab747fSPaolo Bonzini                     irq = (priority + s->priority_add) & 7;
27049ab747fSPaolo Bonzini                     s->isr &= ~(1 << irq);
27149ab747fSPaolo Bonzini                     if (cmd == 5) {
27249ab747fSPaolo Bonzini                         s->priority_add = (irq + 1) & 7;
27349ab747fSPaolo Bonzini                     }
27449ab747fSPaolo Bonzini                     pic_update_irq(s);
27549ab747fSPaolo Bonzini                 }
27649ab747fSPaolo Bonzini                 break;
27749ab747fSPaolo Bonzini             case 3:
27849ab747fSPaolo Bonzini                 irq = val & 7;
27949ab747fSPaolo Bonzini                 s->isr &= ~(1 << irq);
28049ab747fSPaolo Bonzini                 pic_update_irq(s);
28149ab747fSPaolo Bonzini                 break;
28249ab747fSPaolo Bonzini             case 6:
28349ab747fSPaolo Bonzini                 s->priority_add = (val + 1) & 7;
28449ab747fSPaolo Bonzini                 pic_update_irq(s);
28549ab747fSPaolo Bonzini                 break;
28649ab747fSPaolo Bonzini             case 7:
28749ab747fSPaolo Bonzini                 irq = val & 7;
28849ab747fSPaolo Bonzini                 s->isr &= ~(1 << irq);
28949ab747fSPaolo Bonzini                 s->priority_add = (irq + 1) & 7;
29049ab747fSPaolo Bonzini                 pic_update_irq(s);
29149ab747fSPaolo Bonzini                 break;
29249ab747fSPaolo Bonzini             default:
29349ab747fSPaolo Bonzini                 /* no operation */
29449ab747fSPaolo Bonzini                 break;
29549ab747fSPaolo Bonzini             }
29649ab747fSPaolo Bonzini         }
29749ab747fSPaolo Bonzini     } else {
29849ab747fSPaolo Bonzini         switch (s->init_state) {
29949ab747fSPaolo Bonzini         case 0:
30049ab747fSPaolo Bonzini             /* normal mode */
30149ab747fSPaolo Bonzini             s->imr = val;
30249ab747fSPaolo Bonzini             pic_update_irq(s);
30349ab747fSPaolo Bonzini             break;
30449ab747fSPaolo Bonzini         case 1:
30549ab747fSPaolo Bonzini             s->irq_base = val & 0xf8;
30649ab747fSPaolo Bonzini             s->init_state = s->single_mode ? (s->init4 ? 3 : 0) : 2;
30749ab747fSPaolo Bonzini             break;
30849ab747fSPaolo Bonzini         case 2:
30949ab747fSPaolo Bonzini             if (s->init4) {
31049ab747fSPaolo Bonzini                 s->init_state = 3;
31149ab747fSPaolo Bonzini             } else {
31249ab747fSPaolo Bonzini                 s->init_state = 0;
31349ab747fSPaolo Bonzini             }
31449ab747fSPaolo Bonzini             break;
31549ab747fSPaolo Bonzini         case 3:
31649ab747fSPaolo Bonzini             s->special_fully_nested_mode = (val >> 4) & 1;
31749ab747fSPaolo Bonzini             s->auto_eoi = (val >> 1) & 1;
31849ab747fSPaolo Bonzini             s->init_state = 0;
31949ab747fSPaolo Bonzini             break;
32049ab747fSPaolo Bonzini         }
32149ab747fSPaolo Bonzini     }
32249ab747fSPaolo Bonzini }
32349ab747fSPaolo Bonzini 
pic_ioport_read(void * opaque,hwaddr addr,unsigned size)32449ab747fSPaolo Bonzini static uint64_t pic_ioport_read(void *opaque, hwaddr addr,
32549ab747fSPaolo Bonzini                                 unsigned size)
32649ab747fSPaolo Bonzini {
32749ab747fSPaolo Bonzini     PICCommonState *s = opaque;
32849ab747fSPaolo Bonzini     int ret;
32949ab747fSPaolo Bonzini 
33049ab747fSPaolo Bonzini     if (s->poll) {
33149ab747fSPaolo Bonzini         ret = pic_get_irq(s);
33249ab747fSPaolo Bonzini         if (ret >= 0) {
33349ab747fSPaolo Bonzini             pic_intack(s, ret);
33449ab747fSPaolo Bonzini             ret |= 0x80;
33549ab747fSPaolo Bonzini         } else {
33649ab747fSPaolo Bonzini             ret = 0;
33749ab747fSPaolo Bonzini         }
33849ab747fSPaolo Bonzini         s->poll = 0;
33949ab747fSPaolo Bonzini     } else {
34049ab747fSPaolo Bonzini         if (addr == 0) {
34149ab747fSPaolo Bonzini             if (s->read_reg_select) {
34249ab747fSPaolo Bonzini                 ret = s->isr;
34349ab747fSPaolo Bonzini             } else {
34449ab747fSPaolo Bonzini                 ret = s->irr;
34549ab747fSPaolo Bonzini             }
34649ab747fSPaolo Bonzini         } else {
34749ab747fSPaolo Bonzini             ret = s->imr;
34849ab747fSPaolo Bonzini         }
34949ab747fSPaolo Bonzini     }
3500880a873SPeter Xu     trace_pic_ioport_read(s->master, addr, ret);
35149ab747fSPaolo Bonzini     return ret;
35249ab747fSPaolo Bonzini }
35349ab747fSPaolo Bonzini 
pic_get_output(PICCommonState * s)3542aaf0ec7SBernhard Beschow int pic_get_output(PICCommonState *s)
35549ab747fSPaolo Bonzini {
35649ab747fSPaolo Bonzini     return (pic_get_irq(s) >= 0);
35749ab747fSPaolo Bonzini }
35849ab747fSPaolo Bonzini 
elcr_ioport_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)35949ab747fSPaolo Bonzini static void elcr_ioport_write(void *opaque, hwaddr addr,
36049ab747fSPaolo Bonzini                               uint64_t val, unsigned size)
36149ab747fSPaolo Bonzini {
36249ab747fSPaolo Bonzini     PICCommonState *s = opaque;
36349ab747fSPaolo Bonzini     s->elcr = val & s->elcr_mask;
36449ab747fSPaolo Bonzini }
36549ab747fSPaolo Bonzini 
elcr_ioport_read(void * opaque,hwaddr addr,unsigned size)36649ab747fSPaolo Bonzini static uint64_t elcr_ioport_read(void *opaque, hwaddr addr,
36749ab747fSPaolo Bonzini                                  unsigned size)
36849ab747fSPaolo Bonzini {
36949ab747fSPaolo Bonzini     PICCommonState *s = opaque;
37049ab747fSPaolo Bonzini     return s->elcr;
37149ab747fSPaolo Bonzini }
37249ab747fSPaolo Bonzini 
37349ab747fSPaolo Bonzini static const MemoryRegionOps pic_base_ioport_ops = {
37449ab747fSPaolo Bonzini     .read = pic_ioport_read,
37549ab747fSPaolo Bonzini     .write = pic_ioport_write,
37649ab747fSPaolo Bonzini     .impl = {
37749ab747fSPaolo Bonzini         .min_access_size = 1,
37849ab747fSPaolo Bonzini         .max_access_size = 1,
37949ab747fSPaolo Bonzini     },
38049ab747fSPaolo Bonzini };
38149ab747fSPaolo Bonzini 
38249ab747fSPaolo Bonzini static const MemoryRegionOps pic_elcr_ioport_ops = {
38349ab747fSPaolo Bonzini     .read = elcr_ioport_read,
38449ab747fSPaolo Bonzini     .write = elcr_ioport_write,
38549ab747fSPaolo Bonzini     .impl = {
38649ab747fSPaolo Bonzini         .min_access_size = 1,
38749ab747fSPaolo Bonzini         .max_access_size = 1,
38849ab747fSPaolo Bonzini     },
38949ab747fSPaolo Bonzini };
39049ab747fSPaolo Bonzini 
pic_realize(DeviceState * dev,Error ** errp)391a7737e44SMarkus Armbruster static void pic_realize(DeviceState *dev, Error **errp)
39249ab747fSPaolo Bonzini {
393d2628b7dSAndreas Färber     PICCommonState *s = PIC_COMMON(dev);
394d2628b7dSAndreas Färber     PICClass *pc = PIC_GET_CLASS(dev);
39529bb5317SAndreas Färber 
3961437c94bSPaolo Bonzini     memory_region_init_io(&s->base_io, OBJECT(s), &pic_base_ioport_ops, s,
3971437c94bSPaolo Bonzini                           "pic", 2);
3981437c94bSPaolo Bonzini     memory_region_init_io(&s->elcr_io, OBJECT(s), &pic_elcr_ioport_ops, s,
3991437c94bSPaolo Bonzini                           "elcr", 1);
40049ab747fSPaolo Bonzini 
40129bb5317SAndreas Färber     qdev_init_gpio_out(dev, s->int_out, ARRAY_SIZE(s->int_out));
40229bb5317SAndreas Färber     qdev_init_gpio_in(dev, pic_set_irq, 8);
403d2628b7dSAndreas Färber 
404a7737e44SMarkus Armbruster     pc->parent_realize(dev, errp);
40549ab747fSPaolo Bonzini }
40649ab747fSPaolo Bonzini 
i8259_init(ISABus * bus,qemu_irq parent_irq_in)40778827d5fSPhilippe Mathieu-Daudé qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq_in)
40849ab747fSPaolo Bonzini {
40949ab747fSPaolo Bonzini     qemu_irq *irq_set;
410d1eebf4eSAndreas Färber     DeviceState *dev;
411d1eebf4eSAndreas Färber     ISADevice *isadev;
41249ab747fSPaolo Bonzini     int i;
41349ab747fSPaolo Bonzini 
4148945c7f7SPeter Crosthwaite     irq_set = g_new0(qemu_irq, ISA_NUM_IRQS);
41549ab747fSPaolo Bonzini 
416d1eebf4eSAndreas Färber     isadev = i8259_init_chip(TYPE_I8259, bus, true);
417d1eebf4eSAndreas Färber     dev = DEVICE(isadev);
41849ab747fSPaolo Bonzini 
41978827d5fSPhilippe Mathieu-Daudé     qdev_connect_gpio_out(dev, 0, parent_irq_in);
42049ab747fSPaolo Bonzini     for (i = 0 ; i < 8; i++) {
421d1eebf4eSAndreas Färber         irq_set[i] = qdev_get_gpio_in(dev, i);
42249ab747fSPaolo Bonzini     }
42349ab747fSPaolo Bonzini 
4242aaf0ec7SBernhard Beschow     isa_pic = PIC_COMMON(dev);
42549ab747fSPaolo Bonzini 
426d1eebf4eSAndreas Färber     isadev = i8259_init_chip(TYPE_I8259, bus, false);
427d1eebf4eSAndreas Färber     dev = DEVICE(isadev);
42849ab747fSPaolo Bonzini 
429d1eebf4eSAndreas Färber     qdev_connect_gpio_out(dev, 0, irq_set[2]);
43049ab747fSPaolo Bonzini     for (i = 0 ; i < 8; i++) {
431d1eebf4eSAndreas Färber         irq_set[i + 8] = qdev_get_gpio_in(dev, i);
43249ab747fSPaolo Bonzini     }
43349ab747fSPaolo Bonzini 
43429bb5317SAndreas Färber     slave_pic = PIC_COMMON(dev);
43549ab747fSPaolo Bonzini 
43649ab747fSPaolo Bonzini     return irq_set;
43749ab747fSPaolo Bonzini }
43849ab747fSPaolo Bonzini 
i8259_class_init(ObjectClass * klass,void * data)43949ab747fSPaolo Bonzini static void i8259_class_init(ObjectClass *klass, void *data)
44049ab747fSPaolo Bonzini {
441d2628b7dSAndreas Färber     PICClass *k = PIC_CLASS(klass);
44249ab747fSPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
44349ab747fSPaolo Bonzini 
444bf853881SPhilippe Mathieu-Daudé     device_class_set_parent_realize(dc, pic_realize, &k->parent_realize);
445*e3d08143SPeter Maydell     device_class_set_legacy_reset(dc, pic_reset);
44649ab747fSPaolo Bonzini }
44749ab747fSPaolo Bonzini 
44849ab747fSPaolo Bonzini static const TypeInfo i8259_info = {
449d1eebf4eSAndreas Färber     .name       = TYPE_I8259,
45049ab747fSPaolo Bonzini     .instance_size = sizeof(PICCommonState),
45149ab747fSPaolo Bonzini     .parent     = TYPE_PIC_COMMON,
45249ab747fSPaolo Bonzini     .class_init = i8259_class_init,
453d2628b7dSAndreas Färber     .class_size = sizeof(PICClass),
45449ab747fSPaolo Bonzini };
45549ab747fSPaolo Bonzini 
pic_register_types(void)45649ab747fSPaolo Bonzini static void pic_register_types(void)
45749ab747fSPaolo Bonzini {
45849ab747fSPaolo Bonzini     type_register_static(&i8259_info);
45949ab747fSPaolo Bonzini }
46049ab747fSPaolo Bonzini 
46149ab747fSPaolo Bonzini type_init(pic_register_types)
462