Commit a5b38b5171ea46e13612a3471a7cc735db6d6f72

Authored by aurel32
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,6 +166,37 @@ static inline void reset_bit(uint32_t *tab, int index)
166 tab[i] &= ~mask; 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 #define foreach_apic(apic, deliver_bitmask, code) \ 200 #define foreach_apic(apic, deliver_bitmask, code) \
170 {\ 201 {\
171 int __i, __j, __mask;\ 202 int __i, __j, __mask;\
@@ -502,10 +533,8 @@ int apic_accept_pic_intr(CPUState *env) @@ -502,10 +533,8 @@ int apic_accept_pic_intr(CPUState *env)
502 533
503 lvt0 = s->lvt[APIC_LVT_LINT0]; 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 return 1; 538 return 1;
510 539
511 return 0; 540 return 0;
@@ -556,9 +585,7 @@ static void apic_timer(void *opaque) @@ -556,9 +585,7 @@ static void apic_timer(void *opaque)
556 { 585 {
557 APICState *s = opaque; 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 apic_timer_update(s, s->next_time); 589 apic_timer_update(s, s->next_time);
563 } 590 }
564 591
@@ -821,12 +848,14 @@ static void apic_reset(void *opaque) @@ -821,12 +848,14 @@ static void apic_reset(void *opaque)
821 APICState *s = opaque; 848 APICState *s = opaque;
822 apic_init_ipi(s); 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 static CPUReadMemoryFunc *apic_mem_read[3] = { 861 static CPUReadMemoryFunc *apic_mem_read[3] = {
@@ -851,19 +880,13 @@ int apic_init(CPUState *env) @@ -851,19 +880,13 @@ int apic_init(CPUState *env)
851 if (!s) 880 if (!s)
852 return -1; 881 return -1;
853 env->apic_state = s; 882 env->apic_state = s;
854 - apic_init_ipi(s);  
855 s->id = last_apic_id++; 883 s->id = last_apic_id++;
856 env->cpuid_apic_id = s->id; 884 env->cpuid_apic_id = s->id;
857 s->cpu_env = env; 885 s->cpu_env = env;
858 s->apicbase = 0xfee00000 | 886 s->apicbase = 0xfee00000 |
859 (s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE; 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 /* XXX: mapping more APICs at the same memory location */ 891 /* XXX: mapping more APICs at the same memory location */
869 if (apic_io_memory == 0) { 892 if (apic_io_memory == 0) {
@@ -113,9 +113,16 @@ int cpu_get_pic_interrupt(CPUState *env) @@ -113,9 +113,16 @@ int cpu_get_pic_interrupt(CPUState *env)
113 113
114 static void pic_irq_request(void *opaque, int irq, int level) 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 /* PC cmos mappings */ 128 /* PC cmos mappings */
@@ -845,7 +852,7 @@ static void pc_init1(int ram_size, int vga_ram_size, @@ -845,7 +852,7 @@ static void pc_init1(int ram_size, int vga_ram_size,
845 if (linux_boot) 852 if (linux_boot)
846 load_linux(kernel_filename, initrd_filename, kernel_cmdline); 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 i8259 = i8259_init(cpu_irq[0]); 856 i8259 = i8259_init(cpu_irq[0]);
850 ferr_irq = i8259[13]; 857 ferr_irq = i8259[13];
851 858
@@ -39,8 +39,11 @@ void irq_info(void); @@ -39,8 +39,11 @@ void irq_info(void);
39 /* APIC */ 39 /* APIC */
40 typedef struct IOAPICState IOAPICState; 40 typedef struct IOAPICState IOAPICState;
41 41
  42 +#define APIC_LINT0 3
  43 +
42 int apic_init(CPUState *env); 44 int apic_init(CPUState *env);
43 int apic_accept_pic_intr(CPUState *env); 45 int apic_accept_pic_intr(CPUState *env);
  46 +void apic_local_deliver(CPUState *env, int vector);
44 int apic_get_interrupt(CPUState *env); 47 int apic_get_interrupt(CPUState *env);
45 IOAPICState *ioapic_init(void); 48 IOAPICState *ioapic_init(void);
46 void ioapic_set_irq(void *opaque, int vector, int level); 49 void ioapic_set_irq(void *opaque, int vector, int level);