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 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) {
... ...
... ... @@ -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  
... ...
... ... @@ -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);
... ...