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
This commit is contained in:
		
							parent
							
								
									e2eb9d3e91
								
							
						
					
					
						commit
						a5b38b5171
					
				
							
								
								
									
										55
									
								
								hw/apic.c
									
									
									
									
									
								
							
							
						
						
									
										55
									
								
								hw/apic.c
									
									
									
									
									
								
							@ -166,6 +166,37 @@ static inline void reset_bit(uint32_t *tab, int index)
 | 
				
			|||||||
    tab[i] &= ~mask;
 | 
					    tab[i] &= ~mask;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void apic_local_deliver(CPUState *env, int vector)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    APICState *s = env->apic_state;
 | 
				
			||||||
 | 
					    uint32_t lvt = s->lvt[vector];
 | 
				
			||||||
 | 
					    int trigger_mode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (lvt & APIC_LVT_MASKED)
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch ((lvt >> 8) & 7) {
 | 
				
			||||||
 | 
					    case APIC_DM_SMI:
 | 
				
			||||||
 | 
					        cpu_interrupt(env, CPU_INTERRUPT_SMI);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case APIC_DM_NMI:
 | 
				
			||||||
 | 
					        cpu_interrupt(env, CPU_INTERRUPT_NMI);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case APIC_DM_EXTINT:
 | 
				
			||||||
 | 
					        cpu_interrupt(env, CPU_INTERRUPT_HARD);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case APIC_DM_FIXED:
 | 
				
			||||||
 | 
					        trigger_mode = APIC_TRIGGER_EDGE;
 | 
				
			||||||
 | 
					        if ((vector == APIC_LVT_LINT0 || vector == APIC_LVT_LINT1) &&
 | 
				
			||||||
 | 
					            (lvt & APIC_LVT_LEVEL_TRIGGER))
 | 
				
			||||||
 | 
					            trigger_mode = APIC_TRIGGER_LEVEL;
 | 
				
			||||||
 | 
					        apic_set_irq(s, lvt & 0xff, trigger_mode);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define foreach_apic(apic, deliver_bitmask, code) \
 | 
					#define foreach_apic(apic, deliver_bitmask, code) \
 | 
				
			||||||
{\
 | 
					{\
 | 
				
			||||||
    int __i, __j, __mask;\
 | 
					    int __i, __j, __mask;\
 | 
				
			||||||
@ -502,10 +533,8 @@ int apic_accept_pic_intr(CPUState *env)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    lvt0 = s->lvt[APIC_LVT_LINT0];
 | 
					    lvt0 = s->lvt[APIC_LVT_LINT0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (s->id == 0 &&
 | 
					    if ((s->apicbase & MSR_IA32_APICBASE_ENABLE) == 0 ||
 | 
				
			||||||
        ((s->apicbase & MSR_IA32_APICBASE_ENABLE) == 0 ||
 | 
					        (lvt0 & APIC_LVT_MASKED) == 0)
 | 
				
			||||||
         ((lvt0 & APIC_LVT_MASKED) == 0 &&
 | 
					 | 
				
			||||||
          ((lvt0 >> 8) & 0x7) == APIC_DM_EXTINT)))
 | 
					 | 
				
			||||||
        return 1;
 | 
					        return 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
@ -556,9 +585,7 @@ static void apic_timer(void *opaque)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    APICState *s = opaque;
 | 
					    APICState *s = opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
 | 
					    apic_local_deliver(s->cpu_env, APIC_LVT_TIMER);
 | 
				
			||||||
        apic_set_irq(s, s->lvt[APIC_LVT_TIMER] & 0xff, APIC_TRIGGER_EDGE);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    apic_timer_update(s, s->next_time);
 | 
					    apic_timer_update(s, s->next_time);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -821,13 +848,15 @@ static void apic_reset(void *opaque)
 | 
				
			|||||||
    APICState *s = opaque;
 | 
					    APICState *s = opaque;
 | 
				
			||||||
    apic_init_ipi(s);
 | 
					    apic_init_ipi(s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (s->id == 0) {
 | 
				
			||||||
        /*
 | 
					        /*
 | 
				
			||||||
     * LINT0 delivery mode is set to ExtInt at initialization time
 | 
					         * LINT0 delivery mode on CPU #0 is set to ExtInt at initialization
 | 
				
			||||||
     * typically by BIOS, so PIC interrupt can be delivered to the
 | 
					         * time typically by BIOS, so PIC interrupt can be delivered to the
 | 
				
			||||||
         * processor when local APIC is enabled.
 | 
					         * processor when local APIC is enabled.
 | 
				
			||||||
         */
 | 
					         */
 | 
				
			||||||
        s->lvt[APIC_LVT_LINT0] = 0x700;
 | 
					        s->lvt[APIC_LVT_LINT0] = 0x700;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static CPUReadMemoryFunc *apic_mem_read[3] = {
 | 
					static CPUReadMemoryFunc *apic_mem_read[3] = {
 | 
				
			||||||
    apic_mem_readb,
 | 
					    apic_mem_readb,
 | 
				
			||||||
@ -851,19 +880,13 @@ int apic_init(CPUState *env)
 | 
				
			|||||||
    if (!s)
 | 
					    if (!s)
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    env->apic_state = s;
 | 
					    env->apic_state = s;
 | 
				
			||||||
    apic_init_ipi(s);
 | 
					 | 
				
			||||||
    s->id = last_apic_id++;
 | 
					    s->id = last_apic_id++;
 | 
				
			||||||
    env->cpuid_apic_id = s->id;
 | 
					    env->cpuid_apic_id = s->id;
 | 
				
			||||||
    s->cpu_env = env;
 | 
					    s->cpu_env = env;
 | 
				
			||||||
    s->apicbase = 0xfee00000 |
 | 
					    s->apicbase = 0xfee00000 |
 | 
				
			||||||
        (s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE;
 | 
					        (s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*
 | 
					    apic_reset(s);
 | 
				
			||||||
     * LINT0 delivery mode is set to ExtInt at initialization time
 | 
					 | 
				
			||||||
     * typically by BIOS, so PIC interrupt can be delivered to the
 | 
					 | 
				
			||||||
     * processor when local APIC is enabled.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    s->lvt[APIC_LVT_LINT0] = 0x700;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* XXX: mapping more APICs at the same memory location */
 | 
					    /* XXX: mapping more APICs at the same memory location */
 | 
				
			||||||
    if (apic_io_memory == 0) {
 | 
					    if (apic_io_memory == 0) {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										15
									
								
								hw/pc.c
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								hw/pc.c
									
									
									
									
									
								
							@ -113,9 +113,16 @@ int cpu_get_pic_interrupt(CPUState *env)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void pic_irq_request(void *opaque, int irq, int level)
 | 
					static void pic_irq_request(void *opaque, int irq, int level)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    CPUState *env = opaque;
 | 
					    CPUState *env = first_cpu;
 | 
				
			||||||
    if (level && apic_accept_pic_intr(env))
 | 
					
 | 
				
			||||||
        cpu_interrupt(env, CPU_INTERRUPT_HARD);
 | 
					    if (!level)
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (env) {
 | 
				
			||||||
 | 
					        if (apic_accept_pic_intr(env))
 | 
				
			||||||
 | 
					            apic_local_deliver(env, APIC_LINT0);
 | 
				
			||||||
 | 
					        env = env->next_cpu;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* PC cmos mappings */
 | 
					/* PC cmos mappings */
 | 
				
			||||||
@ -845,7 +852,7 @@ static void pc_init1(int ram_size, int vga_ram_size,
 | 
				
			|||||||
    if (linux_boot)
 | 
					    if (linux_boot)
 | 
				
			||||||
	load_linux(kernel_filename, initrd_filename, kernel_cmdline);
 | 
						load_linux(kernel_filename, initrd_filename, kernel_cmdline);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cpu_irq = qemu_allocate_irqs(pic_irq_request, first_cpu, 1);
 | 
					    cpu_irq = qemu_allocate_irqs(pic_irq_request, NULL, 1);
 | 
				
			||||||
    i8259 = i8259_init(cpu_irq[0]);
 | 
					    i8259 = i8259_init(cpu_irq[0]);
 | 
				
			||||||
    ferr_irq = i8259[13];
 | 
					    ferr_irq = i8259[13];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										3
									
								
								hw/pc.h
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								hw/pc.h
									
									
									
									
									
								
							@ -39,8 +39,11 @@ void irq_info(void);
 | 
				
			|||||||
/* APIC */
 | 
					/* APIC */
 | 
				
			||||||
typedef struct IOAPICState IOAPICState;
 | 
					typedef struct IOAPICState IOAPICState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define APIC_LINT0	3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int apic_init(CPUState *env);
 | 
					int apic_init(CPUState *env);
 | 
				
			||||||
int apic_accept_pic_intr(CPUState *env);
 | 
					int apic_accept_pic_intr(CPUState *env);
 | 
				
			||||||
 | 
					void apic_local_deliver(CPUState *env, int vector);
 | 
				
			||||||
int apic_get_interrupt(CPUState *env);
 | 
					int apic_get_interrupt(CPUState *env);
 | 
				
			||||||
IOAPICState *ioapic_init(void);
 | 
					IOAPICState *ioapic_init(void);
 | 
				
			||||||
void ioapic_set_irq(void *opaque, int vector, int level);
 | 
					void ioapic_set_irq(void *opaque, int vector, int level);
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user