Commit d592d3033d7bc41db6159e9387591a216e3c46e0

Authored by bellard
1 parent 1ff5c1a6

IOAPIC support (initial patch by Filip Navara)

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1520 c046a42c-6fe2-441c-8c8c-71466251a162
hw/apic.c
... ... @@ -20,6 +20,7 @@
20 20 #include "vl.h"
21 21  
22 22 //#define DEBUG_APIC
  23 +//#define DEBUG_IOAPIC
23 24  
24 25 /* APIC Local Vector Table */
25 26 #define APIC_LVT_TIMER 0
... ... @@ -39,6 +40,10 @@
39 40 #define APIC_DM_SIPI 6
40 41 #define APIC_DM_EXTINT 7
41 42  
  43 +/* APIC destination mode */
  44 +#define APIC_DESTMODE_FLAT 0xf
  45 +#define APIC_DESTMODE_CLUSTER 1
  46 +
42 47 #define APIC_TRIGGER_EDGE 0
43 48 #define APIC_TRIGGER_LEVEL 1
44 49  
... ... @@ -49,6 +54,8 @@
49 54 #define APIC_INPUT_POLARITY (1<<13)
50 55 #define APIC_SEND_PENDING (1<<12)
51 56  
  57 +#define IOAPIC_NUM_PINS 0x18
  58 +
52 59 #define ESR_ILLEGAL_ADDRESS (1 << 7)
53 60  
54 61 #define APIC_SV_ENABLE (1 << 8)
... ... @@ -57,8 +64,11 @@ typedef struct APICState {
57 64 CPUState *cpu_env;
58 65 uint32_t apicbase;
59 66 uint8_t id;
  67 + uint8_t arb_id;
60 68 uint8_t tpr;
61 69 uint32_t spurious_vec;
  70 + uint8_t log_dest;
  71 + uint8_t dest_mode;
62 72 uint32_t isr[8]; /* in service register */
63 73 uint32_t tmr[8]; /* trigger mode register */
64 74 uint32_t irr[8]; /* interrupt request register */
... ... @@ -71,9 +81,65 @@ typedef struct APICState {
71 81 uint32_t initial_count;
72 82 int64_t initial_count_load_time, next_time;
73 83 QEMUTimer *timer;
  84 +
  85 + struct APICState *next_apic;
74 86 } APICState;
75 87  
  88 +struct IOAPICState {
  89 + uint8_t id;
  90 + uint8_t ioregsel;
  91 +
  92 + uint32_t irr;
  93 + uint64_t ioredtbl[IOAPIC_NUM_PINS];
  94 +};
  95 +
76 96 static int apic_io_memory;
  97 +static APICState *first_local_apic = NULL;
  98 +static int last_apic_id = 0;
  99 +static IOAPICState *ioapic_state;
  100 +
  101 +static void apic_init_ipi(APICState *s);
  102 +static void apic_set_irq(APICState *s, int vector_num, int trigger_mode);
  103 +static void apic_update_irq(APICState *s);
  104 +
  105 +static void apic_bus_deliver(uint32_t deliver_bitmask, uint8_t delivery_mode,
  106 + uint8_t vector_num, uint8_t polarity,
  107 + uint8_t trigger_mode)
  108 +{
  109 + APICState *apic_iter;
  110 +
  111 + switch (delivery_mode) {
  112 + case APIC_DM_LOWPRI:
  113 + case APIC_DM_FIXED:
  114 + /* XXX: arbitration */
  115 + break;
  116 +
  117 + case APIC_DM_SMI:
  118 + case APIC_DM_NMI:
  119 + break;
  120 +
  121 + case APIC_DM_INIT:
  122 + /* normal INIT IPI sent to processors */
  123 + for (apic_iter = first_local_apic; apic_iter != NULL;
  124 + apic_iter = apic_iter->next_apic) {
  125 + apic_init_ipi(apic_iter);
  126 + }
  127 + return;
  128 +
  129 + case APIC_DM_EXTINT:
  130 + /* XXX: implement */
  131 + break;
  132 +
  133 + default:
  134 + return;
  135 + }
  136 +
  137 + for (apic_iter = first_local_apic; apic_iter != NULL;
  138 + apic_iter = apic_iter->next_apic) {
  139 + if (deliver_bitmask & (1 << apic_iter->id))
  140 + apic_set_irq(apic_iter, vector_num, trigger_mode);
  141 + }
  142 +}
77 143  
78 144 void cpu_set_apic_base(CPUState *env, uint64_t val)
79 145 {
... ... @@ -104,6 +170,7 @@ void cpu_set_apic_tpr(CPUX86State *env, uint8_t val)
104 170 {
105 171 APICState *s = env->apic_state;
106 172 s->tpr = (val & 0x0f) << 4;
  173 + apic_update_irq(s);
107 174 }
108 175  
109 176 uint8_t cpu_get_apic_tpr(CPUX86State *env)
... ... @@ -112,16 +179,24 @@ uint8_t cpu_get_apic_tpr(CPUX86State *env)
112 179 return s->tpr >> 4;
113 180 }
114 181  
115   -/* return -1 if no bit is set */
116   -static int get_highest_priority_int(uint32_t *tab)
  182 +int fls_bit(int value)
117 183 {
118   - int i;
119   - for(i = 0;i < 8; i++) {
120   - if (tab[i] != 0) {
121   - return i * 32 + ffs(tab[i]) - 1;
122   - }
123   - }
124   - return -1;
  184 + unsigned int ret = 0;
  185 +
  186 +#ifdef HOST_I386
  187 + __asm__ __volatile__ ("bsr %1, %0\n" : "+r" (ret) : "rm" (value));
  188 + return ret;
  189 +#else
  190 + if (value > 0xffff)
  191 + value >>= 16, ret = 16;
  192 + if (value > 0xff)
  193 + value >>= 8, ret += 8;
  194 + if (value > 0xf)
  195 + value >>= 4, ret += 4;
  196 + if (value > 0x3)
  197 + value >>= 2, ret += 2;
  198 + return ret + (value >> 1);
  199 +#endif
125 200 }
126 201  
127 202 static inline void set_bit(uint32_t *tab, int index)
... ... @@ -140,6 +215,18 @@ static inline void reset_bit(uint32_t *tab, int index)
140 215 tab[i] &= ~mask;
141 216 }
142 217  
  218 +/* return -1 if no bit is set */
  219 +static int get_highest_priority_int(uint32_t *tab)
  220 +{
  221 + int i;
  222 + for(i = 7; i >= 0; i--) {
  223 + if (tab[i] != 0) {
  224 + return i * 32 + fls_bit(tab[i]);
  225 + }
  226 + }
  227 + return -1;
  228 +}
  229 +
