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