X-Git-Url: https://vcs.maemo.org/git/?a=blobdiff_plain;f=hw%2Fapic.c;h=3a442bf8264b4f60b44003d1ef5979c6271097a1;hb=cd346349b45ef056f138a184f660b8c34c3213cc;hp=65f96a5b76511092fee4244893e2cd8b72ced3bd;hpb=d3e9db933f416c9f1c04df4834d36e2315952e42;p=qemu diff --git a/hw/apic.c b/hw/apic.c index 65f96a5..3a442bf 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -1,6 +1,6 @@ /* * APIC support - * + * * Copyright (c) 2004-2005 Fabrice Bellard * * This library is free software; you can redistribute it and/or @@ -182,7 +182,7 @@ static inline void reset_bit(uint32_t *tab, int index) }\ } -static void apic_bus_deliver(const uint32_t *deliver_bitmask, +static void apic_bus_deliver(const uint32_t *deliver_bitmask, uint8_t delivery_mode, uint8_t vector_num, uint8_t polarity, uint8_t trigger_mode) @@ -219,10 +219,10 @@ static void apic_bus_deliver(const uint32_t *deliver_bitmask, case APIC_DM_INIT: /* normal INIT IPI sent to processors */ - foreach_apic(apic_iter, deliver_bitmask, + foreach_apic(apic_iter, deliver_bitmask, apic_init_ipi(apic_iter) ); return; - + case APIC_DM_EXTINT: /* handled in I/O APIC code */ break; @@ -231,7 +231,7 @@ static void apic_bus_deliver(const uint32_t *deliver_bitmask, return; } - foreach_apic(apic_iter, deliver_bitmask, + foreach_apic(apic_iter, deliver_bitmask, apic_set_irq(apic_iter, vector_num, trigger_mode) ); } @@ -239,9 +239,9 @@ void cpu_set_apic_base(CPUState *env, uint64_t val) { APICState *s = env->apic_state; #ifdef DEBUG_APIC - printf("cpu_set_apic_base: %016llx\n", val); + printf("cpu_set_apic_base: %016" PRIx64 "\n", val); #endif - s->apicbase = (val & 0xfffff000) | + s->apicbase = (val & 0xfffff000) | (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE)); /* if disabled, cannot be enabled again */ if (!(val & MSR_IA32_APICBASE_ENABLE)) { @@ -255,7 +255,7 @@ uint64_t cpu_get_apic_base(CPUState *env) { APICState *s = env->apic_state; #ifdef DEBUG_APIC - printf("cpu_get_apic_base: %016llx\n", (uint64_t)s->apicbase); + printf("cpu_get_apic_base: %016" PRIx64 "\n", (uint64_t)s->apicbase); #endif return s->apicbase; } @@ -382,8 +382,6 @@ static void apic_init_ipi(APICState *s) { int i; - for(i = 0; i < APIC_LVT_NB; i++) - s->lvt[i] = 1 << 16; /* mask LVT */ s->tpr = 0; s->spurious_vec = 0xff; s->log_dest = 0; @@ -391,7 +389,8 @@ static void apic_init_ipi(APICState *s) memset(s->isr, 0, sizeof(s->isr)); memset(s->tmr, 0, sizeof(s->tmr)); memset(s->irr, 0, sizeof(s->irr)); - memset(s->lvt, 0, sizeof(s->lvt)); + for(i = 0; i < APIC_LVT_NB; i++) + s->lvt[i] = 1 << 16; /* mask LVT */ s->esr = 0; memset(s->icr, 0, sizeof(s->icr)); s->divide_conf = 0; @@ -408,7 +407,7 @@ static void apic_startup(APICState *s, int vector_num) if (!(env->hflags & HF_HALTED_MASK)) return; env->eip = 0; - cpu_x86_load_seg_cache(env, R_CS, vector_num << 8, vector_num << 12, + cpu_x86_load_seg_cache(env, R_CS, vector_num << 8, vector_num << 12, 0xffff, 0); env->hflags &= ~HF_HALTED_MASK; } @@ -444,7 +443,7 @@ static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode, int trig_mode = (s->icr[0] >> 15) & 1; int level = (s->icr[0] >> 14) & 1; if (level == 0 && trig_mode == 1) { - foreach_apic(apic_iter, deliver_bitmask, + foreach_apic(apic_iter, deliver_bitmask, apic_iter->arb_id = apic_iter->id ); return; } @@ -452,7 +451,7 @@ static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode, break; case APIC_DM_SIPI: - foreach_apic(apic_iter, deliver_bitmask, + foreach_apic(apic_iter, deliver_bitmask, apic_startup(apic_iter, vector_num) ); return; } @@ -472,24 +471,43 @@ int apic_get_interrupt(CPUState *env) return -1; if (!(s->spurious_vec & APIC_SV_ENABLE)) return -1; - + /* XXX: spurious IRQ handling */ intno = get_highest_priority_int(s->irr); if (intno < 0) return -1; - reset_bit(s->irr, intno); if (s->tpr && intno <= s->tpr) return s->spurious_vec & 0xff; + reset_bit(s->irr, intno); set_bit(s->isr, intno); apic_update_irq(s); return intno; } +int apic_accept_pic_intr(CPUState *env) +{ + APICState *s = env->apic_state; + uint32_t lvt0; + + if (!s) + return -1; + + lvt0 = s->lvt[APIC_LVT_LINT0]; + + if (s->id == 0 && + ((s->apicbase & MSR_IA32_APICBASE_ENABLE) == 0 || + ((lvt0 & APIC_LVT_MASKED) == 0 && + ((lvt0 >> 8) & 0x7) == APIC_DM_EXTINT))) + return 1; + + return 0; +} + static uint32_t apic_get_current_count(APICState *s) { int64_t d; uint32_t val; - d = (qemu_get_clock(vm_clock) - s->initial_count_load_time) >> + d = (qemu_get_clock(vm_clock) - s->initial_count_load_time) >> s->count_shift; if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) { /* periodic */ @@ -506,9 +524,9 @@ static uint32_t apic_get_current_count(APICState *s) static void apic_timer_update(APICState *s, int64_t current_time) { int64_t next_time, d; - + if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) { - d = (current_time - s->initial_count_load_time) >> + d = (current_time - s->initial_count_load_time) >> s->count_shift; if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) { d = ((d / ((uint64_t)s->initial_count + 1)) + 1) * ((uint64_t)s->initial_count + 1); @@ -745,6 +763,8 @@ static void apic_save(QEMUFile *f, void *opaque) qemu_put_be32s(f, &s->initial_count); qemu_put_be64s(f, &s->initial_count_load_time); qemu_put_be64s(f, &s->next_time); + + qemu_put_timer(f, s->timer); } static int apic_load(QEMUFile *f, void *opaque, int version_id) @@ -752,7 +772,7 @@ static int apic_load(QEMUFile *f, void *opaque, int version_id) APICState *s = opaque; int i; - if (version_id != 1) + if (version_id > 2) return -EINVAL; /* XXX: what if the base changes? (registered memory regions) */ @@ -779,6 +799,9 @@ static int apic_load(QEMUFile *f, void *opaque, int version_id) qemu_get_be32s(f, &s->initial_count); qemu_get_be64s(f, &s->initial_count_load_time); qemu_get_be64s(f, &s->next_time); + + if (version_id >= 2) + qemu_get_timer(f, s->timer); return 0; } @@ -786,6 +809,13 @@ static void apic_reset(void *opaque) { APICState *s = opaque; apic_init_ipi(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; } static CPUReadMemoryFunc *apic_mem_read[3] = { @@ -812,24 +842,32 @@ int apic_init(CPUState *env) env->apic_state = s; apic_init_ipi(s); s->id = last_apic_id++; + env->cpuid_apic_id = s->id; s->cpu_env = env; - s->apicbase = 0xfee00000 | + s->apicbase = 0xfee00000 | (s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE; + /* + * 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 */ if (apic_io_memory == 0) { /* NOTE: the APIC is directly connected to the CPU - it is not on the global memory bus. */ - apic_io_memory = cpu_register_io_memory(0, apic_mem_read, + apic_io_memory = cpu_register_io_memory(0, apic_mem_read, apic_mem_write, NULL); cpu_register_physical_memory(s->apicbase & ~0xfff, 0x1000, apic_io_memory); } s->timer = qemu_new_timer(vm_clock, apic_timer, s); - register_savevm("apic", 0, 1, apic_save, apic_load, s); + register_savevm("apic", s->id, 2, apic_save, apic_load, s); qemu_register_reset(apic_reset, s); - + local_apics[s->id] = s; return 0; } @@ -863,9 +901,9 @@ static void ioapic_service(IOAPICState *s) vector = pic_read_irq(isa_pic); else vector = entry & 0xff; - + apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode); - apic_bus_deliver(deliver_bitmask, delivery_mode, + apic_bus_deliver(deliver_bitmask, delivery_mode, vector, polarity, trig_mode); } } @@ -1031,12 +1069,12 @@ IOAPICState *ioapic_init(void) ioapic_reset(s); s->id = last_apic_id++; - io_memory = cpu_register_io_memory(0, ioapic_mem_read, + io_memory = cpu_register_io_memory(0, ioapic_mem_read, ioapic_mem_write, s); cpu_register_physical_memory(0xfec00000, 0x1000, io_memory); register_savevm("ioapic", 0, 1, ioapic_save, ioapic_load, s); qemu_register_reset(ioapic_reset, s); - + return s; }