143 230 static int apic_get_ppr(APICState *s)
144 231 {
145 232 int tpr, isrv, ppr;
... ... @@ -156,16 +243,23 @@ static int apic_get_ppr(APICState *s)
156 243 return ppr;
157 244 }
158 245  
  246 +static int apic_get_arb_pri(APICState *s)
  247 +{
  248 + /* XXX: arbitration */
  249 + return 0;
  250 +}
  251 +
159 252 /* signal the CPU if an irq is pending */
160 253 static void apic_update_irq(APICState *s)
161 254 {
162   - int irrv, isrv;
  255 + int irrv, ppr;
  256 + if (!(s->spurious_vec & APIC_SV_ENABLE))
  257 + return;
163 258 irrv = get_highest_priority_int(s->irr);
164 259 if (irrv < 0)
165 260 return;
166   - isrv = get_highest_priority_int(s->isr);
167   - /* if the pending irq has less priority, we do not make a new request */
168   - if (isrv >= 0 && irrv >= isrv)
  261 + ppr = apic_get_ppr(s);
  262 + if (ppr && (irrv & 0xf0) <= (ppr & 0xf0))
169 263 return;
170 264 cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
171 265 }
... ... @@ -187,9 +281,116 @@ static void apic_eoi(APICState *s)
187 281 if (isrv < 0)
188 282 return;
189 283 reset_bit(s->isr, isrv);
  284 + /* XXX: send the EOI packet to the APIC bus to allow the I/O APIC to
  285 + set the remote IRR bit for level triggered interrupts. */
