ia64/xen-unstable

view tools/ioemu/hw/i8259.c @ 6946:e703abaf6e3d

Add behaviour to the remove methods to remove the transaction's path itself. This allows us to write Remove(path) to remove the specified path rather than having to slice the path ourselves.
author emellor@ewan
date Sun Sep 18 14:42:13 2005 +0100 (2005-09-18)
parents 3233e7ecfa9f
children 06d84bf87159
line source
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 #include "xenctrl.h"
26 #include <io/ioreq.h>
28 /* debug PIC */
29 //#define DEBUG_PIC
31 //#define DEBUG_IRQ_LATENCY
32 #define DEBUG_IRQ_COUNT
34 extern void pit_reset_vmx_vectors();
36 typedef struct PicState {
37 uint8_t last_irr; /* edge detection */
38 uint8_t irr; /* interrupt request register */
39 uint8_t imr; /* interrupt mask register */
40 uint8_t isr; /* interrupt service register */
41 uint8_t priority_add; /* highest irq priority */
42 uint8_t irq_base;
43 uint8_t read_reg_select;
44 uint8_t poll;
45 uint8_t special_mask;
46 uint8_t init_state;
47 uint8_t auto_eoi;
48 uint8_t rotate_on_auto_eoi;
49 uint8_t special_fully_nested_mode;
50 uint8_t init4; /* true if 4 byte init */
51 uint8_t elcr; /* PIIX edge/trigger selection*/
52 uint8_t elcr_mask;
53 } PicState;
55 /* 0 is master pic, 1 is slave pic */
56 static PicState pics[2];
58 #if defined(DEBUG_PIC) || defined (DEBUG_IRQ_COUNT)
59 static int irq_level[16];
60 #endif
61 #ifdef DEBUG_IRQ_COUNT
62 static uint64_t irq_count[16];
63 #endif
65 /* set irq level. If an edge is detected, then the IRR is set to 1 */
66 static inline void pic_set_irq1(PicState *s, int irq, int level)
67 {
68 int mask;
69 mask = 1 << irq;
70 if (s->elcr & mask) {
71 /* level triggered */
72 if (level) {
73 s->irr |= mask;
74 s->last_irr |= mask;
75 } else {
76 s->irr &= ~mask;
77 s->last_irr &= ~mask;
78 }
79 } else {
80 /* edge triggered */
81 if (level) {
82 if ((s->last_irr & mask) == 0)
83 s->irr |= mask;
84 s->last_irr |= mask;
85 } else {
86 s->last_irr &= ~mask;
87 }
88 }
89 }
91 /* return the highest priority found in mask (highest = smallest
92 number). Return 8 if no irq */
93 static inline int get_priority(PicState *s, int mask)
94 {
95 int priority;
96 if (mask == 0)
97 return 8;
98 priority = 0;
99 while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0)
100 priority++;
101 return priority;
102 }
104 /* return the pic wanted interrupt. return -1 if none */
105 static int pic_get_irq(PicState *s)
106 {
107 int mask, cur_priority, priority;
109 mask = s->irr & ~s->imr;
110 priority = get_priority(s, mask);
111 if (priority == 8)
112 return -1;
113 /* compute current priority. If special fully nested mode on the
114 master, the IRQ coming from the slave is not taken into account
115 for the priority computation. */
116 mask = s->isr;
117 if (s->special_fully_nested_mode && s == &pics[0])
118 mask &= ~(1 << 2);
119 cur_priority = get_priority(s, mask);
120 if (priority < cur_priority) {
121 /* higher priority found: an irq should be generated */
122 return (priority + s->priority_add) & 7;
123 } else {
124 return -1;
125 }
126 }
128 /* pic[1] is connected to pin2 of pic[0] */
129 #define CASCADE_IRQ 2
131 extern shared_iopage_t *shared_page;
133 static void xen_update_shared_imr(void)
134 {
135 uint8_t *pmask = (uint8_t *)shared_page->sp_global.pic_mask;
136 int index;
138 index = pics[0].irq_base/8;
139 pmask[index] = pics[0].imr;
141 index = pics[1].irq_base/8;
142 pmask[index] = (pics[0].imr & (1 << CASCADE_IRQ)) ? 0xff : pics[1].imr;
143 }
145 static void xen_clear_shared_irr(void)
146 {
147 memset(shared_page->sp_global.pic_intr, 0, INTR_LEN);
148 }
150 /* raise irq to CPU if necessary. must be called every time the active
151 irq may change */
152 static void pic_update_irq(void)
153 {
154 int irq2, irq;
156 /* first look at slave pic */
157 irq2 = pic_get_irq(&pics[1]);
158 if (irq2 >= 0) {
159 /* if irq request by slave pic, signal master PIC */
160 pic_set_irq1(&pics[0], 2, 1);
161 pic_set_irq1(&pics[0], 2, 0);
162 }
163 /* look at requested irq */
164 irq = pic_get_irq(&pics[0]);
165 if (irq >= 0) {
166 #if defined(DEBUG_PIC)
167 {
168 int i;
169 for(i = 0; i < 2; i++) {
170 printf("pic%d: imr=%x irr=%x padd=%d\n",
171 i, pics[i].imr, pics[i].irr, pics[i].priority_add);
173 }
174 }
175 printf("pic: cpu_interrupt\n");
176 #endif
177 cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
178 }
180 xen_update_shared_imr();
181 }
183 #ifdef DEBUG_IRQ_LATENCY
184 int64_t irq_time[16];
185 #endif
187 extern void ioapic_legacy_irq(int irq, int level);
189 void pic_set_irq(int irq, int level)
190 {
191 ioapic_legacy_irq(irq, level);
192 #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
193 if (level != irq_level[irq]) {
194 #if defined(DEBUG_PIC)
195 printf("pic_set_irq: irq=%d level=%d\n", irq, level);
196 #endif
197 irq_level[irq] = level;
198 #ifdef DEBUG_IRQ_COUNT
199 if (level == 1)
200 irq_count[irq]++;
201 #endif
202 }
203 #endif
204 #ifdef DEBUG_IRQ_LATENCY
205 if (level) {
206 irq_time[irq] = qemu_get_clock(vm_clock);
207 }
208 #endif
209 pic_set_irq1(&pics[irq >> 3], irq & 7, level);
210 pic_update_irq();
211 }
213 /* acknowledge interrupt 'irq' */
214 static inline void pic_intack(PicState *s, int irq)
215 {
216 if (s->auto_eoi) {
217 if (s->rotate_on_auto_eoi)
218 s->priority_add = (irq + 1) & 7;
219 } else {
220 s->isr |= (1 << irq);
221 }
222 /* We don't clear a level sensitive interrupt here */
223 if (!(s->elcr & (1 << irq)))
224 s->irr &= ~(1 << irq);
225 }
227 int cpu_get_pic_interrupt(CPUState *env)
228 {
229 int irq, irq2, intno;
231 /* read the irq from the PIC */
233 irq = pic_get_irq(&pics[0]);
234 if (irq >= 0) {
235 pic_intack(&pics[0], irq);
236 if (irq == 2) {
237 irq2 = pic_get_irq(&pics[1]);
238 if (irq2 >= 0) {
239 pic_intack(&pics[1], irq2);
240 } else {
241 /* spurious IRQ on slave controller */
242 irq2 = 7;
243 }
244 intno = pics[1].irq_base + irq2;
245 irq = irq2 + 8;
246 } else {
247 intno = pics[0].irq_base + irq;
248 }
249 } else {
250 /* spurious IRQ on host controller */
251 irq = 7;
252 intno = pics[0].irq_base + irq;
253 }
254 pic_update_irq();
256 #ifdef DEBUG_IRQ_LATENCY
257 printf("IRQ%d latency=%0.3fus\n",
258 irq,
259 (double)(qemu_get_clock(vm_clock) - irq_time[irq]) * 1000000.0 / ticks_per_sec);
260 #endif
261 #if defined(DEBUG_PIC)
262 printf("pic_interrupt: irq=%d\n", irq);
263 #endif
264 return intno;
265 }
267 int pic_irq2vec(int irq)
268 {
269 int vector = -1;
271 if (irq >= 8 && irq <= 15) {
272 if (pics[1].irq_base != 0xFF)
273 vector = pics[1].irq_base + irq;
274 } else if (irq != 2 && irq <= 7) {
275 if (pics[0].irq_base != 0xFF)
276 vector = pics[0].irq_base + irq;
277 }
278 return vector;
279 }
281 static void pic_reset(void *opaque)
282 {
283 PicState *s = opaque;
284 int tmp;
286 tmp = s->elcr_mask;
287 memset(s, 0, sizeof(PicState));
288 s->elcr_mask = tmp;
290 xen_update_shared_imr();
291 xen_clear_shared_irr();
292 }
294 static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
295 {
296 PicState *s = opaque;
297 int priority, cmd, irq;
299 #ifdef DEBUG_PIC
300 printf("pic_write: addr=0x%02x val=0x%02x\n", addr, val);
301 #endif
302 addr &= 1;
303 if (addr == 0) {
304 if (val & 0x10) {
305 /* init */
306 pic_reset(s);
307 /* deassert a pending interrupt */
308 cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
310 s->init_state = 1;
311 s->init4 = val & 1;
312 if (val & 0x02)
313 hw_error("single mode not supported");
314 if (val & 0x08)
315 hw_error("level sensitive irq not supported");
316 } else if (val & 0x08) {
317 if (val & 0x04)
318 s->poll = 1;
319 if (val & 0x02)
320 s->read_reg_select = val & 1;
321 if (val & 0x40)
322 s->special_mask = (val >> 5) & 1;
323 } else {
324 cmd = val >> 5;
325 switch(cmd) {
326 case 0:
327 case 4:
328 s->rotate_on_auto_eoi = cmd >> 2;
329 break;
330 case 1: /* end of interrupt */
331 case 5:
332 priority = get_priority(s, s->isr);
333 if (priority != 8) {
334 irq = (priority + s->priority_add) & 7;
335 s->isr &= ~(1 << irq);
336 if (cmd == 5)
337 s->priority_add = (irq + 1) & 7;
338 pic_update_irq();
339 }
340 break;
341 case 3:
342 irq = val & 7;
343 s->isr &= ~(1 << irq);
344 pic_update_irq();
345 break;
346 case 6:
347 s->priority_add = (val + 1) & 7;
348 pic_update_irq();
349 break;
350 case 7:
351 irq = val & 7;
352 s->isr &= ~(1 << irq);
353 s->priority_add = (irq + 1) & 7;
354 pic_update_irq();
355 break;
356 default:
357 /* no operation */
358 break;
359 }
360 }
361 } else {
362 switch(s->init_state) {
363 case 0:
364 /* normal mode */
365 s->imr = val;
366 pic_update_irq();
367 break;
368 case 1:
369 s->irq_base = val & 0xf8;
370 s->init_state = 2;
371 pit_reset_vmx_vectors();
372 break;
373 case 2:
374 if (s->init4) {
375 s->init_state = 3;
376 } else {
377 s->init_state = 0;
378 }
379 break;
380 case 3:
381 s->special_fully_nested_mode = (val >> 4) & 1;
382 s->auto_eoi = (val >> 1) & 1;
383 s->init_state = 0;
384 break;
385 }
386 }
387 }
389 static uint32_t pic_poll_read (PicState *s, uint32_t addr1)
390 {
391 int ret;
393 ret = pic_get_irq(s);
394 if (ret >= 0) {
395 if (addr1 >> 7) {
396 pics[0].isr &= ~(1 << 2);
397 pics[0].irr &= ~(1 << 2);
398 }
399 s->irr &= ~(1 << ret);
400 s->isr &= ~(1 << ret);
401 if (addr1 >> 7 || ret != 2)
402 pic_update_irq();
403 } else {
404 ret = 0x07;
405 pic_update_irq();
406 }
408 return ret;
409 }
411 static uint32_t pic_ioport_read(void *opaque, uint32_t addr1)
412 {
413 PicState *s = opaque;
414 unsigned int addr;
415 int ret;
417 addr = addr1;
418 addr &= 1;
419 if (s->poll) {
420 ret = pic_poll_read(s, addr1);
421 s->poll = 0;
422 } else {
423 if (addr == 0) {
424 if (s->read_reg_select)
425 ret = s->isr;
426 else
427 ret = s->irr;
428 } else {
429 ret = s->imr;
430 }
431 }
432 #ifdef DEBUG_PIC
433 printf("pic_read: addr=0x%02x val=0x%02x\n", addr1, ret);
434 #endif
435 return ret;
436 }
438 /* memory mapped interrupt status */
439 uint32_t pic_intack_read(CPUState *env)
440 {
441 int ret;
443 ret = pic_poll_read(&pics[0], 0x00);
444 if (ret == 2)
445 ret = pic_poll_read(&pics[1], 0x80) + 8;
446 /* Prepare for ISR read */
447 pics[0].read_reg_select = 1;
449 return ret;
450 }
452 static void elcr_ioport_write(void *opaque, uint32_t addr, uint32_t val)
453 {
454 PicState *s = opaque;
455 s->elcr = val & s->elcr_mask;
456 }
458 static uint32_t elcr_ioport_read(void *opaque, uint32_t addr1)
459 {
460 PicState *s = opaque;
461 return s->elcr;
462 }
464 static void pic_save(QEMUFile *f, void *opaque)
465 {
466 PicState *s = opaque;
468 qemu_put_8s(f, &s->last_irr);
469 qemu_put_8s(f, &s->irr);
470 qemu_put_8s(f, &s->imr);
471 qemu_put_8s(f, &s->isr);
472 qemu_put_8s(f, &s->priority_add);
473 qemu_put_8s(f, &s->irq_base);
474 qemu_put_8s(f, &s->read_reg_select);
475 qemu_put_8s(f, &s->poll);
476 qemu_put_8s(f, &s->special_mask);
477 qemu_put_8s(f, &s->init_state);
478 qemu_put_8s(f, &s->auto_eoi);
479 qemu_put_8s(f, &s->rotate_on_auto_eoi);
480 qemu_put_8s(f, &s->special_fully_nested_mode);
481 qemu_put_8s(f, &s->init4);
482 qemu_put_8s(f, &s->elcr);
483 }
485 static int pic_load(QEMUFile *f, void *opaque, int version_id)
486 {
487 PicState *s = opaque;
489 if (version_id != 1)
490 return -EINVAL;
492 qemu_get_8s(f, &s->last_irr);
493 qemu_get_8s(f, &s->irr);
494 qemu_get_8s(f, &s->imr);
495 qemu_get_8s(f, &s->isr);
496 qemu_get_8s(f, &s->priority_add);
497 qemu_get_8s(f, &s->irq_base);
498 qemu_get_8s(f, &s->read_reg_select);
499 qemu_get_8s(f, &s->poll);
500 qemu_get_8s(f, &s->special_mask);
501 qemu_get_8s(f, &s->init_state);
502 qemu_get_8s(f, &s->auto_eoi);
503 qemu_get_8s(f, &s->rotate_on_auto_eoi);
504 qemu_get_8s(f, &s->special_fully_nested_mode);
505 qemu_get_8s(f, &s->init4);
506 qemu_get_8s(f, &s->elcr);
507 return 0;
508 }
510 /* XXX: add generic master/slave system */
511 static void pic_init1(int io_addr, int elcr_addr, PicState *s)
512 {
513 register_ioport_write(io_addr, 2, 1, pic_ioport_write, s);
514 register_ioport_read(io_addr, 2, 1, pic_ioport_read, s);
515 if (elcr_addr >= 0) {
516 register_ioport_write(elcr_addr, 1, 1, elcr_ioport_write, s);
517 register_ioport_read(elcr_addr, 1, 1, elcr_ioport_read, s);
518 }
519 register_savevm("i8259", io_addr, 1, pic_save, pic_load, s);
520 qemu_register_reset(pic_reset, s);
521 }
523 void pic_info(void)
524 {
525 int i;
526 PicState *s;
528 for(i=0;i<2;i++) {
529 s = &pics[i];
530 term_printf("pic%d: irr=%02x imr=%02x isr=%02x hprio=%d irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
531 i, s->irr, s->imr, s->isr, s->priority_add,
532 s->irq_base, s->read_reg_select, s->elcr,
533 s->special_fully_nested_mode);
534 }
535 }
537 void irq_info(void)
538 {
539 #ifndef DEBUG_IRQ_COUNT
540 term_printf("irq statistic code not compiled.\n");
541 #else
542 int i;
543 int64_t count;
545 term_printf("IRQ statistics:\n");
546 for (i = 0; i < 16; i++) {
547 count = irq_count[i];
548 if (count > 0)
549 term_printf("%2d: %lld\n", i, count);
550 }
551 #endif
552 }
554 void pic_init(void)
555 {
556 pic_init1(0x20, 0x4d0, &pics[0]);
557 pic_init1(0xa0, 0x4d1, &pics[1]);
558 pics[0].elcr_mask = 0xf8;
559 pics[1].elcr_mask = 0xde;
560 pics[0].irq_base = 0xff;
561 pics[0].irq_base = 0xff;
562 }