Commit a5b38b5171ea46e13612a3471a7cc735db6d6f72
1 parent
e2eb9d3e
x86: Rework local IRQ delivery for APICs
(Jan Kiszka) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4207 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
57 additions
and
24 deletions
hw/apic.c
| ... | ... | @@ -166,6 +166,37 @@ static inline void reset_bit(uint32_t *tab, int index) |
| 166 | 166 | tab[i] &= ~mask; |
| 167 | 167 | } |
| 168 | 168 | |
| 169 | +void apic_local_deliver(CPUState *env, int vector) | |
| 170 | +{ | |
| 171 | + APICState *s = env->apic_state; | |
| 172 | + uint32_t lvt = s->lvt[vector]; | |
| 173 | + int trigger_mode; | |
| 174 | + | |
| 175 | + if (lvt & APIC_LVT_MASKED) | |
| 176 | + return; | |
| 177 | + | |
| 178 | + switch ((lvt >> 8) & 7) { | |
| 179 | + case APIC_DM_SMI: | |
| 180 | + cpu_interrupt(env, CPU_INTERRUPT_SMI); | |
| 181 | + break; | |
| 182 | + | |
| 183 | + case APIC_DM_NMI: | |
| 184 | + cpu_interrupt(env, CPU_INTERRUPT_NMI); | |
| 185 | + break; | |
| 186 | + | |
| 187 | + case APIC_DM_EXTINT: | |
| 188 | + cpu_interrupt(env, CPU_INTERRUPT_HARD); | |
| 189 | + break; | |
| 190 | + | |
| 191 | + case APIC_DM_FIXED: | |
| 192 | + trigger_mode = APIC_TRIGGER_EDGE; | |
| 193 | + if ((vector == APIC_LVT_LINT0 || vector == APIC_LVT_LINT1) && | |
| 194 | + (lvt & APIC_LVT_LEVEL_TRIGGER)) | |
| 195 | + trigger_mode = APIC_TRIGGER_LEVEL; | |
| 196 | + apic_set_irq(s, lvt & 0xff, trigger_mode); | |
| 197 | + } | |
| 198 | +} | |
| 199 | + | |
| 169 | 200 | #define foreach_apic(apic, deliver_bitmask, code) \ |
| 170 | 201 | {\ |
| 171 | 202 | int __i, __j, __mask;\ |
| ... | ... | @@ -502,10 +533,8 @@ int apic_accept_pic_intr(CPUState *env) |
| 502 | 533 | |
| 503 | 534 | lvt0 = s->lvt[APIC_LVT_LINT0]; |
| 504 | 535 | |
| 505 | - if (s->id == 0 && | |
| 506 | - ((s->apicbase & MSR_IA32_APICBASE_ENABLE) == 0 || | |
| 507 | - ((lvt0 & APIC_LVT_MASKED) == 0 && | |
| 508 | - ((lvt0 >> 8) & 0x7) == APIC_DM_EXTINT))) | |
| 536 | + if ((s->apicbase & MSR_IA32_APICBASE_ENABLE) == 0 || | |
| 537 | + (lvt0 & APIC_LVT_MASKED) == 0) | |
| 509 | 538 | return 1; |
| 510 | 539 | |
| 511 | 540 | return 0; |
| ... | ... | @@ -556,9 +585,7 @@ static void apic_timer(void *opaque) |
| 556 | 585 | { |
| 557 | 586 | APICState *s = opaque; |
| 558 | 587 | |
| 559 | - if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) { | |
| 560 | - apic_set_irq(s, s->lvt[APIC_LVT_TIMER] & 0xff, APIC_TRIGGER_EDGE); | |
| 561 | - } | |
| 588 | + apic_local_deliver(s->cpu_env, APIC_LVT_TIMER); | |
| 562 | 589 | apic_timer_update(s, s->next_time); |
| 563 | 590 | } |
| 564 | 591 | |
| ... | ... | @@ -821,12 +848,14 @@ static void apic_reset(void *opaque) |
| 821 | 848 | APICState *s = opaque; |
| 822 | 849 | apic_init_ipi(s); |
| 823 | 850 | |
| 824 | - /* | |
| 825 | - * LINT0 delivery mode is set to ExtInt at initialization time | |
| 826 | - * typically by BIOS, so PIC interrupt can be delivered to the | |
| 827 | - * processor when local APIC is enabled. | |
| 828 | - */ | |
| 829 | - s->lvt[APIC_LVT_LINT0] = 0x700; | |
| 851 | + if (s->id == 0) { | |
| 852 | + /* | |
| 853 | + * LINT0 delivery mode on CPU #0 is set to ExtInt at initialization | |
| 854 | + * time typically by BIOS, so PIC interrupt can be delivered to the | |
| 855 | + * processor when local APIC is enabled. | |
| 856 | + */ | |
| 857 | + s->lvt[APIC_LVT_LINT0] = 0x700; | |
| 858 | + } | |
| 830 | 859 | } |
| 831 | 860 | |
| 832 | 861 | static CPUReadMemoryFunc *apic_mem_read[3] = { |
| ... | ... | @@ -851,19 +880,13 @@ int apic_init(CPUState *env) |
| 851 | 880 | if (!s) |
| 852 | 881 | return -1; |
| 853 | 882 | env->apic_state = s; |
| 854 | - apic_init_ipi(s); | |
| 855 | 883 | s->id = last_apic_id++; |
| 856 | 884 | env->cpuid_apic_id = s->id; |
| 857 | 885 | s->cpu_env = env; |
| 858 | 886 | s->apicbase = 0xfee00000 | |
| 859 | 887 | (s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE; |
| 860 | 888 | |
| 861 | - /* | |
| 862 | - * LINT0 delivery mode is set to ExtInt at initialization time | |
| 863 | - * typically by BIOS, so PIC interrupt can be delivered to the | |
| 864 | - * processor when local APIC is enabled. | |
| 865 | - */ | |
| 866 | - s->lvt[APIC_LVT_LINT0] = 0x700; | |
| 889 | + apic_reset(s); | |
| 867 | 890 | |
| 868 | 891 | /* XXX: mapping more APICs at the same memory location */ |
| 869 | 892 | if (apic_io_memory == 0) { | ... | ... |
hw/pc.c
| ... | ... | @@ -113,9 +113,16 @@ int cpu_get_pic_interrupt(CPUState *env) |
| 113 | 113 | |
| 114 | 114 | static void pic_irq_request(void *opaque, int irq, int level) |
| 115 | 115 | { |
| 116 | - CPUState *env = opaque; | |
| 117 | - if (level && apic_accept_pic_intr(env)) | |
| 118 | - cpu_interrupt(env, CPU_INTERRUPT_HARD); | |
| 116 | + CPUState *env = first_cpu; | |
| 117 | + | |
| 118 | + if (!level) | |
| 119 | + return; | |
| 120 | + | |
| 121 | + while (env) { | |
| 122 | + if (apic_accept_pic_intr(env)) | |
| 123 | + apic_local_deliver(env, APIC_LINT0); | |
| 124 | + env = env->next_cpu; | |
| 125 | + } | |
| 119 | 126 | } |
| 120 | 127 | |
| 121 | 128 | /* PC cmos mappings */ |
| ... | ... | @@ -845,7 +852,7 @@ static void pc_init1(int ram_size, int vga_ram_size, |
| 845 | 852 | if (linux_boot) |
| 846 | 853 | load_linux(kernel_filename, initrd_filename, kernel_cmdline); |
| 847 | 854 | |
| 848 | - cpu_irq = qemu_allocate_irqs(pic_irq_request, first_cpu, 1); | |
| 855 | + cpu_irq = qemu_allocate_irqs(pic_irq_request, NULL, 1); | |
| 849 | 856 | i8259 = i8259_init(cpu_irq[0]); |
| 850 | 857 | ferr_irq = i8259[13]; |
| 851 | 858 | ... | ... |
hw/pc.h
| ... | ... | @@ -39,8 +39,11 @@ void irq_info(void); |
| 39 | 39 | /* APIC */ |
| 40 | 40 | typedef struct IOAPICState IOAPICState; |
| 41 | 41 | |
| 42 | +#define APIC_LINT0 3 | |
| 43 | + | |
| 42 | 44 | int apic_init(CPUState *env); |
| 43 | 45 | int apic_accept_pic_intr(CPUState *env); |
| 46 | +void apic_local_deliver(CPUState *env, int vector); | |
| 44 | 47 | int apic_get_interrupt(CPUState *env); |
| 45 | 48 | IOAPICState *ioapic_init(void); |
| 46 | 49 | void ioapic_set_irq(void *opaque, int vector, int level); | ... | ... |