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