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 "vl.h" 25 26 /* debug PIC */ 27 //#define DEBUG_PIC 28 29 //#define DEBUG_IRQ_LATENCY 30 31 typedef struct PicState { 32 uint8_t last_irr; /* edge detection */ 33 uint8_t irr; /* interrupt request register */ 34 uint8_t imr; /* interrupt mask register */ 35 uint8_t isr; /* interrupt service register */ 36 uint8_t priority_add; /* highest irq priority */ 37 uint8_t irq_base; 38 uint8_t read_reg_select; 39 uint8_t poll; 40 uint8_t special_mask; 41 uint8_t init_state; 42 uint8_t auto_eoi; 43 uint8_t rotate_on_auto_eoi; 44 uint8_t special_fully_nested_mode; 45 uint8_t init4; /* true if 4 byte init */ 46 } PicState; 47 48 /* 0 is master pic, 1 is slave pic */ 49 PicState pics[2]; 50 int pic_irq_requested; 51 52 /* set irq level. If an edge is detected, then the IRR is set to 1 */ 53 static inline void pic_set_irq1(PicState *s, int irq, int level) 54 { 55 int mask; 56 mask = 1 << irq; 57 if (level) { 58 if ((s->last_irr & mask) == 0) 59 s->irr |= mask; 60 s->last_irr |= mask; 61 } else { 62 s->last_irr &= ~mask; 63 } 64 } 65 66 /* return the highest priority found in mask (highest = smallest 67 number). Return 8 if no irq */ 68 static inline int get_priority(PicState *s, int mask) 69 { 70 int priority; 71 if (mask == 0) 72 return 8; 73 priority = 0; 74 while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0) 75 priority++; 76 return priority; 77 } 78 79 /* return the pic wanted interrupt. return -1 if none */ 80 static int pic_get_irq(PicState *s) 81 { 82 int mask, cur_priority, priority; 83 84 mask = s->irr & ~s->imr; 85 priority = get_priority(s, mask); 86 if (priority == 8) 87 return -1; 88 /* compute current priority. If special fully nested mode on the 89 master, the IRQ coming from the slave is not taken into account 90 for the priority computation. */ 91 mask = s->isr; 92 if (s->special_fully_nested_mode && s == &pics[0]) 93 mask &= ~(1 << 2); 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 /* raise irq to CPU if necessary. must be called every time the active 104 irq may change */ 105 static void pic_update_irq(void) 106 { 107 int irq2, irq; 108 109 /* first look at slave pic */ 110 irq2 = pic_get_irq(&pics[1]); 111 if (irq2 >= 0) { 112 /* if irq request by slave pic, signal master PIC */ 113 pic_set_irq1(&pics[0], 2, 1); 114 pic_set_irq1(&pics[0], 2, 0); 115 } 116 /* look at requested irq */ 117 irq = pic_get_irq(&pics[0]); 118 if (irq >= 0) { 119 if (irq == 2) { 120 /* from slave pic */ 121 pic_irq_requested = 8 + irq2; 122 } else { 123 /* from master pic */ 124 pic_irq_requested = irq; 125 } 126 #if defined(DEBUG_PIC) 127 { 128 int i; 129 for(i = 0; i < 2; i++) { 130 printf("pic%d: imr=%x irr=%x padd=%d\n", 131 i, pics[i].imr, pics[i].irr, pics[i].priority_add); 132 133 } 134 } 135 printf("pic: cpu_interrupt req=%d\n", pic_irq_requested); 136 #endif 137 cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); 138 } 139 } 140 141 #ifdef DEBUG_IRQ_LATENCY 142 int64_t irq_time[16]; 143 #endif 144 #if defined(DEBUG_PIC) 145 int irq_level[16]; 146 #endif 147 148 void pic_set_irq(int irq, int level) 149 { 150 #if defined(DEBUG_PIC) 151 if (level != irq_level[irq]) { 152 printf("pic_set_irq: irq=%d level=%d\n", irq, level); 153 irq_level[irq] = level; 154 } 155 #endif 156 #ifdef DEBUG_IRQ_LATENCY 157 if (level) { 158 irq_time[irq] = cpu_get_ticks(); 159 } 160 #endif 161 pic_set_irq1(&pics[irq >> 3], irq & 7, level); 162 pic_update_irq(); 163 } 164 165 /* acknowledge interrupt 'irq' */ 166 static inline void pic_intack(PicState *s, int irq) 167 { 168 if (s->auto_eoi) { 169 if (s->rotate_on_auto_eoi) 170 s->priority_add = (irq + 1) & 7; 171 } else { 172 s->isr |= (1 << irq); 173 } 174 s->irr &= ~(1 << irq); 175 } 176 177 int cpu_get_pic_interrupt(CPUState *env) 178 { 179 int irq, irq2, intno; 180 181 /* signal the pic that the irq was acked by the CPU */ 182 irq = pic_irq_requested; 183 #ifdef DEBUG_IRQ_LATENCY 184 printf("IRQ%d latency=%0.3fus\n", 185 irq, 186 (double)(cpu_get_ticks() - irq_time[irq]) * 1000000.0 / ticks_per_sec); 187 #endif 188 #if defined(DEBUG_PIC) 189 printf("pic_interrupt: irq=%d\n", irq); 190 #endif 191 192 if (irq >= 8) { 193 irq2 = irq & 7; 194 pic_intack(&pics[1], irq2); 195 irq = 2; 196 intno = pics[1].irq_base + irq2; 197 } else { 198 intno = pics[0].irq_base + irq; 199 } 200 pic_intack(&pics[0], irq); 201 return intno; 202 } 203 204 static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val) 205 { 206 PicState *s = opaque; 207 int priority, cmd, irq; 208 209 #ifdef DEBUG_PIC 210 printf("pic_write: addr=0x%02x val=0x%02x\n", addr, val); 211 #endif 212 addr &= 1; 213 if (addr == 0) { 214 if (val & 0x10) { 215 /* init */ 216 memset(s, 0, sizeof(PicState)); 217 s->init_state = 1; 218 s->init4 = val & 1; 219 if (val & 0x02) 220 hw_error("single mode not supported"); 221 if (val & 0x08) 222 hw_error("level sensitive irq not supported"); 223 } else if (val & 0x08) { 224 if (val & 0x04) 225 s->poll = 1; 226 if (val & 0x02) 227 s->read_reg_select = val & 1; 228 if (val & 0x40) 229 s->special_mask = (val >> 5) & 1; 230 } else { 231 cmd = val >> 5; 232 switch(cmd) { 233 case 0: 234 case 4: 235 s->rotate_on_auto_eoi = cmd >> 2; 236 break; 237 case 1: /* end of interrupt */ 238 case 5: 239 priority = get_priority(s, s->isr); 240 if (priority != 8) { 241 irq = (priority + s->priority_add) & 7; 242 s->isr &= ~(1 << irq); 243 if (cmd == 5) 244 s->priority_add = (irq + 1) & 7; 245 pic_update_irq(); 246 } 247 break; 248 case 3: 249 irq = val & 7; 250 s->isr &= ~(1 << irq); 251 pic_update_irq(); 252 break; 253 case 6: 254 s->priority_add = (val + 1) & 7; 255 pic_update_irq(); 256 break; 257 case 7: 258 irq = val & 7; 259 s->isr &= ~(1 << irq); 260 s->priority_add = (irq + 1) & 7; 261 pic_update_irq(); 262 break; 263 default: 264 /* no operation */ 265 break; 266 } 267 } 268 } else { 269 switch(s->init_state) { 270 case 0: 271 /* normal mode */ 272 s->imr = val; 273 pic_update_irq(); 274 break; 275 case 1: 276 s->irq_base = val & 0xf8; 277 s->init_state = 2; 278 break; 279 case 2: 280 if (s->init4) { 281 s->init_state = 3; 282 } else { 283 s->init_state = 0; 284 } 285 break; 286 case 3: 287 s->special_fully_nested_mode = (val >> 4) & 1; 288 s->auto_eoi = (val >> 1) & 1; 289 s->init_state = 0; 290 break; 291 } 292 } 293 } 294 295 static uint32_t pic_poll_read (PicState *s, uint32_t addr1) 296 { 297 int ret; 298 299 ret = pic_get_irq(s); 300 if (ret >= 0) { 301 if (addr1 >> 7) { 302 pics[0].isr &= ~(1 << 2); 303 pics[0].irr &= ~(1 << 2); 304 } 305 s->irr &= ~(1 << ret); 306 s->isr &= ~(1 << ret); 307 if (addr1 >> 7 || ret != 2) 308 pic_update_irq(); 309 } else { 310 ret = 0x07; 311 pic_update_irq(); 312 } 313 314 return ret; 315 } 316 317 static uint32_t pic_ioport_read(void *opaque, uint32_t addr1) 318 { 319 PicState *s = opaque; 320 unsigned int addr; 321 int ret; 322 323 addr = addr1; 324 addr &= 1; 325 if (s->poll) { 326 ret = pic_poll_read(s, addr1); 327 s->poll = 0; 328 } else { 329 if (addr == 0) { 330 if (s->read_reg_select) 331 ret = s->isr; 332 else 333 ret = s->irr; 334 } else { 335 ret = s->imr; 336 } 337 } 338 #ifdef DEBUG_PIC 339 printf("pic_read: addr=0x%02x val=0x%02x\n", addr1, ret); 340 #endif 341 return ret; 342 } 343 344 /* memory mapped interrupt status */ 345 uint32_t pic_intack_read(CPUState *env) 346 { 347 int ret; 348 349 ret = pic_poll_read(&pics[0], 0x00); 350 if (ret == 2) 351 ret = pic_poll_read(&pics[1], 0x80) + 8; 352 /* Prepare for ISR read */ 353 pics[0].read_reg_select = 1; 354 355 return ret; 356 } 357 358 static void pic_save(QEMUFile *f, void *opaque) 359 { 360 PicState *s = opaque; 361 362 qemu_put_8s(f, &s->last_irr); 363 qemu_put_8s(f, &s->irr); 364 qemu_put_8s(f, &s->imr); 365 qemu_put_8s(f, &s->isr); 366 qemu_put_8s(f, &s->priority_add); 367 qemu_put_8s(f, &s->irq_base); 368 qemu_put_8s(f, &s->read_reg_select); 369 qemu_put_8s(f, &s->poll); 370 qemu_put_8s(f, &s->special_mask); 371 qemu_put_8s(f, &s->init_state); 372 qemu_put_8s(f, &s->auto_eoi); 373 qemu_put_8s(f, &s->rotate_on_auto_eoi); 374 qemu_put_8s(f, &s->special_fully_nested_mode); 375 qemu_put_8s(f, &s->init4); 376 } 377 378 static int pic_load(QEMUFile *f, void *opaque, int version_id) 379 { 380 PicState *s = opaque; 381 382 if (version_id != 1) 383 return -EINVAL; 384 385 qemu_get_8s(f, &s->last_irr); 386 qemu_get_8s(f, &s->irr); 387 qemu_get_8s(f, &s->imr); 388 qemu_get_8s(f, &s->isr); 389 qemu_get_8s(f, &s->priority_add); 390 qemu_get_8s(f, &s->irq_base); 391 qemu_get_8s(f, &s->read_reg_select); 392 qemu_get_8s(f, &s->poll); 393 qemu_get_8s(f, &s->special_mask); 394 qemu_get_8s(f, &s->init_state); 395 qemu_get_8s(f, &s->auto_eoi); 396 qemu_get_8s(f, &s->rotate_on_auto_eoi); 397 qemu_get_8s(f, &s->special_fully_nested_mode); 398 qemu_get_8s(f, &s->init4); 399 return 0; 400 } 401 402 /* XXX: add generic master/slave system */ 403 static void pic_init1(int io_addr, PicState *s) 404 { 405 register_ioport_write(io_addr, 2, 1, pic_ioport_write, s); 406 register_ioport_read(io_addr, 2, 1, pic_ioport_read, s); 407 408 register_savevm("i8259", io_addr, 1, pic_save, pic_load, s); 409 } 410 411 void pic_init(void) 412 { 413 pic_init1(0x20, &pics[0]); 414 pic_init1(0xa0, &pics[1]); 415 } 416 417