Commit 0e21e12bb311c4c1095d0269dc2ef81196ccb60a
1 parent
aacb758b
Don't route PIC interrupts through the local APIC if the local APIC
config says so. By Ari Kivity. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3371 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
38 additions
and
3 deletions
hw/apic.c
| ... | ... | @@ -484,6 +484,25 @@ int apic_get_interrupt(CPUState *env) |
| 484 | 484 | return intno; |
| 485 | 485 | } |
| 486 | 486 | |
| 487 | +int apic_accept_pic_intr(CPUState *env) | |
| 488 | +{ | |
| 489 | + APICState *s = env->apic_state; | |
| 490 | + uint32_t lvt0; | |
| 491 | + | |
| 492 | + if (!s) | |
| 493 | + return -1; | |
| 494 | + | |
| 495 | + lvt0 = s->lvt[APIC_LVT_LINT0]; | |
| 496 | + | |
| 497 | + if (s->id == 0 && | |
| 498 | + ((s->apicbase & MSR_IA32_APICBASE_ENABLE) == 0 || | |
| 499 | + ((lvt0 & APIC_LVT_MASKED) == 0 && | |
| 500 | + ((lvt0 >> 8) & 0x7) == APIC_DM_EXTINT))) | |
| 501 | + return 1; | |
| 502 | + | |
| 503 | + return 0; | |
| 504 | +} | |
| 505 | + | |
| 487 | 506 | static uint32_t apic_get_current_count(APICState *s) |
| 488 | 507 | { |
| 489 | 508 | int64_t d; |
| ... | ... | @@ -790,6 +809,13 @@ static void apic_reset(void *opaque) |
| 790 | 809 | { |
| 791 | 810 | APICState *s = opaque; |
| 792 | 811 | apic_init_ipi(s); |
| 812 | + | |
| 813 | + /* | |
| 814 | + * LINT0 delivery mode is set to ExtInt at initialization time | |
| 815 | + * typically by BIOS, so PIC interrupt can be delivered to the | |
| 816 | + * processor when local APIC is enabled. | |
| 817 | + */ | |
| 818 | + s->lvt[APIC_LVT_LINT0] = 0x700; | |
| 793 | 819 | } |
| 794 | 820 | |
| 795 | 821 | static CPUReadMemoryFunc *apic_mem_read[3] = { |
| ... | ... | @@ -821,6 +847,13 @@ int apic_init(CPUState *env) |
| 821 | 847 | s->apicbase = 0xfee00000 | |
| 822 | 848 | (s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE; |
| 823 | 849 | |
| 850 | + /* | |
| 851 | + * LINT0 delivery mode is set to ExtInt at initialization time | |
| 852 | + * typically by BIOS, so PIC interrupt can be delivered to the | |
| 853 | + * processor when local APIC is enabled. | |
| 854 | + */ | |
| 855 | + s->lvt[APIC_LVT_LINT0] = 0x700; | |
| 856 | + | |
| 824 | 857 | /* XXX: mapping more APICs at the same memory location */ |
| 825 | 858 | if (apic_io_memory == 0) { |
| 826 | 859 | /* NOTE: the APIC is directly connected to the CPU - it is not | ... | ... |
hw/pc.c
| ... | ... | @@ -93,6 +93,9 @@ int cpu_get_pic_interrupt(CPUState *env) |
| 93 | 93 | return intno; |
| 94 | 94 | } |
| 95 | 95 | /* read the irq from the PIC */ |
| 96 | + if (!apic_accept_pic_intr(env)) | |
| 97 | + return -1; | |
| 98 | + | |
| 96 | 99 | intno = pic_read_irq(isa_pic); |
| 97 | 100 | return intno; |
| 98 | 101 | } |
| ... | ... | @@ -100,10 +103,8 @@ int cpu_get_pic_interrupt(CPUState *env) |
| 100 | 103 | static void pic_irq_request(void *opaque, int irq, int level) |
| 101 | 104 | { |
| 102 | 105 | CPUState *env = opaque; |
| 103 | - if (level) | |
| 106 | + if (level && apic_accept_pic_intr(env)) | |
| 104 | 107 | cpu_interrupt(env, CPU_INTERRUPT_HARD); |
| 105 | - else | |
| 106 | - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); | |
| 107 | 108 | } |
| 108 | 109 | |
| 109 | 110 | /* PC cmos mappings */ | ... | ... |
vl.h
| ... | ... | @@ -1139,6 +1139,7 @@ void irq_info(void); |
| 1139 | 1139 | typedef struct IOAPICState IOAPICState; |
| 1140 | 1140 | |
| 1141 | 1141 | int apic_init(CPUState *env); |
| 1142 | +int apic_accept_pic_intr(CPUState *env); | |
| 1142 | 1143 | int apic_get_interrupt(CPUState *env); |
| 1143 | 1144 | IOAPICState *ioapic_init(void); |
| 1144 | 1145 | void ioapic_set_irq(void *opaque, int vector, int level); | ... | ... |