190 286 apic_update_irq(s);
191 287 }
192 288  
  289 +static uint32_t apic_get_delivery_bitmask(uint8_t dest, uint8_t dest_mode)
  290 +{
  291 + uint32_t mask = 0;
  292 + APICState *apic_iter;
  293 +
  294 + if (dest_mode == 0) {
  295 + if (dest == 0xff)
  296 + mask = 0xff;
  297 + else
  298 + mask = 1 << dest;
  299 + } else {
  300 + /* XXX: cluster mode */
  301 + for (apic_iter = first_local_apic; apic_iter != NULL;
  302 + apic_iter = apic_iter->next_apic) {
  303 + if (dest & apic_iter->log_dest)
  304 + mask |= (1 << apic_iter->id);
  305 + }
  306 + }
  307 +
  308 + return mask;
  309 +}
  310 +
  311 +
  312 +static void apic_init_ipi(APICState *s)
  313 +{
  314 + int i;
  315 +
  316 + for(i = 0; i < APIC_LVT_NB; i++)
  317 + s->lvt[i] = 1 << 16; /* mask LVT */
  318 + s->tpr = 0;
  319 + s->spurious_vec = 0xff;
  320 + s->log_dest = 0;
  321 + s->dest_mode = 0;
  322 + memset(s->isr, 0, sizeof(s->isr));
  323 + memset(s->tmr, 0, sizeof(s->tmr));
  324 + memset(s->irr, 0, sizeof(s->irr));
  325 + memset(s->lvt, 0, sizeof(s->lvt));
  326 + s->esr = 0;
  327 + memset(s->icr, 0, sizeof(s->icr));
  328 + s->divide_conf = 0;
  329 + s->count_shift = 0;
  330 + s->initial_count = 0;
  331 + s->initial_count_load_time = 0;
  332 + s->next_time = 0;
  333 +}
  334 +
  335 +static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode,
  336 + uint8_t delivery_mode, uint8_t vector_num,
  337 + uint8_t polarity, uint8_t trigger_mode)
  338 +{
  339 + uint32_t deliver_bitmask = 0;
  340 + int dest_shorthand = (s->icr[0] >> 18) & 3;
  341 + APICState *apic_iter;
  342 +
  343 + switch (delivery_mode) {
  344 + case APIC_DM_LOWPRI:
  345 + /* XXX: serch for focus processor, arbitration */
  346 + dest = s->id;
  347 +
  348 + case APIC_DM_INIT:
  349 + {
  350 + int trig_mode = (s->icr[0] >> 15) & 1;
  351 + int level = (s->icr[0] >> 14) & 1;
  352 + if (level == 0 && trig_mode == 1) {
  353 + for (apic_iter = first_local_apic; apic_iter != NULL;
  354 + apic_iter = apic_iter->next_apic) {
  355 + if (deliver_bitmask & (1 << apic_iter->id)) {
  356 + apic_iter->arb_id = apic_iter->id;
  357 + }
  358 + }
  359 + return;
  360 + }
  361 + }
  362 + break;
  363 +
  364 + case APIC_DM_SIPI:
  365 + for (apic_iter = first_local_apic; apic_iter != NULL;
  366 + apic_iter = apic_iter->next_apic) {
  367 + if (deliver_bitmask & (1 << apic_iter->id)) {
  368 + /* XXX: SMP support */
  369 + /* apic_startup(apic_iter); */
  370 + }
  371 + }
  372 + return;
  373 + }
  374 +
  375 + switch (dest_shorthand) {
  376 + case 0:
  377 + deliver_bitmask = apic_get_delivery_bitmask(dest, dest_mode);
  378 + break;
  379 + case 1:
  380 + deliver_bitmask = (1 << s->id);
  381 + break;
  382 + case 2:
  383 + deliver_bitmask = 0xffffffff;
  384 + break;
  385 + case 3:
  386 + deliver_bitmask = 0xffffffff & ~(1 << s->id);
  387 + break;
  388 + }
  389 +
  390 + apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, polarity,
  391 + trigger_mode);
  392 +}
  393 +
