bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 1 | /* |
| 2 | * QEMU 8259 interrupt controller emulation |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 3 | * |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 4 | * Copyright (c) 2003-2004 Fabrice Bellard |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 5 | * |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 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 | */ |
Paolo Bonzini | 83c9f4c | 2013-02-04 15:40:22 +0100 | [diff] [blame] | 24 | #include "hw/hw.h" |
Paolo Bonzini | 0d09e41 | 2013-02-05 17:06:20 +0100 | [diff] [blame] | 25 | #include "hw/i386/pc.h" |
| 26 | #include "hw/isa/isa.h" |
Paolo Bonzini | 83c9089 | 2012-12-17 18:19:49 +0100 | [diff] [blame] | 27 | #include "monitor/monitor.h" |
Paolo Bonzini | 1de7afc | 2012-12-17 18:20:00 +0100 | [diff] [blame] | 28 | #include "qemu/timer.h" |
Paolo Bonzini | 0d09e41 | 2013-02-05 17:06:20 +0100 | [diff] [blame] | 29 | #include "hw/isa/i8259_internal.h" |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 30 | |
| 31 | /* debug PIC */ |
| 32 | //#define DEBUG_PIC |
| 33 | |
Blue Swirl | 8ac02ff | 2010-05-29 20:23:19 +0000 | [diff] [blame] | 34 | #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 | |
bellard | b41a2cd | 2004-03-14 21:46:48 +0000 | [diff] [blame] | 41 | //#define DEBUG_IRQ_LATENCY |
bellard | 4a0fb71e | 2004-05-21 11:39:07 +0000 | [diff] [blame] | 42 | //#define DEBUG_IRQ_COUNT |
bellard | b41a2cd | 2004-03-14 21:46:48 +0000 | [diff] [blame] | 43 | |
Andreas Färber | d1eebf4 | 2012-11-25 22:35:49 +0100 | [diff] [blame] | 44 | #define TYPE_I8259 "isa-i8259" |
Andreas Färber | d2628b7 | 2012-11-25 22:54:47 +0100 | [diff] [blame] | 45 | #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 | */ |
| 52 | typedef struct PICClass { |
| 53 | PICCommonClass parent_class; |
| 54 | |
| 55 | DeviceRealize parent_realize; |
| 56 | } PICClass; |
Andreas Färber | d1eebf4 | 2012-11-25 22:35:49 +0100 | [diff] [blame] | 57 | |
Jan Kiszka | 81a02f9 | 2011-10-07 09:19:54 +0200 | [diff] [blame] | 58 | #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) |
bellard | 4a0fb71e | 2004-05-21 11:39:07 +0000 | [diff] [blame] | 59 | static int irq_level[16]; |
| 60 | #endif |
| 61 | #ifdef DEBUG_IRQ_COUNT |
| 62 | static uint64_t irq_count[16]; |
| 63 | #endif |
Jan Kiszka | 747c70a | 2011-10-07 09:19:53 +0200 | [diff] [blame] | 64 | #ifdef DEBUG_IRQ_LATENCY |
| 65 | static int64_t irq_time[16]; |
| 66 | #endif |
Jan Kiszka | 9aa78c4 | 2012-01-10 16:31:16 +0100 | [diff] [blame] | 67 | DeviceState *isa_pic; |
Jan Kiszka | 512709f | 2011-10-16 14:38:45 +0200 | [diff] [blame] | 68 | static PICCommonState *slave_pic; |
bellard | 4a0fb71e | 2004-05-21 11:39:07 +0000 | [diff] [blame] | 69 | |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 70 | /* return the highest priority found in mask (highest = smallest |
| 71 | number). Return 8 if no irq */ |
Jan Kiszka | 512709f | 2011-10-16 14:38:45 +0200 | [diff] [blame] | 72 | static int get_priority(PICCommonState *s, int mask) |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 73 | { |
| 74 | int priority; |
Jan Kiszka | 81a02f9 | 2011-10-07 09:19:54 +0200 | [diff] [blame] | 75 | |
| 76 | if (mask == 0) { |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 77 | return 8; |
Jan Kiszka | 81a02f9 | 2011-10-07 09:19:54 +0200 | [diff] [blame] | 78 | } |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 79 | priority = 0; |
Jan Kiszka | 81a02f9 | 2011-10-07 09:19:54 +0200 | [diff] [blame] | 80 | while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0) { |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 81 | priority++; |
Jan Kiszka | 81a02f9 | 2011-10-07 09:19:54 +0200 | [diff] [blame] | 82 | } |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 83 | return priority; |
| 84 | } |
| 85 | |
| 86 | /* return the pic wanted interrupt. return -1 if none */ |
Jan Kiszka | 512709f | 2011-10-16 14:38:45 +0200 | [diff] [blame] | 87 | static int pic_get_irq(PICCommonState *s) |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 88 | { |
| 89 | int mask, cur_priority, priority; |
| 90 | |
| 91 | mask = s->irr & ~s->imr; |
| 92 | priority = get_priority(s, mask); |
Jan Kiszka | 81a02f9 | 2011-10-07 09:19:54 +0200 | [diff] [blame] | 93 | if (priority == 8) { |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 94 | return -1; |
Jan Kiszka | 81a02f9 | 2011-10-07 09:19:54 +0200 | [diff] [blame] | 95 | } |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 96 | /* 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 Kiszka | 81a02f9 | 2011-10-07 09:19:54 +0200 | [diff] [blame] | 100 | if (s->special_mask) { |
balrog | 8467871 | 2008-07-19 09:18:48 +0000 | [diff] [blame] | 101 | mask &= ~s->imr; |
Jan Kiszka | 81a02f9 | 2011-10-07 09:19:54 +0200 | [diff] [blame] | 102 | } |
Jan Kiszka | 2598539 | 2011-10-07 09:19:50 +0200 | [diff] [blame] | 103 | if (s->special_fully_nested_mode && s->master) { |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 104 | mask &= ~(1 << 2); |
Jan Kiszka | 2598539 | 2011-10-07 09:19:50 +0200 | [diff] [blame] | 105 | } |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 106 | 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 Kiszka | b76750c | 2011-10-07 09:19:46 +0200 | [diff] [blame] | 115 | /* Update INT output. Must be called every time the output may have changed. */ |
Jan Kiszka | 512709f | 2011-10-16 14:38:45 +0200 | [diff] [blame] | 116 | static void pic_update_irq(PICCommonState *s) |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 117 | { |
Jan Kiszka | b76750c | 2011-10-07 09:19:46 +0200 | [diff] [blame] | 118 | int irq; |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 119 | |
Jan Kiszka | b76750c | 2011-10-07 09:19:46 +0200 | [diff] [blame] | 120 | irq = pic_get_irq(s); |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 121 | if (irq >= 0) { |
Jan Kiszka | b76750c | 2011-10-07 09:19:46 +0200 | [diff] [blame] | 122 | DPRINTF("pic%d: imr=%x irr=%x padd=%d\n", |
Jan Kiszka | 2598539 | 2011-10-07 09:19:50 +0200 | [diff] [blame] | 123 | s->master ? 0 : 1, s->imr, s->irr, s->priority_add); |
Jan Kiszka | 747c70a | 2011-10-07 09:19:53 +0200 | [diff] [blame] | 124 | qemu_irq_raise(s->int_out[0]); |
Jan Kiszka | d96e173 | 2011-10-07 09:19:37 +0200 | [diff] [blame] | 125 | } else { |
Jan Kiszka | 747c70a | 2011-10-07 09:19:53 +0200 | [diff] [blame] | 126 | qemu_irq_lower(s->int_out[0]); |
ths | 4de9b24 | 2007-01-24 01:47:51 +0000 | [diff] [blame] | 127 | } |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 128 | } |
| 129 | |
Jan Kiszka | 6202601 | 2011-10-07 09:19:40 +0200 | [diff] [blame] | 130 | /* set irq level. If an edge is detected, then the IRR is set to 1 */ |
Jan Kiszka | 747c70a | 2011-10-07 09:19:53 +0200 | [diff] [blame] | 131 | static void pic_set_irq(void *opaque, int irq, int level) |
Jan Kiszka | 6202601 | 2011-10-07 09:19:40 +0200 | [diff] [blame] | 132 | { |
Jan Kiszka | 512709f | 2011-10-16 14:38:45 +0200 | [diff] [blame] | 133 | PICCommonState *s = opaque; |
Jan Kiszka | 747c70a | 2011-10-07 09:19:53 +0200 | [diff] [blame] | 134 | 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 Kiszka | 6202601 | 2011-10-07 09:19:40 +0200 | [diff] [blame] | 157 | 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 Kiszka | b76750c | 2011-10-07 09:19:46 +0200 | [diff] [blame] | 177 | pic_update_irq(s); |
Jan Kiszka | 6202601 | 2011-10-07 09:19:40 +0200 | [diff] [blame] | 178 | } |
| 179 | |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 180 | /* acknowledge interrupt 'irq' */ |
Jan Kiszka | 512709f | 2011-10-16 14:38:45 +0200 | [diff] [blame] | 181 | static void pic_intack(PICCommonState *s, int irq) |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 182 | { |
| 183 | if (s->auto_eoi) { |
Jan Kiszka | 81a02f9 | 2011-10-07 09:19:54 +0200 | [diff] [blame] | 184 | if (s->rotate_on_auto_eoi) { |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 185 | s->priority_add = (irq + 1) & 7; |
Jan Kiszka | 81a02f9 | 2011-10-07 09:19:54 +0200 | [diff] [blame] | 186 | } |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 187 | } else { |
| 188 | s->isr |= (1 << irq); |
| 189 | } |
bellard | 0ecf89a | 2004-09-29 21:55:52 +0000 | [diff] [blame] | 190 | /* We don't clear a level sensitive interrupt here */ |
Jan Kiszka | 81a02f9 | 2011-10-07 09:19:54 +0200 | [diff] [blame] | 191 | if (!(s->elcr & (1 << irq))) { |
bellard | 0ecf89a | 2004-09-29 21:55:52 +0000 | [diff] [blame] | 192 | s->irr &= ~(1 << irq); |
Jan Kiszka | 81a02f9 | 2011-10-07 09:19:54 +0200 | [diff] [blame] | 193 | } |
Jan Kiszka | b76750c | 2011-10-07 09:19:46 +0200 | [diff] [blame] | 194 | pic_update_irq(s); |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 195 | } |
| 196 | |
Jan Kiszka | 9aa78c4 | 2012-01-10 16:31:16 +0100 | [diff] [blame] | 197 | int pic_read_irq(DeviceState *d) |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 198 | { |
Andreas Färber | 29bb531 | 2013-04-27 22:18:40 +0200 | [diff] [blame] | 199 | PICCommonState *s = PIC_COMMON(d); |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 200 | int irq, irq2, intno; |
| 201 | |
Jan Kiszka | c17725f | 2011-10-07 09:19:51 +0200 | [diff] [blame] | 202 | irq = pic_get_irq(s); |
bellard | 15aeac3 | 2004-05-20 16:12:05 +0000 | [diff] [blame] | 203 | if (irq >= 0) { |
bellard | 15aeac3 | 2004-05-20 16:12:05 +0000 | [diff] [blame] | 204 | if (irq == 2) { |
Jan Kiszka | c17725f | 2011-10-07 09:19:51 +0200 | [diff] [blame] | 205 | irq2 = pic_get_irq(slave_pic); |
bellard | 15aeac3 | 2004-05-20 16:12:05 +0000 | [diff] [blame] | 206 | if (irq2 >= 0) { |
Jan Kiszka | c17725f | 2011-10-07 09:19:51 +0200 | [diff] [blame] | 207 | pic_intack(slave_pic, irq2); |
bellard | 15aeac3 | 2004-05-20 16:12:05 +0000 | [diff] [blame] | 208 | } else { |
| 209 | /* spurious IRQ on slave controller */ |
| 210 | irq2 = 7; |
| 211 | } |
Jan Kiszka | c17725f | 2011-10-07 09:19:51 +0200 | [diff] [blame] | 212 | intno = slave_pic->irq_base + irq2; |
bellard | 15aeac3 | 2004-05-20 16:12:05 +0000 | [diff] [blame] | 213 | } else { |
Jan Kiszka | c17725f | 2011-10-07 09:19:51 +0200 | [diff] [blame] | 214 | intno = s->irq_base + irq; |
bellard | 15aeac3 | 2004-05-20 16:12:05 +0000 | [diff] [blame] | 215 | } |
Jan Kiszka | c17725f | 2011-10-07 09:19:51 +0200 | [diff] [blame] | 216 | pic_intack(s, irq); |
bellard | 15aeac3 | 2004-05-20 16:12:05 +0000 | [diff] [blame] | 217 | } else { |
| 218 | /* spurious IRQ on host controller */ |
| 219 | irq = 7; |
Jan Kiszka | c17725f | 2011-10-07 09:19:51 +0200 | [diff] [blame] | 220 | intno = s->irq_base + irq; |
bellard | 15aeac3 | 2004-05-20 16:12:05 +0000 | [diff] [blame] | 221 | } |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 222 | |
Jan Kiszka | 78ef2b6 | 2011-10-07 09:19:43 +0200 | [diff] [blame] | 223 | #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_LATENCY) |
| 224 | if (irq == 2) { |
| 225 | irq = irq2 + 8; |
| 226 | } |
| 227 | #endif |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 228 | #ifdef DEBUG_IRQ_LATENCY |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 229 | printf("IRQ%d latency=%0.3fus\n", |
| 230 | irq, |
Paolo Bonzini | 7447545 | 2011-03-11 16:47:48 +0100 | [diff] [blame] | 231 | (double)(qemu_get_clock_ns(vm_clock) - |
Juan Quintela | 6ee093c | 2009-09-10 03:04:26 +0200 | [diff] [blame] | 232 | irq_time[irq]) * 1000000.0 / get_ticks_per_sec()); |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 233 | #endif |
Blue Swirl | 8ac02ff | 2010-05-29 20:23:19 +0000 | [diff] [blame] | 234 | DPRINTF("pic_interrupt: irq=%d\n", irq); |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 235 | return intno; |
| 236 | } |
| 237 | |
Jan Kiszka | 512709f | 2011-10-16 14:38:45 +0200 | [diff] [blame] | 238 | static void pic_init_reset(PICCommonState *s) |
bellard | d7d02e3 | 2004-06-20 12:58:36 +0000 | [diff] [blame] | 239 | { |
Jan Kiszka | 512709f | 2011-10-16 14:38:45 +0200 | [diff] [blame] | 240 | pic_reset_common(s); |
Jan Kiszka | b76750c | 2011-10-07 09:19:46 +0200 | [diff] [blame] | 241 | pic_update_irq(s); |
bellard | d7d02e3 | 2004-06-20 12:58:36 +0000 | [diff] [blame] | 242 | } |
| 243 | |
Jan Kiszka | 747c70a | 2011-10-07 09:19:53 +0200 | [diff] [blame] | 244 | static void pic_reset(DeviceState *dev) |
Jan Kiszka | 86fbf97 | 2011-10-07 09:19:45 +0200 | [diff] [blame] | 245 | { |
Andreas Färber | 29bb531 | 2013-04-27 22:18:40 +0200 | [diff] [blame] | 246 | PICCommonState *s = PIC_COMMON(dev); |
Jan Kiszka | 86fbf97 | 2011-10-07 09:19:45 +0200 | [diff] [blame] | 247 | |
Jan Kiszka | 86fbf97 | 2011-10-07 09:19:45 +0200 | [diff] [blame] | 248 | s->elcr = 0; |
Jan Kiszka | aa24822 | 2012-01-24 16:29:29 +0100 | [diff] [blame] | 249 | pic_init_reset(s); |
Jan Kiszka | 86fbf97 | 2011-10-07 09:19:45 +0200 | [diff] [blame] | 250 | } |
| 251 | |
Avi Kivity | a8170e5 | 2012-10-23 12:30:10 +0200 | [diff] [blame] | 252 | static void pic_ioport_write(void *opaque, hwaddr addr64, |
Richard Henderson | 098d314 | 2011-08-10 15:28:16 -0700 | [diff] [blame] | 253 | uint64_t val64, unsigned size) |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 254 | { |
Jan Kiszka | 512709f | 2011-10-16 14:38:45 +0200 | [diff] [blame] | 255 | PICCommonState *s = opaque; |
Richard Henderson | 098d314 | 2011-08-10 15:28:16 -0700 | [diff] [blame] | 256 | uint32_t addr = addr64; |
| 257 | uint32_t val = val64; |
bellard | d7d02e3 | 2004-06-20 12:58:36 +0000 | [diff] [blame] | 258 | int priority, cmd, irq; |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 259 | |
Blue Swirl | 8ac02ff | 2010-05-29 20:23:19 +0000 | [diff] [blame] | 260 | DPRINTF("write: addr=0x%02x val=0x%02x\n", addr, val); |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 261 | if (addr == 0) { |
| 262 | if (val & 0x10) { |
Jan Kiszka | 86fbf97 | 2011-10-07 09:19:45 +0200 | [diff] [blame] | 263 | pic_init_reset(s); |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 264 | s->init_state = 1; |
| 265 | s->init4 = val & 1; |
ths | 2053152 | 2007-04-01 18:26:11 +0000 | [diff] [blame] | 266 | s->single_mode = val & 2; |
Jan Kiszka | 81a02f9 | 2011-10-07 09:19:54 +0200 | [diff] [blame] | 267 | if (val & 0x08) { |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 268 | hw_error("level sensitive irq not supported"); |
Jan Kiszka | 81a02f9 | 2011-10-07 09:19:54 +0200 | [diff] [blame] | 269 | } |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 270 | } else if (val & 0x08) { |
Jan Kiszka | 81a02f9 | 2011-10-07 09:19:54 +0200 | [diff] [blame] | 271 | if (val & 0x04) { |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 272 | s->poll = 1; |
Jan Kiszka | 81a02f9 | 2011-10-07 09:19:54 +0200 | [diff] [blame] | 273 | } |
| 274 | if (val & 0x02) { |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 275 | s->read_reg_select = val & 1; |
Jan Kiszka | 81a02f9 | 2011-10-07 09:19:54 +0200 | [diff] [blame] | 276 | } |
| 277 | if (val & 0x40) { |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 278 | s->special_mask = (val >> 5) & 1; |
Jan Kiszka | 81a02f9 | 2011-10-07 09:19:54 +0200 | [diff] [blame] | 279 | } |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 280 | } else { |
| 281 | cmd = val >> 5; |
Jan Kiszka | 81a02f9 | 2011-10-07 09:19:54 +0200 | [diff] [blame] | 282 | switch (cmd) { |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 283 | 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 Kiszka | 81a02f9 | 2011-10-07 09:19:54 +0200 | [diff] [blame] | 293 | if (cmd == 5) { |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 294 | s->priority_add = (irq + 1) & 7; |
Jan Kiszka | 81a02f9 | 2011-10-07 09:19:54 +0200 | [diff] [blame] | 295 | } |
Jan Kiszka | b76750c | 2011-10-07 09:19:46 +0200 | [diff] [blame] | 296 | pic_update_irq(s); |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 297 | } |
| 298 | break; |
| 299 | case 3: |
| 300 | irq = val & 7; |
| 301 | s->isr &= ~(1 << irq); |
Jan Kiszka | b76750c | 2011-10-07 09:19:46 +0200 | [diff] [blame] | 302 | pic_update_irq(s); |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 303 | break; |
| 304 | case 6: |
| 305 | s->priority_add = (val + 1) & 7; |
Jan Kiszka | b76750c | 2011-10-07 09:19:46 +0200 | [diff] [blame] | 306 | pic_update_irq(s); |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 307 | break; |
| 308 | case 7: |
| 309 | irq = val & 7; |
| 310 | s->isr &= ~(1 << irq); |
| 311 | s->priority_add = (irq + 1) & 7; |
Jan Kiszka | b76750c | 2011-10-07 09:19:46 +0200 | [diff] [blame] | 312 | pic_update_irq(s); |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 313 | break; |
| 314 | default: |
| 315 | /* no operation */ |
| 316 | break; |
| 317 | } |
| 318 | } |
| 319 | } else { |
Jan Kiszka | 81a02f9 | 2011-10-07 09:19:54 +0200 | [diff] [blame] | 320 | switch (s->init_state) { |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 321 | case 0: |
| 322 | /* normal mode */ |
| 323 | s->imr = val; |
Jan Kiszka | b76750c | 2011-10-07 09:19:46 +0200 | [diff] [blame] | 324 | pic_update_irq(s); |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 325 | break; |
| 326 | case 1: |
| 327 | s->irq_base = val & 0xf8; |
ths | 2bb081f | 2007-07-31 23:12:09 +0000 | [diff] [blame] | 328 | s->init_state = s->single_mode ? (s->init4 ? 3 : 0) : 2; |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 329 | 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 Kivity | a8170e5 | 2012-10-23 12:30:10 +0200 | [diff] [blame] | 346 | static uint64_t pic_ioport_read(void *opaque, hwaddr addr, |
Richard Henderson | 098d314 | 2011-08-10 15:28:16 -0700 | [diff] [blame] | 347 | unsigned size) |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 348 | { |
Jan Kiszka | 512709f | 2011-10-16 14:38:45 +0200 | [diff] [blame] | 349 | PICCommonState *s = opaque; |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 350 | int ret; |
| 351 | |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 352 | if (s->poll) { |
Jan Kiszka | 8d484ca | 2011-10-07 09:19:47 +0200 | [diff] [blame] | 353 | ret = pic_get_irq(s); |
| 354 | if (ret >= 0) { |
| 355 | pic_intack(s, ret); |
| 356 | ret |= 0x80; |
| 357 | } else { |
| 358 | ret = 0; |
| 359 | } |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 360 | s->poll = 0; |
| 361 | } else { |
| 362 | if (addr == 0) { |
Jan Kiszka | 81a02f9 | 2011-10-07 09:19:54 +0200 | [diff] [blame] | 363 | if (s->read_reg_select) { |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 364 | ret = s->isr; |
Jan Kiszka | 81a02f9 | 2011-10-07 09:19:54 +0200 | [diff] [blame] | 365 | } else { |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 366 | ret = s->irr; |
Jan Kiszka | 81a02f9 | 2011-10-07 09:19:54 +0200 | [diff] [blame] | 367 | } |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 368 | } else { |
| 369 | ret = s->imr; |
| 370 | } |
| 371 | } |
malc | 08406b0 | 2012-08-27 18:33:24 +0400 | [diff] [blame] | 372 | DPRINTF("read: addr=0x%02x val=0x%02x\n", addr, ret); |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 373 | return ret; |
| 374 | } |
| 375 | |
Jan Kiszka | 9aa78c4 | 2012-01-10 16:31:16 +0100 | [diff] [blame] | 376 | int pic_get_output(DeviceState *d) |
Jan Kiszka | d96e173 | 2011-10-07 09:19:37 +0200 | [diff] [blame] | 377 | { |
Andreas Färber | 29bb531 | 2013-04-27 22:18:40 +0200 | [diff] [blame] | 378 | PICCommonState *s = PIC_COMMON(d); |
Jan Kiszka | 9aa78c4 | 2012-01-10 16:31:16 +0100 | [diff] [blame] | 379 | |
Jan Kiszka | c17725f | 2011-10-07 09:19:51 +0200 | [diff] [blame] | 380 | return (pic_get_irq(s) >= 0); |
Jan Kiszka | d96e173 | 2011-10-07 09:19:37 +0200 | [diff] [blame] | 381 | } |
| 382 | |
Avi Kivity | a8170e5 | 2012-10-23 12:30:10 +0200 | [diff] [blame] | 383 | static void elcr_ioport_write(void *opaque, hwaddr addr, |
Richard Henderson | 098d314 | 2011-08-10 15:28:16 -0700 | [diff] [blame] | 384 | uint64_t val, unsigned size) |
bellard | 660de33 | 2004-05-20 12:41:21 +0000 | [diff] [blame] | 385 | { |
Jan Kiszka | 512709f | 2011-10-16 14:38:45 +0200 | [diff] [blame] | 386 | PICCommonState *s = opaque; |
bellard | 660de33 | 2004-05-20 12:41:21 +0000 | [diff] [blame] | 387 | s->elcr = val & s->elcr_mask; |
| 388 | } |
| 389 | |
Avi Kivity | a8170e5 | 2012-10-23 12:30:10 +0200 | [diff] [blame] | 390 | static uint64_t elcr_ioport_read(void *opaque, hwaddr addr, |
Richard Henderson | 098d314 | 2011-08-10 15:28:16 -0700 | [diff] [blame] | 391 | unsigned size) |
bellard | 660de33 | 2004-05-20 12:41:21 +0000 | [diff] [blame] | 392 | { |
Jan Kiszka | 512709f | 2011-10-16 14:38:45 +0200 | [diff] [blame] | 393 | PICCommonState *s = opaque; |
bellard | 660de33 | 2004-05-20 12:41:21 +0000 | [diff] [blame] | 394 | return s->elcr; |
| 395 | } |
| 396 | |
Richard Henderson | 098d314 | 2011-08-10 15:28:16 -0700 | [diff] [blame] | 397 | static 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 | |
| 406 | static 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ärber | d2628b7 | 2012-11-25 22:54:47 +0100 | [diff] [blame] | 415 | static void pic_realize(DeviceState *dev, Error **err) |
bellard | b0a21b5 | 2004-03-31 18:58:38 +0000 | [diff] [blame] | 416 | { |
Andreas Färber | d2628b7 | 2012-11-25 22:54:47 +0100 | [diff] [blame] | 417 | PICCommonState *s = PIC_COMMON(dev); |
| 418 | PICClass *pc = PIC_GET_CLASS(dev); |
Andreas Färber | 29bb531 | 2013-04-27 22:18:40 +0200 | [diff] [blame] | 419 | |
Paolo Bonzini | 1437c94 | 2013-06-06 21:25:08 -0400 | [diff] [blame] | 420 | 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 Henderson | 098d314 | 2011-08-10 15:28:16 -0700 | [diff] [blame] | 424 | |
Andreas Färber | 29bb531 | 2013-04-27 22:18:40 +0200 | [diff] [blame] | 425 | 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ärber | d2628b7 | 2012-11-25 22:54:47 +0100 | [diff] [blame] | 427 | |
| 428 | pc->parent_realize(dev, err); |
bellard | b0a21b5 | 2004-03-31 18:58:38 +0000 | [diff] [blame] | 429 | } |
| 430 | |
Wenchao Xia | 84f2d0e | 2013-01-14 14:06:25 +0800 | [diff] [blame] | 431 | void pic_info(Monitor *mon, const QDict *qdict) |
bellard | ba91cd8 | 2004-04-25 18:03:53 +0000 | [diff] [blame] | 432 | { |
| 433 | int i; |
Jan Kiszka | 512709f | 2011-10-16 14:38:45 +0200 | [diff] [blame] | 434 | PICCommonState *s; |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 435 | |
Jan Kiszka | 81a02f9 | 2011-10-07 09:19:54 +0200 | [diff] [blame] | 436 | if (!isa_pic) { |
bellard | 3de388f | 2005-07-02 18:11:44 +0000 | [diff] [blame] | 437 | return; |
Jan Kiszka | 81a02f9 | 2011-10-07 09:19:54 +0200 | [diff] [blame] | 438 | } |
Jan Kiszka | c17725f | 2011-10-07 09:19:51 +0200 | [diff] [blame] | 439 | for (i = 0; i < 2; i++) { |
Andreas Färber | 29bb531 | 2013-04-27 22:18:40 +0200 | [diff] [blame] | 440 | s = i == 0 ? PIC_COMMON(isa_pic) : slave_pic; |
aliguori | 376253e | 2009-03-05 23:01:23 +0000 | [diff] [blame] | 441 | 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); |
bellard | ba91cd8 | 2004-04-25 18:03:53 +0000 | [diff] [blame] | 446 | } |
| 447 | } |
| 448 | |
Wenchao Xia | 84f2d0e | 2013-01-14 14:06:25 +0800 | [diff] [blame] | 449 | void irq_info(Monitor *mon, const QDict *qdict) |
bellard | 4a0fb71e | 2004-05-21 11:39:07 +0000 | [diff] [blame] | 450 | { |
| 451 | #ifndef DEBUG_IRQ_COUNT |
aliguori | 376253e | 2009-03-05 23:01:23 +0000 | [diff] [blame] | 452 | monitor_printf(mon, "irq statistic code not compiled.\n"); |
bellard | 4a0fb71e | 2004-05-21 11:39:07 +0000 | [diff] [blame] | 453 | #else |
| 454 | int i; |
| 455 | int64_t count; |
| 456 | |
aliguori | 376253e | 2009-03-05 23:01:23 +0000 | [diff] [blame] | 457 | monitor_printf(mon, "IRQ statistics:\n"); |
bellard | 4a0fb71e | 2004-05-21 11:39:07 +0000 | [diff] [blame] | 458 | for (i = 0; i < 16; i++) { |
| 459 | count = irq_count[i]; |
Jan Kiszka | 81a02f9 | 2011-10-07 09:19:54 +0200 | [diff] [blame] | 460 | if (count > 0) { |
aliguori | 376253e | 2009-03-05 23:01:23 +0000 | [diff] [blame] | 461 | monitor_printf(mon, "%2d: %" PRId64 "\n", i, count); |
Jan Kiszka | 81a02f9 | 2011-10-07 09:19:54 +0200 | [diff] [blame] | 462 | } |
bellard | 4a0fb71e | 2004-05-21 11:39:07 +0000 | [diff] [blame] | 463 | } |
| 464 | #endif |
| 465 | } |
bellard | ba91cd8 | 2004-04-25 18:03:53 +0000 | [diff] [blame] | 466 | |
Hervé Poussineau | 48a18b3 | 2011-12-15 22:09:51 +0100 | [diff] [blame] | 467 | qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq) |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 468 | { |
Jan Kiszka | 747c70a | 2011-10-07 09:19:53 +0200 | [diff] [blame] | 469 | qemu_irq *irq_set; |
Andreas Färber | d1eebf4 | 2012-11-25 22:35:49 +0100 | [diff] [blame] | 470 | DeviceState *dev; |
| 471 | ISADevice *isadev; |
Jan Kiszka | 747c70a | 2011-10-07 09:19:53 +0200 | [diff] [blame] | 472 | int i; |
pbrook | d537cf6 | 2007-04-07 18:14:41 +0000 | [diff] [blame] | 473 | |
Jan Kiszka | 747c70a | 2011-10-07 09:19:53 +0200 | [diff] [blame] | 474 | irq_set = g_malloc(ISA_NUM_IRQS * sizeof(qemu_irq)); |
Jan Kiszka | c17725f | 2011-10-07 09:19:51 +0200 | [diff] [blame] | 475 | |
Andreas Färber | d1eebf4 | 2012-11-25 22:35:49 +0100 | [diff] [blame] | 476 | isadev = i8259_init_chip(TYPE_I8259, bus, true); |
| 477 | dev = DEVICE(isadev); |
Jan Kiszka | c17725f | 2011-10-07 09:19:51 +0200 | [diff] [blame] | 478 | |
Andreas Färber | d1eebf4 | 2012-11-25 22:35:49 +0100 | [diff] [blame] | 479 | qdev_connect_gpio_out(dev, 0, parent_irq); |
Jan Kiszka | 747c70a | 2011-10-07 09:19:53 +0200 | [diff] [blame] | 480 | for (i = 0 ; i < 8; i++) { |
Andreas Färber | d1eebf4 | 2012-11-25 22:35:49 +0100 | [diff] [blame] | 481 | irq_set[i] = qdev_get_gpio_in(dev, i); |
Jan Kiszka | 747c70a | 2011-10-07 09:19:53 +0200 | [diff] [blame] | 482 | } |
Jan Kiszka | c17725f | 2011-10-07 09:19:51 +0200 | [diff] [blame] | 483 | |
Andreas Färber | d1eebf4 | 2012-11-25 22:35:49 +0100 | [diff] [blame] | 484 | isa_pic = dev; |
Jan Kiszka | 747c70a | 2011-10-07 09:19:53 +0200 | [diff] [blame] | 485 | |
Andreas Färber | d1eebf4 | 2012-11-25 22:35:49 +0100 | [diff] [blame] | 486 | isadev = i8259_init_chip(TYPE_I8259, bus, false); |
| 487 | dev = DEVICE(isadev); |
Jan Kiszka | 747c70a | 2011-10-07 09:19:53 +0200 | [diff] [blame] | 488 | |
Andreas Färber | d1eebf4 | 2012-11-25 22:35:49 +0100 | [diff] [blame] | 489 | qdev_connect_gpio_out(dev, 0, irq_set[2]); |
Jan Kiszka | 747c70a | 2011-10-07 09:19:53 +0200 | [diff] [blame] | 490 | for (i = 0 ; i < 8; i++) { |
Andreas Färber | d1eebf4 | 2012-11-25 22:35:49 +0100 | [diff] [blame] | 491 | irq_set[i + 8] = qdev_get_gpio_in(dev, i); |
Jan Kiszka | 747c70a | 2011-10-07 09:19:53 +0200 | [diff] [blame] | 492 | } |
| 493 | |
Andreas Färber | 29bb531 | 2013-04-27 22:18:40 +0200 | [diff] [blame] | 494 | slave_pic = PIC_COMMON(dev); |
Jan Kiszka | 747c70a | 2011-10-07 09:19:53 +0200 | [diff] [blame] | 495 | |
| 496 | return irq_set; |
bellard | 80cabfa | 2004-03-14 12:20:30 +0000 | [diff] [blame] | 497 | } |
Jan Kiszka | 747c70a | 2011-10-07 09:19:53 +0200 | [diff] [blame] | 498 | |
Anthony Liguori | 8f04ee0 | 2011-12-04 11:52:49 -0600 | [diff] [blame] | 499 | static void i8259_class_init(ObjectClass *klass, void *data) |
| 500 | { |
Andreas Färber | d2628b7 | 2012-11-25 22:54:47 +0100 | [diff] [blame] | 501 | PICClass *k = PIC_CLASS(klass); |
Anthony Liguori | 39bffca | 2011-12-07 21:34:16 -0600 | [diff] [blame] | 502 | DeviceClass *dc = DEVICE_CLASS(klass); |
Anthony Liguori | 8f04ee0 | 2011-12-04 11:52:49 -0600 | [diff] [blame] | 503 | |
Andreas Färber | d2628b7 | 2012-11-25 22:54:47 +0100 | [diff] [blame] | 504 | k->parent_realize = dc->realize; |
| 505 | dc->realize = pic_realize; |
Anthony Liguori | 39bffca | 2011-12-07 21:34:16 -0600 | [diff] [blame] | 506 | dc->reset = pic_reset; |
Anthony Liguori | 8f04ee0 | 2011-12-04 11:52:49 -0600 | [diff] [blame] | 507 | } |
| 508 | |
Andreas Färber | 8c43a6f | 2013-01-10 16:19:07 +0100 | [diff] [blame] | 509 | static const TypeInfo i8259_info = { |
Andreas Färber | d1eebf4 | 2012-11-25 22:35:49 +0100 | [diff] [blame] | 510 | .name = TYPE_I8259, |
Anthony Liguori | 39bffca | 2011-12-07 21:34:16 -0600 | [diff] [blame] | 511 | .instance_size = sizeof(PICCommonState), |
| 512 | .parent = TYPE_PIC_COMMON, |
Anthony Liguori | 8f04ee0 | 2011-12-04 11:52:49 -0600 | [diff] [blame] | 513 | .class_init = i8259_class_init, |
Andreas Färber | d2628b7 | 2012-11-25 22:54:47 +0100 | [diff] [blame] | 514 | .class_size = sizeof(PICClass), |
Jan Kiszka | 747c70a | 2011-10-07 09:19:53 +0200 | [diff] [blame] | 515 | }; |
| 516 | |
Andreas Färber | 83f7d43 | 2012-02-09 15:20:55 +0100 | [diff] [blame] | 517 | static void pic_register_types(void) |
Jan Kiszka | 747c70a | 2011-10-07 09:19:53 +0200 | [diff] [blame] | 518 | { |
Anthony Liguori | 39bffca | 2011-12-07 21:34:16 -0600 | [diff] [blame] | 519 | type_register_static(&i8259_info); |
Jan Kiszka | 747c70a | 2011-10-07 09:19:53 +0200 | [diff] [blame] | 520 | } |
Jan Kiszka | 512709f | 2011-10-16 14:38:45 +0200 | [diff] [blame] | 521 | |
Andreas Färber | 83f7d43 | 2012-02-09 15:20:55 +0100 | [diff] [blame] | 522 | type_init(pic_register_types) |