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