193 394 int apic_get_interrupt(CPUState *env)
194 395 {
195 396 APICState *s = env->apic_state;
... ... @@ -207,6 +408,8 @@ int apic_get_interrupt(CPUState *env)
207 408 if (intno < 0)
208 409 return -1;
209 410 reset_bit(s->irr, intno);
  411 + if (s->tpr && intno <= s->tpr)
  412 + return s->spurious_vec & 0xff;
210 413 set_bit(s->isr, intno);
211 414 apic_update_irq(s);
212 415 return intno;
... ... @@ -220,7 +423,7 @@ static uint32_t apic_get_current_count(APICState *s)
220 423 s->count_shift;
221 424 if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
222 425 /* periodic */
223   - val = s->initial_count - (d % (s->initial_count + 1));
  426 + val = s->initial_count - (d % ((uint64_t)s->initial_count + 1));
224 427 } else {
225 428 if (d >= s->initial_count)
226 429 val = 0;
... ... @@ -238,11 +441,11 @@ static void apic_timer_update(APICState *s, int64_t current_time)
238 441 d = (current_time - s->initial_count_load_time) >>
239 442 s->count_shift;
240 443 if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
241   - d = ((d / (s->initial_count + 1)) + 1) * (s->initial_count + 1);
  444 + d = ((d / ((uint64_t)s->initial_count + 1)) + 1) * ((uint64_t)s->initial_count + 1);
242 445 } else {
243 446 if (d >= s->initial_count)
244 447 goto no_timer;
245   - d = s->initial_count + 1;
  448 + d = (uint64_t)s->initial_count + 1;
246 449 }
247 450 next_time = s->initial_count_load_time + (d << s->count_shift);
248 451 qemu_mod_timer(s->timer, next_time);
... ... @@ -304,10 +507,19 @@ static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
304 507 case 0x08:
305 508 val = s->tpr;
306 509 break;
  510 + case 0x09:
  511 + val = apic_get_arb_pri(s);
  512 + break;
307 513 case 0x0a:
308 514 /* ppr */
309 515 val = apic_get_ppr(s);
310 516 break;
  517 + case 0x0d:
  518 + val = s->log_dest << 24;
  519 + break;
  520 + case 0x0e:
  521 + val = s->dest_mode << 28;
  522 + break;
311 523 case 0x0f:
312 524 val = s->spurious_vec;
313 525 break;
... ... @@ -372,16 +584,29 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
372 584 break;
373 585 case 0x08:
374 586 s->tpr = val;
  587 + apic_update_irq(s);
375 588 break;
376 589 case 0x0b: /* EOI */
377 590 apic_eoi(s);
378 591 break;
  592 + case 0x0d:
  593 + s->log_dest = val >> 24;
  594 + break;
  595 + case 0x0e:
  596 + s->dest_mode = val >> 28;
  597 + break;
379 598 case 0x0f:
380 599 s->spurious_vec = val & 0x1ff;
  600 + apic_update_irq(s);
381 601 break;
382 602 case 0x30:
  603 + s->icr[0] = val;
  604 + apic_deliver(s, (s->icr[1] >> 24) & 0xff, (s->icr[0] >> 11) & 1,
  605 + (s->icr[0] >> 8) & 7, (s->icr[0] & 0xff),
  606 + (s->icr[0] >> 14) & 1, (s->icr[0] >> 15) & 1);
  607 + break;
383 608 case 0x31:
384   - s->icr[index & 1] = val;
  609 + s->icr[1] = val;
