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