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