385 610 break;
386 611 case 0x32 ... 0x37:
387 612 {
... ... @@ -410,7 +635,76 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
410 635 }
411 636 }
412 637  
  638 +static void apic_save(QEMUFile *f, void *opaque)
  639 +{
  640 + APICState *s = opaque;
  641 + int i;
  642 +
  643 + qemu_put_be32s(f, &s->apicbase);
  644 + qemu_put_8s(f, &s->id);
  645 + qemu_put_8s(f, &s->arb_id);
  646 + qemu_put_8s(f, &s->tpr);
  647 + qemu_put_be32s(f, &s->spurious_vec);
  648 + qemu_put_8s(f, &s->log_dest);
  649 + qemu_put_8s(f, &s->dest_mode);
  650 + for (i = 0; i < 8; i++) {
  651 + qemu_put_be32s(f, &s->isr[i]);
  652 + qemu_put_be32s(f, &s->tmr[i]);
  653 + qemu_put_be32s(f, &s->irr[i]);
  654 + }
  655 + for (i = 0; i < APIC_LVT_NB; i++) {
  656 + qemu_put_be32s(f, &s->lvt[i]);
  657 + }
  658 + qemu_put_be32s(f, &s->esr);
  659 + qemu_put_be32s(f, &s->icr[0]);
  660 + qemu_put_be32s(f, &s->icr[1]);
  661 + qemu_put_be32s(f, &s->divide_conf);
  662 + qemu_put_be32s(f, &s->count_shift);
  663 + qemu_put_be32s(f, &s->initial_count);
  664 + qemu_put_be64s(f, &s->initial_count_load_time);
  665 + qemu_put_be64s(f, &s->next_time);
  666 +}
  667 +
  668 +static int apic_load(QEMUFile *f, void *opaque, int version_id)
  669 +{
  670 + APICState *s = opaque;
  671 + int i;
  672 +
  673 + if (version_id != 1)
  674 + return -EINVAL;
  675 +
  676 + /* XXX: what if the base changes? (registered memory regions) */
  677 + qemu_get_be32s(f, &s->apicbase);
  678 + qemu_get_8s(f, &s->id);
  679 + qemu_get_8s(f, &s->arb_id);
  680 + qemu_get_8s(f, &s->tpr);
  681 + qemu_get_be32s(f, &s->spurious_vec);
  682 + qemu_get_8s(f, &s->log_dest);
  683 + qemu_get_8s(f, &s->dest_mode);
  684 + for (i = 0; i < 8; i++) {
  685 + qemu_get_be32s(f, &s->isr[i]);
  686 + qemu_get_be32s(f, &s->tmr[i]);
  687 + qemu_get_be32s(f, &s->irr[i]);
  688 + }
  689 + for (i = 0; i < APIC_LVT_NB; i++) {
  690 + qemu_get_be32s(f, &s->lvt[i]);
  691 + }
  692 + qemu_get_be32s(f, &s->esr);
  693 + qemu_get_be32s(f, &s->icr[0]);
  694 + qemu_get_be32s(f, &s->icr[1]);
  695 + qemu_get_be32s(f, &s->divide_conf);
  696 + qemu_get_be32s(f, &s->count_shift);
  697 + qemu_get_be32s(f, &s->initial_count);
  698 + qemu_get_be64s(f, &s->initial_count_load_time);
  699 + qemu_get_be64s(f, &s->next_time);
  700 + return 0;
  701 +}
413 702  
  703 +static void apic_reset(void *opaque)
  704 +{
  705 + APICState *s = opaque;
  706 + apic_init_ipi(s);
  707 +}
