blob: 1415bda93fe6b4213c6ddaebf3e41e3001d83f61 [file] [log] [blame]
bellard80cabfa2004-03-14 12:20:30 +00001/*
2 * QEMU 8259 interrupt controller emulation
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard80cabfa2004-03-14 12:20:30 +00004 * Copyright (c) 2003-2004 Fabrice Bellard
ths5fafdf22007-09-16 21:08:06 +00005 *
bellard80cabfa2004-03-14 12:20:30 +00006 * 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 */
Paolo Bonzini83c9f4c2013-02-04 15:40:22 +010024#include "hw/hw.h"
Paolo Bonzini0d09e412013-02-05 17:06:20 +010025#include "hw/i386/pc.h"
26#include "hw/isa/isa.h"
Paolo Bonzini83c90892012-12-17 18:19:49 +010027#include "monitor/monitor.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010028#include "qemu/timer.h"
Paolo Bonzini0d09e412013-02-05 17:06:20 +010029#include "hw/isa/i8259_internal.h"
bellard80cabfa2004-03-14 12:20:30 +000030
31/* debug PIC */
32//#define DEBUG_PIC
33
Blue Swirl8ac02ff2010-05-29 20:23:19 +000034#ifdef DEBUG_PIC
35#define DPRINTF(fmt, ...) \
36 do { printf("pic: " fmt , ## __VA_ARGS__); } while (0)
37#else
38#define DPRINTF(fmt, ...)
39#endif
40
bellardb41a2cd2004-03-14 21:46:48 +000041//#define DEBUG_IRQ_LATENCY
bellard4a0fb71e2004-05-21 11:39:07 +000042//#define DEBUG_IRQ_COUNT
bellardb41a2cd2004-03-14 21:46:48 +000043
Andreas Färberd1eebf42012-11-25 22:35:49 +010044#define TYPE_I8259 "isa-i8259"
Andreas Färberd2628b72012-11-25 22:54:47 +010045#define PIC_CLASS(class) OBJECT_CLASS_CHECK(PICClass, (class), TYPE_I8259)
46#define PIC_GET_CLASS(obj) OBJECT_GET_CLASS(PICClass, (obj), TYPE_I8259)
47
48/**
49 * PICClass:
50 * @parent_realize: The parent's realizefn.
51 */
52typedef struct PICClass {
53 PICCommonClass parent_class;
54
55 DeviceRealize parent_realize;
56} PICClass;
Andreas Färberd1eebf42012-11-25 22:35:49 +010057
Jan Kiszka81a02f92011-10-07 09:19:54 +020058#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
bellard4a0fb71e2004-05-21 11:39:07 +000059static int irq_level[16];
60#endif
61#ifdef DEBUG_IRQ_COUNT
62static uint64_t irq_count[16];
63#endif
Jan Kiszka747c70a2011-10-07 09:19:53 +020064#ifdef DEBUG_IRQ_LATENCY
65static int64_t irq_time[16];
66#endif
Jan Kiszka9aa78c42012-01-10 16:31:16 +010067DeviceState *isa_pic;
Jan Kiszka512709f2011-10-16 14:38:45 +020068static PICCommonState *slave_pic;
bellard4a0fb71e2004-05-21 11:39:07 +000069
bellard80cabfa2004-03-14 12:20:30 +000070/* return the highest priority found in mask (highest = smallest
71 number). Return 8 if no irq */
Jan Kiszka512709f2011-10-16 14:38:45 +020072static int get_priority(PICCommonState *s, int mask)
bellard80cabfa2004-03-14 12:20:30 +000073{
74 int priority;
Jan Kiszka81a02f92011-10-07 09:19:54 +020075
76 if (mask == 0) {
bellard80cabfa2004-03-14 12:20:30 +000077 return 8;
Jan Kiszka81a02f92011-10-07 09:19:54 +020078 }
bellard80cabfa2004-03-14 12:20:30 +000079 priority = 0;
Jan Kiszka81a02f92011-10-07 09:19:54 +020080 while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0) {
bellard80cabfa2004-03-14 12:20:30 +000081 priority++;
Jan Kiszka81a02f92011-10-07 09:19:54 +020082 }
bellard80cabfa2004-03-14 12:20:30 +000083 return priority;
84}
85
86/* return the pic wanted interrupt. return -1 if none */
Jan Kiszka512709f2011-10-16 14:38:45 +020087static int pic_get_irq(PICCommonState *s)
bellard80cabfa2004-03-14 12:20:30 +000088{
89 int mask, cur_priority, priority;
90
91 mask = s->irr & ~s->imr;
92 priority = get_priority(s, mask);
Jan Kiszka81a02f92011-10-07 09:19:54 +020093 if (priority == 8) {
bellard80cabfa2004-03-14 12:20:30 +000094 return -1;
Jan Kiszka81a02f92011-10-07 09:19:54 +020095 }
bellard80cabfa2004-03-14 12:20:30 +000096 /* compute current priority. If special fully nested mode on the
97 master, the IRQ coming from the slave is not taken into account
98 for the priority computation. */
99 mask = s->isr;
Jan Kiszka81a02f92011-10-07 09:19:54 +0200100 if (s->special_mask) {
balrog84678712008-07-19 09:18:48 +0000101 mask &= ~s->imr;
Jan Kiszka81a02f92011-10-07 09:19:54 +0200102 }
Jan Kiszka25985392011-10-07 09:19:50 +0200103 if (s->special_fully_nested_mode && s->master) {
bellard80cabfa2004-03-14 12:20:30 +0000104 mask &= ~(1 << 2);
Jan Kiszka25985392011-10-07 09:19:50 +0200105 }
bellard80cabfa2004-03-14 12:20:30 +0000106 cur_priority = get_priority(s, mask);
107 if (priority < cur_priority) {
108 /* higher priority found: an irq should be generated */
109 return (priority + s->priority_add) & 7;
110 } else {
111 return -1;
112 }
113}
114
Jan Kiszkab76750c2011-10-07 09:19:46 +0200115/* Update INT output. Must be called every time the output may have changed. */
Jan Kiszka512709f2011-10-16 14:38:45 +0200116static void pic_update_irq(PICCommonState *s)
bellard80cabfa2004-03-14 12:20:30 +0000117{
Jan Kiszkab76750c2011-10-07 09:19:46 +0200118 int irq;
bellard80cabfa2004-03-14 12:20:30 +0000119
Jan Kiszkab76750c2011-10-07 09:19:46 +0200120 irq = pic_get_irq(s);
bellard80cabfa2004-03-14 12:20:30 +0000121 if (irq >= 0) {
Jan Kiszkab76750c2011-10-07 09:19:46 +0200122 DPRINTF("pic%d: imr=%x irr=%x padd=%d\n",
Jan Kiszka25985392011-10-07 09:19:50 +0200123 s->master ? 0 : 1, s->imr, s->irr, s->priority_add);
Jan Kiszka747c70a2011-10-07 09:19:53 +0200124 qemu_irq_raise(s->int_out[0]);
Jan Kiszkad96e1732011-10-07 09:19:37 +0200125 } else {
Jan Kiszka747c70a2011-10-07 09:19:53 +0200126 qemu_irq_lower(s->int_out[0]);
ths4de9b242007-01-24 01:47:51 +0000127 }
bellard80cabfa2004-03-14 12:20:30 +0000128}
129
Jan Kiszka62026012011-10-07 09:19:40 +0200130/* set irq level. If an edge is detected, then the IRR is set to 1 */
Jan Kiszka747c70a2011-10-07 09:19:53 +0200131static void pic_set_irq(void *opaque, int irq, int level)
Jan Kiszka62026012011-10-07 09:19:40 +0200132{
Jan Kiszka512709f2011-10-16 14:38:45 +0200133 PICCommonState *s = opaque;
Jan Kiszka747c70a2011-10-07 09:19:53 +0200134 int mask = 1 << irq;
135
136#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) || \
137 defined(DEBUG_IRQ_LATENCY)
138 int irq_index = s->master ? irq : irq + 8;
139#endif
140#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
141 if (level != irq_level[irq_index]) {
142 DPRINTF("pic_set_irq: irq=%d level=%d\n", irq_index, level);
143 irq_level[irq_index] = level;
144#ifdef DEBUG_IRQ_COUNT
145 if (level == 1) {
146 irq_count[irq_index]++;
147 }
148#endif
149 }
150#endif
151#ifdef DEBUG_IRQ_LATENCY
152 if (level) {
153 irq_time[irq_index] = qemu_get_clock_ns(vm_clock);
154 }
155#endif
156
Jan Kiszka62026012011-10-07 09:19:40 +0200157 if (s->elcr & mask) {
158 /* level triggered */
159 if (level) {
160 s->irr |= mask;
161 s->last_irr |= mask;
162 } else {
163 s->irr &= ~mask;
164 s->last_irr &= ~mask;
165 }
166 } else {
167 /* edge triggered */
168 if (level) {
169 if ((s->last_irr & mask) == 0) {
170 s->irr |= mask;
171 }
172 s->last_irr |= mask;
173 } else {
174 s->last_irr &= ~mask;
175 }
176 }
Jan Kiszkab76750c2011-10-07 09:19:46 +0200177 pic_update_irq(s);
Jan Kiszka62026012011-10-07 09:19:40 +0200178}
179
bellard80cabfa2004-03-14 12:20:30 +0000180/* acknowledge interrupt 'irq' */
Jan Kiszka512709f2011-10-16 14:38:45 +0200181static void pic_intack(PICCommonState *s, int irq)
bellard80cabfa2004-03-14 12:20:30 +0000182{
183 if (s->auto_eoi) {
Jan Kiszka81a02f92011-10-07 09:19:54 +0200184 if (s->rotate_on_auto_eoi) {
bellard80cabfa2004-03-14 12:20:30 +0000185 s->priority_add = (irq + 1) & 7;
Jan Kiszka81a02f92011-10-07 09:19:54 +0200186 }
bellard80cabfa2004-03-14 12:20:30 +0000187 } else {
188 s->isr |= (1 << irq);
189 }
bellard0ecf89a2004-09-29 21:55:52 +0000190 /* We don't clear a level sensitive interrupt here */
Jan Kiszka81a02f92011-10-07 09:19:54 +0200191 if (!(s->elcr & (1 << irq))) {
bellard0ecf89a2004-09-29 21:55:52 +0000192 s->irr &= ~(1 << irq);
Jan Kiszka81a02f92011-10-07 09:19:54 +0200193 }
Jan Kiszkab76750c2011-10-07 09:19:46 +0200194 pic_update_irq(s);
bellard80cabfa2004-03-14 12:20:30 +0000195}
196
Jan Kiszka9aa78c42012-01-10 16:31:16 +0100197int pic_read_irq(DeviceState *d)
bellard80cabfa2004-03-14 12:20:30 +0000198{
Andreas Färber29bb5312013-04-27 22:18:40 +0200199 PICCommonState *s = PIC_COMMON(d);
bellard80cabfa2004-03-14 12:20:30 +0000200 int irq, irq2, intno;
201
Jan Kiszkac17725f2011-10-07 09:19:51 +0200202 irq = pic_get_irq(s);
bellard15aeac32004-05-20 16:12:05 +0000203 if (irq >= 0) {
bellard15aeac32004-05-20 16:12:05 +0000204 if (irq == 2) {
Jan Kiszkac17725f2011-10-07 09:19:51 +0200205 irq2 = pic_get_irq(slave_pic);
bellard15aeac32004-05-20 16:12:05 +0000206 if (irq2 >= 0) {
Jan Kiszkac17725f2011-10-07 09:19:51 +0200207 pic_intack(slave_pic, irq2);
bellard15aeac32004-05-20 16:12:05 +0000208 } else {
209 /* spurious IRQ on slave controller */
210 irq2 = 7;
211 }
Jan Kiszkac17725f2011-10-07 09:19:51 +0200212 intno = slave_pic->irq_base + irq2;
bellard15aeac32004-05-20 16:12:05 +0000213 } else {
Jan Kiszkac17725f2011-10-07 09:19:51 +0200214 intno = s->irq_base + irq;
bellard15aeac32004-05-20 16:12:05 +0000215 }
Jan Kiszkac17725f2011-10-07 09:19:51 +0200216 pic_intack(s, irq);
bellard15aeac32004-05-20 16:12:05 +0000217 } else {
218 /* spurious IRQ on host controller */
219 irq = 7;
Jan Kiszkac17725f2011-10-07 09:19:51 +0200220 intno = s->irq_base + irq;
bellard15aeac32004-05-20 16:12:05 +0000221 }
ths3b46e622007-09-17 08:09:54 +0000222
Jan Kiszka78ef2b62011-10-07 09:19:43 +0200223#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_LATENCY)
224 if (irq == 2) {
225 irq = irq2 + 8;
226 }
227#endif
bellard80cabfa2004-03-14 12:20:30 +0000228#ifdef DEBUG_IRQ_LATENCY
ths5fafdf22007-09-16 21:08:06 +0000229 printf("IRQ%d latency=%0.3fus\n",
230 irq,
Paolo Bonzini74475452011-03-11 16:47:48 +0100231 (double)(qemu_get_clock_ns(vm_clock) -
Juan Quintela6ee093c2009-09-10 03:04:26 +0200232 irq_time[irq]) * 1000000.0 / get_ticks_per_sec());
bellard80cabfa2004-03-14 12:20:30 +0000233#endif
Blue Swirl8ac02ff2010-05-29 20:23:19 +0000234 DPRINTF("pic_interrupt: irq=%d\n", irq);
bellard80cabfa2004-03-14 12:20:30 +0000235 return intno;
236}
237
Jan Kiszka512709f2011-10-16 14:38:45 +0200238static void pic_init_reset(PICCommonState *s)
bellardd7d02e32004-06-20 12:58:36 +0000239{
Jan Kiszka512709f2011-10-16 14:38:45 +0200240 pic_reset_common(s);
Jan Kiszkab76750c2011-10-07 09:19:46 +0200241 pic_update_irq(s);
bellardd7d02e32004-06-20 12:58:36 +0000242}
243
Jan Kiszka747c70a2011-10-07 09:19:53 +0200244static void pic_reset(DeviceState *dev)
Jan Kiszka86fbf972011-10-07 09:19:45 +0200245{
Andreas Färber29bb5312013-04-27 22:18:40 +0200246 PICCommonState *s = PIC_COMMON(dev);
Jan Kiszka86fbf972011-10-07 09:19:45 +0200247
Jan Kiszka86fbf972011-10-07 09:19:45 +0200248 s->elcr = 0;
Jan Kiszkaaa248222012-01-24 16:29:29 +0100249 pic_init_reset(s);
Jan Kiszka86fbf972011-10-07 09:19:45 +0200250}
251
Avi Kivitya8170e52012-10-23 12:30:10 +0200252static void pic_ioport_write(void *opaque, hwaddr addr64,
Richard Henderson098d3142011-08-10 15:28:16 -0700253 uint64_t val64, unsigned size)
bellard80cabfa2004-03-14 12:20:30 +0000254{
Jan Kiszka512709f2011-10-16 14:38:45 +0200255 PICCommonState *s = opaque;
Richard Henderson098d3142011-08-10 15:28:16 -0700256 uint32_t addr = addr64;
257 uint32_t val = val64;
bellardd7d02e32004-06-20 12:58:36 +0000258 int priority, cmd, irq;
bellard80cabfa2004-03-14 12:20:30 +0000259
Blue Swirl8ac02ff2010-05-29 20:23:19 +0000260 DPRINTF("write: addr=0x%02x val=0x%02x\n", addr, val);
bellard80cabfa2004-03-14 12:20:30 +0000261 if (addr == 0) {
262 if (val & 0x10) {
Jan Kiszka86fbf972011-10-07 09:19:45 +0200263 pic_init_reset(s);
bellard80cabfa2004-03-14 12:20:30 +0000264 s->init_state = 1;
265 s->init4 = val & 1;
ths20531522007-04-01 18:26:11 +0000266 s->single_mode = val & 2;
Jan Kiszka81a02f92011-10-07 09:19:54 +0200267 if (val & 0x08) {
bellard80cabfa2004-03-14 12:20:30 +0000268 hw_error("level sensitive irq not supported");
Jan Kiszka81a02f92011-10-07 09:19:54 +0200269 }
bellard80cabfa2004-03-14 12:20:30 +0000270 } else if (val & 0x08) {
Jan Kiszka81a02f92011-10-07 09:19:54 +0200271 if (val & 0x04) {
bellard80cabfa2004-03-14 12:20:30 +0000272 s->poll = 1;
Jan Kiszka81a02f92011-10-07 09:19:54 +0200273 }
274 if (val & 0x02) {
bellard80cabfa2004-03-14 12:20:30 +0000275 s->read_reg_select = val & 1;
Jan Kiszka81a02f92011-10-07 09:19:54 +0200276 }
277 if (val & 0x40) {
bellard80cabfa2004-03-14 12:20:30 +0000278 s->special_mask = (val >> 5) & 1;
Jan Kiszka81a02f92011-10-07 09:19:54 +0200279 }
bellard80cabfa2004-03-14 12:20:30 +0000280 } else {
281 cmd = val >> 5;
Jan Kiszka81a02f92011-10-07 09:19:54 +0200282 switch (cmd) {
bellard80cabfa2004-03-14 12:20:30 +0000283 case 0:
284 case 4:
285 s->rotate_on_auto_eoi = cmd >> 2;
286 break;
287 case 1: /* end of interrupt */
288 case 5:
289 priority = get_priority(s, s->isr);
290 if (priority != 8) {
291 irq = (priority + s->priority_add) & 7;
292 s->isr &= ~(1 << irq);
Jan Kiszka81a02f92011-10-07 09:19:54 +0200293 if (cmd == 5) {
bellard80cabfa2004-03-14 12:20:30 +0000294 s->priority_add = (irq + 1) & 7;
Jan Kiszka81a02f92011-10-07 09:19:54 +0200295 }
Jan Kiszkab76750c2011-10-07 09:19:46 +0200296 pic_update_irq(s);
bellard80cabfa2004-03-14 12:20:30 +0000297 }
298 break;
299 case 3:
300 irq = val & 7;
301 s->isr &= ~(1 << irq);
Jan Kiszkab76750c2011-10-07 09:19:46 +0200302 pic_update_irq(s);
bellard80cabfa2004-03-14 12:20:30 +0000303 break;
304 case 6:
305 s->priority_add = (val + 1) & 7;
Jan Kiszkab76750c2011-10-07 09:19:46 +0200306 pic_update_irq(s);
bellard80cabfa2004-03-14 12:20:30 +0000307 break;
308 case 7:
309 irq = val & 7;
310 s->isr &= ~(1 << irq);
311 s->priority_add = (irq + 1) & 7;
Jan Kiszkab76750c2011-10-07 09:19:46 +0200312 pic_update_irq(s);
bellard80cabfa2004-03-14 12:20:30 +0000313 break;
314 default:
315 /* no operation */
316 break;
317 }
318 }
319 } else {
Jan Kiszka81a02f92011-10-07 09:19:54 +0200320 switch (s->init_state) {
bellard80cabfa2004-03-14 12:20:30 +0000321 case 0:
322 /* normal mode */
323 s->imr = val;
Jan Kiszkab76750c2011-10-07 09:19:46 +0200324 pic_update_irq(s);
bellard80cabfa2004-03-14 12:20:30 +0000325 break;
326 case 1:
327 s->irq_base = val & 0xf8;
ths2bb081f2007-07-31 23:12:09 +0000328 s->init_state = s->single_mode ? (s->init4 ? 3 : 0) : 2;
bellard80cabfa2004-03-14 12:20:30 +0000329 break;
330 case 2:
331 if (s->init4) {
332 s->init_state = 3;
333 } else {
334 s->init_state = 0;
335 }
336 break;
337 case 3:
338 s->special_fully_nested_mode = (val >> 4) & 1;
339 s->auto_eoi = (val >> 1) & 1;
340 s->init_state = 0;
341 break;
342 }
343 }
344}
345
Avi Kivitya8170e52012-10-23 12:30:10 +0200346static uint64_t pic_ioport_read(void *opaque, hwaddr addr,
Richard Henderson098d3142011-08-10 15:28:16 -0700347 unsigned size)
bellard80cabfa2004-03-14 12:20:30 +0000348{
Jan Kiszka512709f2011-10-16 14:38:45 +0200349 PICCommonState *s = opaque;
bellard80cabfa2004-03-14 12:20:30 +0000350 int ret;
351
bellard80cabfa2004-03-14 12:20:30 +0000352 if (s->poll) {
Jan Kiszka8d484ca2011-10-07 09:19:47 +0200353 ret = pic_get_irq(s);
354 if (ret >= 0) {
355 pic_intack(s, ret);
356 ret |= 0x80;
357 } else {
358 ret = 0;
359 }
bellard80cabfa2004-03-14 12:20:30 +0000360 s->poll = 0;
361 } else {
362 if (addr == 0) {
Jan Kiszka81a02f92011-10-07 09:19:54 +0200363 if (s->read_reg_select) {
bellard80cabfa2004-03-14 12:20:30 +0000364 ret = s->isr;
Jan Kiszka81a02f92011-10-07 09:19:54 +0200365 } else {
bellard80cabfa2004-03-14 12:20:30 +0000366 ret = s->irr;
Jan Kiszka81a02f92011-10-07 09:19:54 +0200367 }
bellard80cabfa2004-03-14 12:20:30 +0000368 } else {
369 ret = s->imr;
370 }
371 }
malc08406b02012-08-27 18:33:24 +0400372 DPRINTF("read: addr=0x%02x val=0x%02x\n", addr, ret);
bellard80cabfa2004-03-14 12:20:30 +0000373 return ret;
374}
375
Jan Kiszka9aa78c42012-01-10 16:31:16 +0100376int pic_get_output(DeviceState *d)
Jan Kiszkad96e1732011-10-07 09:19:37 +0200377{
Andreas Färber29bb5312013-04-27 22:18:40 +0200378 PICCommonState *s = PIC_COMMON(d);
Jan Kiszka9aa78c42012-01-10 16:31:16 +0100379
Jan Kiszkac17725f2011-10-07 09:19:51 +0200380 return (pic_get_irq(s) >= 0);
Jan Kiszkad96e1732011-10-07 09:19:37 +0200381}
382
Avi Kivitya8170e52012-10-23 12:30:10 +0200383static void elcr_ioport_write(void *opaque, hwaddr addr,
Richard Henderson098d3142011-08-10 15:28:16 -0700384 uint64_t val, unsigned size)
bellard660de332004-05-20 12:41:21 +0000385{
Jan Kiszka512709f2011-10-16 14:38:45 +0200386 PICCommonState *s = opaque;
bellard660de332004-05-20 12:41:21 +0000387 s->elcr = val & s->elcr_mask;
388}
389
Avi Kivitya8170e52012-10-23 12:30:10 +0200390static uint64_t elcr_ioport_read(void *opaque, hwaddr addr,
Richard Henderson098d3142011-08-10 15:28:16 -0700391 unsigned size)
bellard660de332004-05-20 12:41:21 +0000392{
Jan Kiszka512709f2011-10-16 14:38:45 +0200393 PICCommonState *s = opaque;
bellard660de332004-05-20 12:41:21 +0000394 return s->elcr;
395}
396
Richard Henderson098d3142011-08-10 15:28:16 -0700397static const MemoryRegionOps pic_base_ioport_ops = {
398 .read = pic_ioport_read,
399 .write = pic_ioport_write,
400 .impl = {
401 .min_access_size = 1,
402 .max_access_size = 1,
403 },
404};
405
406static const MemoryRegionOps pic_elcr_ioport_ops = {
407 .read = elcr_ioport_read,
408 .write = elcr_ioport_write,
409 .impl = {
410 .min_access_size = 1,
411 .max_access_size = 1,
412 },
413};
414
Andreas Färberd2628b72012-11-25 22:54:47 +0100415static void pic_realize(DeviceState *dev, Error **err)
bellardb0a21b52004-03-31 18:58:38 +0000416{
Andreas Färberd2628b72012-11-25 22:54:47 +0100417 PICCommonState *s = PIC_COMMON(dev);
418 PICClass *pc = PIC_GET_CLASS(dev);
Andreas Färber29bb5312013-04-27 22:18:40 +0200419
Paolo Bonzini1437c942013-06-06 21:25:08 -0400420 memory_region_init_io(&s->base_io, OBJECT(s), &pic_base_ioport_ops, s,
421 "pic", 2);
422 memory_region_init_io(&s->elcr_io, OBJECT(s), &pic_elcr_ioport_ops, s,
423 "elcr", 1);
Richard Henderson098d3142011-08-10 15:28:16 -0700424
Andreas Färber29bb5312013-04-27 22:18:40 +0200425 qdev_init_gpio_out(dev, s->int_out, ARRAY_SIZE(s->int_out));
426 qdev_init_gpio_in(dev, pic_set_irq, 8);
Andreas Färberd2628b72012-11-25 22:54:47 +0100427
428 pc->parent_realize(dev, err);
bellardb0a21b52004-03-31 18:58:38 +0000429}
430
Wenchao Xia84f2d0e2013-01-14 14:06:25 +0800431void pic_info(Monitor *mon, const QDict *qdict)
bellardba91cd82004-04-25 18:03:53 +0000432{
433 int i;
Jan Kiszka512709f2011-10-16 14:38:45 +0200434 PICCommonState *s;
ths3b46e622007-09-17 08:09:54 +0000435
Jan Kiszka81a02f92011-10-07 09:19:54 +0200436 if (!isa_pic) {
bellard3de388f2005-07-02 18:11:44 +0000437 return;
Jan Kiszka81a02f92011-10-07 09:19:54 +0200438 }
Jan Kiszkac17725f2011-10-07 09:19:51 +0200439 for (i = 0; i < 2; i++) {
Andreas Färber29bb5312013-04-27 22:18:40 +0200440 s = i == 0 ? PIC_COMMON(isa_pic) : slave_pic;
aliguori376253e2009-03-05 23:01:23 +0000441 monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d "
442 "irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
443 i, s->irr, s->imr, s->isr, s->priority_add,
444 s->irq_base, s->read_reg_select, s->elcr,
445 s->special_fully_nested_mode);
bellardba91cd82004-04-25 18:03:53 +0000446 }
447}
448
Wenchao Xia84f2d0e2013-01-14 14:06:25 +0800449void irq_info(Monitor *mon, const QDict *qdict)
bellard4a0fb71e2004-05-21 11:39:07 +0000450{
451#ifndef DEBUG_IRQ_COUNT
aliguori376253e2009-03-05 23:01:23 +0000452 monitor_printf(mon, "irq statistic code not compiled.\n");
bellard4a0fb71e2004-05-21 11:39:07 +0000453#else
454 int i;
455 int64_t count;
456
aliguori376253e2009-03-05 23:01:23 +0000457 monitor_printf(mon, "IRQ statistics:\n");
bellard4a0fb71e2004-05-21 11:39:07 +0000458 for (i = 0; i < 16; i++) {
459 count = irq_count[i];
Jan Kiszka81a02f92011-10-07 09:19:54 +0200460 if (count > 0) {
aliguori376253e2009-03-05 23:01:23 +0000461 monitor_printf(mon, "%2d: %" PRId64 "\n", i, count);
Jan Kiszka81a02f92011-10-07 09:19:54 +0200462 }
bellard4a0fb71e2004-05-21 11:39:07 +0000463 }
464#endif
465}
bellardba91cd82004-04-25 18:03:53 +0000466
Hervé Poussineau48a18b32011-12-15 22:09:51 +0100467qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq)
bellard80cabfa2004-03-14 12:20:30 +0000468{
Jan Kiszka747c70a2011-10-07 09:19:53 +0200469 qemu_irq *irq_set;
Andreas Färberd1eebf42012-11-25 22:35:49 +0100470 DeviceState *dev;
471 ISADevice *isadev;
Jan Kiszka747c70a2011-10-07 09:19:53 +0200472 int i;
pbrookd537cf62007-04-07 18:14:41 +0000473
Jan Kiszka747c70a2011-10-07 09:19:53 +0200474 irq_set = g_malloc(ISA_NUM_IRQS * sizeof(qemu_irq));
Jan Kiszkac17725f2011-10-07 09:19:51 +0200475
Andreas Färberd1eebf42012-11-25 22:35:49 +0100476 isadev = i8259_init_chip(TYPE_I8259, bus, true);
477 dev = DEVICE(isadev);
Jan Kiszkac17725f2011-10-07 09:19:51 +0200478
Andreas Färberd1eebf42012-11-25 22:35:49 +0100479 qdev_connect_gpio_out(dev, 0, parent_irq);
Jan Kiszka747c70a2011-10-07 09:19:53 +0200480 for (i = 0 ; i < 8; i++) {
Andreas Färberd1eebf42012-11-25 22:35:49 +0100481 irq_set[i] = qdev_get_gpio_in(dev, i);
Jan Kiszka747c70a2011-10-07 09:19:53 +0200482 }
Jan Kiszkac17725f2011-10-07 09:19:51 +0200483
Andreas Färberd1eebf42012-11-25 22:35:49 +0100484 isa_pic = dev;
Jan Kiszka747c70a2011-10-07 09:19:53 +0200485
Andreas Färberd1eebf42012-11-25 22:35:49 +0100486 isadev = i8259_init_chip(TYPE_I8259, bus, false);
487 dev = DEVICE(isadev);
Jan Kiszka747c70a2011-10-07 09:19:53 +0200488
Andreas Färberd1eebf42012-11-25 22:35:49 +0100489 qdev_connect_gpio_out(dev, 0, irq_set[2]);
Jan Kiszka747c70a2011-10-07 09:19:53 +0200490 for (i = 0 ; i < 8; i++) {
Andreas Färberd1eebf42012-11-25 22:35:49 +0100491 irq_set[i + 8] = qdev_get_gpio_in(dev, i);
Jan Kiszka747c70a2011-10-07 09:19:53 +0200492 }
493
Andreas Färber29bb5312013-04-27 22:18:40 +0200494 slave_pic = PIC_COMMON(dev);
Jan Kiszka747c70a2011-10-07 09:19:53 +0200495
496 return irq_set;
bellard80cabfa2004-03-14 12:20:30 +0000497}
Jan Kiszka747c70a2011-10-07 09:19:53 +0200498
Anthony Liguori8f04ee02011-12-04 11:52:49 -0600499static void i8259_class_init(ObjectClass *klass, void *data)
500{
Andreas Färberd2628b72012-11-25 22:54:47 +0100501 PICClass *k = PIC_CLASS(klass);
Anthony Liguori39bffca2011-12-07 21:34:16 -0600502 DeviceClass *dc = DEVICE_CLASS(klass);
Anthony Liguori8f04ee02011-12-04 11:52:49 -0600503
Andreas Färberd2628b72012-11-25 22:54:47 +0100504 k->parent_realize = dc->realize;
505 dc->realize = pic_realize;
Anthony Liguori39bffca2011-12-07 21:34:16 -0600506 dc->reset = pic_reset;
Anthony Liguori8f04ee02011-12-04 11:52:49 -0600507}
508
Andreas Färber8c43a6f2013-01-10 16:19:07 +0100509static const TypeInfo i8259_info = {
Andreas Färberd1eebf42012-11-25 22:35:49 +0100510 .name = TYPE_I8259,
Anthony Liguori39bffca2011-12-07 21:34:16 -0600511 .instance_size = sizeof(PICCommonState),
512 .parent = TYPE_PIC_COMMON,
Anthony Liguori8f04ee02011-12-04 11:52:49 -0600513 .class_init = i8259_class_init,
Andreas Färberd2628b72012-11-25 22:54:47 +0100514 .class_size = sizeof(PICClass),
Jan Kiszka747c70a2011-10-07 09:19:53 +0200515};
516
Andreas Färber83f7d432012-02-09 15:20:55 +0100517static void pic_register_types(void)
Jan Kiszka747c70a2011-10-07 09:19:53 +0200518{
Anthony Liguori39bffca2011-12-07 21:34:16 -0600519 type_register_static(&i8259_info);
Jan Kiszka747c70a2011-10-07 09:19:53 +0200520}
Jan Kiszka512709f2011-10-16 14:38:45 +0200521
Andreas Färber83f7d432012-02-09 15:20:55 +0100522type_init(pic_register_types)