414 708  
415 709 static CPUReadMemoryFunc *apic_mem_read[3] = {
416 710 apic_mem_readb,
... ... @@ -427,27 +721,228 @@ static CPUWriteMemoryFunc *apic_mem_write[3] = {
427 721 int apic_init(CPUState *env)
428 722 {
429 723 APICState *s;
430   - int i;
431 724  
432   - s = malloc(sizeof(APICState));
  725 + s = qemu_mallocz(sizeof(APICState));
433 726 if (!s)
434 727 return -1;
435   - memset(s, 0, sizeof(*s));
436 728 env->apic_state = s;
  729 + apic_init_ipi(s);
  730 + s->id = last_apic_id++;
437 731 s->cpu_env = env;
438 732 s->apicbase = 0xfee00000 |
439   - MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE;
440   - for(i = 0; i < APIC_LVT_NB; i++)
441   - s->lvt[i] = 1 << 16; /* mask LVT */
442   - s->spurious_vec = 0xff;
  733 + (s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE;
443 734  
  735 + /* XXX: mapping more APICs at the same memory location */
444 736 if (apic_io_memory == 0) {
445 737 /* NOTE: the APIC is directly connected to the CPU - it is not
446 738 on the global memory bus. */
447 739 apic_io_memory = cpu_register_io_memory(0, apic_mem_read,
448 740 apic_mem_write, NULL);
449   - cpu_register_physical_memory(s->apicbase & ~0xfff, 0x1000, apic_io_memory);
  741 + cpu_register_physical_memory(s->apicbase & ~0xfff, 0x1000,
  742 + apic_io_memory);
450 743 }
451 744 s->timer = qemu_new_timer(vm_clock, apic_timer, s);
  745 +
  746 + register_savevm("apic", 0, 1, apic_save, apic_load, s);
  747 + qemu_register_reset(apic_reset, s);
  748 +
  749 + s->next_apic = first_local_apic;
  750 + first_local_apic = s;
  751 +
  752 + return 0;
  753 +}
  754 +
  755 +static void ioapic_service(IOAPICState *s)
  756 +{
  757 + uint8_t vector;
  758 + uint32_t mask;
  759 + uint64_t entry;
  760 + uint8_t dest;
  761 + uint8_t dest_mode;
  762 +
  763 + for (vector = 0; vector < IOAPIC_NUM_PINS; vector++) {
  764 + mask = 1 << vector;
  765 + if (s->irr & mask) {
  766 + entry = s->ioredtbl[vector];
  767 + if (!(entry & APIC_LVT_MASKED)) {
  768 + if (!((entry >> 15) & 1))
  769 + s->irr &= ~mask;
  770 + dest = entry >> 56;
  771 + dest_mode = (entry >> 11) & 1;
  772 + apic_bus_deliver(apic_get_delivery_bitmask(dest, dest_mode),
  773 + (entry >> 8) & 7, entry & 0xff,
  774 + (entry >> 13) & 1, (entry >> 15) & 1);
  775 + }
  776 + }
  777 + }
  778 +}
  779 +
  780 +void ioapic_set_irq(void *opaque, int vector, int level)
  781 +{
  782 + IOAPICState *s = opaque;
  783 +
  784 + if (vector >= 0 && vector < IOAPIC_NUM_PINS) {
  785 + uint32_t mask = 1 << vector;
  786 + uint64_t entry = s->ioredtbl[vector];
  787 +
  788 + if ((entry >> 15) & 1) {
  789 + /* level triggered */
  790 + if (level) {
  791 + s->irr |= mask;
  792 + ioapic_service(s);
  793 + } else {
  794 + s->irr &= ~mask;
  795 + }
  796 + } else {
  797 + /* edge triggered */
  798 + if (level) {
  799 + s->irr |= mask;
  800 + ioapic_service(s);
  801 + }
  802 + }
  803 + }
  804 +}
  805 +
  806 +static uint32_t ioapic_mem_readl(void *opaque, target_phys_addr_t addr)
  807 +{
  808 + IOAPICState *s = opaque;
  809 + int index;
  810 + uint32_t val = 0;
  811 +
  812 + addr &= 0xff;
  813 + if (addr == 0x00) {
  814 + val = s->ioregsel;
  815 + } else if (addr == 0x10) {
  816 + switch (s->ioregsel) {
  817 + case 0x00:
  818 + val = s->id << 24;
  819 + break;
  820 + case 0x01:
  821 + val = 0x11 | ((IOAPIC_NUM_PINS - 1) << 16); /* version 0x11 */
  822 + break;
  823 + case 0x02:
  824 + val = 0;
  825 + break;
  826 + default:
  827 + index = (s->ioregsel - 0x10) >> 1;
  828 + if (index >= 0 && index < IOAPIC_NUM_PINS) {
  829 + if (s->ioregsel & 1)
  830 + val = s->ioredtbl[index] >> 32;
  831 + else
  832 + val = s->ioredtbl[index] & 0xffffffff;
  833 + }
  834 + }
  835 +#ifdef DEBUG_IOAPIC
  836 + printf("I/O APIC read: %08x = %08x\n", s->ioregsel, val);
  837 +#endif
  838 + }
  839 + return val;
  840 +}
  841 +
  842 +static void ioapic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
  843 +{
  844 + IOAPICState *s = opaque;
  845 + int index;
  846 +
  847 + addr &= 0xff;
  848 + if (addr == 0x00) {
  849 + s->ioregsel = val;
  850 + return;
  851 + } else if (addr == 0x10) {
  852 +#ifdef DEBUG_IOAPIC
  853 + printf("I/O APIC write: %08x = %08x\n", s->ioregsel, val);
  854 +#endif
  855 + switch (s->ioregsel) {
  856 + case 0x00:
  857 + s->id = (val >> 24) & 0xff;
  858 + return;
  859 + case 0x01:
  860 + case 0x02:
  861 + return;
  862 + default:
  863 + index = (s->ioregsel - 0x10) >> 1;
  864 + if (index >= 0 && index < IOAPIC_NUM_PINS) {
  865 + if (s->ioregsel & 1) {
  866 + s->ioredtbl[index] &= 0xffffffff;
  867 + s->ioredtbl[index] |= (uint64_t)val << 32;
  868 + } else {
  869 + s->ioredtbl[index] &= ~0xffffffffULL;
  870 + s->ioredtbl[index] |= val;
  871 + }
  872 + ioapic_service(s);
  873 + }
  874 + }
  875 + }
  876 +}
  877 +
  878 +static void ioapic_save(QEMUFile *f, void *opaque)
  879 +{
  880 + IOAPICState *s = opaque;
  881 + int i;
  882 +
  883 + qemu_put_8s(f, &s->id);
  884 + qemu_put_8s(f, &s->ioregsel);
  885 + for (i = 0; i < IOAPIC_NUM_PINS; i++) {
  886 + qemu_put_be64s(f, &s->ioredtbl[i]);
  887 + }
  888 +}
  889 +
  890 +static int ioapic_load(QEMUFile *f, void *opaque, int version_id)
  891 +{
  892 + IOAPICState *s = opaque;
  893 + int i;
  894 +
  895 + if (version_id != 1)
  896 + return -EINVAL;
  897 +
  898 + qemu_get_8s(f, &s->id);
  899 + qemu_get_8s(f, &s->ioregsel);
  900 + for (i = 0; i < IOAPIC_NUM_PINS; i++) {
  901 + qemu_get_be64s(f, &s->ioredtbl[i]);
  902 + }
452 903 return 0;
453 904 }
  905 +
  906 +static void ioapic_reset(void *opaque)
  907 +{
  908 + IOAPICState *s = opaque;
  909 + int i;
  910 +
  911 + memset(s, 0, sizeof(*s));
  912 + for(i = 0; i < IOAPIC_NUM_PINS; i++)
  913 + s->ioredtbl[i] = 1 << 16; /* mask LVT */
  914 +}
  915 +
  916 +static CPUReadMemoryFunc *ioapic_mem_read[3] = {
  917 + ioapic_mem_readl,
  918 + ioapic_mem_readl,
  919 + ioapic_mem_readl,
  920 +};
  921 +
  922 +static CPUWriteMemoryFunc *ioapic_mem_write[3] = {
  923 + ioapic_mem_writel,
  924 + ioapic_mem_writel,
  925 + ioapic_mem_writel,
  926 +};
  927 +
  928 +IOAPICState *ioapic_init(void)
  929 +{
  930 + IOAPICState *s;
  931 + int io_memory;
  932 +
  933 + s = malloc(sizeof(IOAPICState));
  934 + if (!s)
  935 + return NULL;
  936 + ioapic_state = s;
  937 + ioapic_reset(s);
  938 + s->id = last_apic_id++;
  939 +
  940 + io_memory = cpu_register_io_memory(0, ioapic_mem_read,
  941 + ioapic_mem_write, s);
  942 + cpu_register_physical_memory(0xfec00000, 0x1000, io_memory);
  943 +
  944 + register_savevm("ioapic", 0, 1, ioapic_save, ioapic_load, s);
  945 + qemu_register_reset(ioapic_reset, s);
  946 +
  947 + return s;
  948 +}
... ...
hw/i8259.c
... ... @@ -55,6 +55,9 @@ struct PicState2 {
55 55 PicState pics[2];
56 56 IRQRequestFunc *irq_request;
57 57 void *irq_request_opaque;
  58 + /* IOAPIC callback support */
  59 + SetIRQFunc *alt_irq_func;
  60 + void *alt_irq_opaque;
58 61 };
59 62  
60 63 #if defined(DEBUG_PIC) || defined (DEBUG_IRQ_COUNT)
... ... @@ -186,6 +189,9 @@ void pic_set_irq_new(void *opaque, int irq, int level)
186 189 }
187 190 #endif
188 191 pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
  192 + /* used for IOAPIC irqs */
  193 + if (s->alt_irq_func)
  194 + s->alt_irq_func(s->alt_irq_opaque, irq, level);
189 195 pic_update_irq(s);
190 196 }
191 197  
... ... @@ -546,3 +552,10 @@ PicState2 *pic_init(IRQRequestFunc *irq_request, void *irq_request_opaque)
546 552 s->pics[1].pics_state = s;
547 553 return s;
548 554 }
  555 +
  556 +void pic_set_alt_irq_func(PicState2 *s, SetIRQFunc *alt_irq_func,
  557 + void *alt_irq_opaque)
  558 +{
  559 + s->alt_irq_func = alt_irq_func;
  560 + s->alt_irq_opaque = alt_irq_opaque;
  561 +}
... ...
... ... @@ -41,6 +41,7 @@ int dummy_refresh_clock;
41 41 static fdctrl_t *floppy_controller;
42 42 static RTCState *rtc_state;
43 43 static PITState *pit;
  44 +static IOAPICState *ioapic;
44 45  
45 46 static void ioport80_write(void *opaque, uint32_t addr, uint32_t data)
46 47 {
... ... @@ -70,7 +71,6 @@ int cpu_get_pic_interrupt(CPUState *env)
70 71 {
71 72 int intno;
72 73  
73   -#ifdef TARGET_X86_64
74 74 intno = apic_get_interrupt(env);
75 75 if (intno >= 0) {
76 76 /* set irq request if a PIC irq is still pending */
... ... @@ -78,7 +78,6 @@ int cpu_get_pic_interrupt(CPUState *env)
78 78 pic_update_irq(isa_pic);
79 79 return intno;
80 80 }
81   -#endif
82 81 /* read the irq from the PIC */
83 82 intno = pic_read_irq(isa_pic);
84 83 return intno;
... ... @@ -417,7 +416,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
417 416 unsigned long bios_offset, vga_bios_offset;
418 417 int bios_size, isa_bios_size;
419 418 PCIBus *pci_bus;
420   -
  419 +
421 420 linux_boot = (kernel_filename != NULL);
422 421  
423 422 /* allocate RAM */
... ... @@ -557,10 +556,15 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
557 556 register_ioport_read(0x92, 1, 1, ioport92_read, NULL);
558 557 register_ioport_write(0x92, 1, 1, ioport92_write, NULL);
559 558  
560   - if (pci_enabled)
  559 + if (pci_enabled) {
561 560 apic_init(cpu_single_env);
  561 + ioapic = ioapic_init();
  562 + }
562 563 isa_pic = pic_init(pic_irq_request, cpu_single_env);
563 564 pit = pit_init(0x40, 0);
  565 + if (pci_enabled) {
  566 + pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic);
  567 + }
564 568  
565 569 for(i = 0; i < MAX_SERIAL_PORTS; i++) {
566 570 if (serial_hds[i]) {
... ...
... ... @@ -695,6 +695,8 @@ extern PicState2 *isa_pic;
695 695 void pic_set_irq(int irq, int level);
696 696 void pic_set_irq_new(void *opaque, int irq, int level);
697 697 PicState2 *pic_init(IRQRequestFunc *irq_request, void *irq_request_opaque);
  698 +void pic_set_alt_irq_func(PicState2 *s, SetIRQFunc *alt_irq_func,
  699 + void *alt_irq_opaque);
698 700 int pic_read_irq(PicState2 *s);
699 701 void pic_update_irq(PicState2 *s);
700 702 uint32_t pic_intack_read(PicState2 *s);
... ... @@ -702,8 +704,12 @@ void pic_info(void);
702 704 void irq_info(void);
703 705  
704 706 /* APIC */
  707 +typedef struct IOAPICState IOAPICState;
  708 +
705 709 int apic_init(CPUState *env);
706 710 int apic_get_interrupt(CPUState *env);
  711 +IOAPICState *ioapic_init(void);
  712 +void ioapic_set_irq(void *opaque, int vector, int level);
707 713  
708 714 /* i8254.c */
709 715  
... ...