Also, provide a kvm_apic that does not depend highly on common code. Signed-off-by: Glauber Costa <glommer@xxxxxxxxxx> --- hw/apic.c | 241 ++++++++++++++++++++++++++++++++++---------------------- hw/pc.c | 7 ++- hw/pc.h | 1 + qemu-kvm-x86.c | 5 +- 4 files changed, 157 insertions(+), 97 deletions(-) diff --git a/hw/apic.c b/hw/apic.c index 39e1675..e3b606b 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -857,103 +857,11 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) } } -#ifdef KVM_CAP_IRQCHIP - -static inline uint32_t kapic_reg(struct kvm_lapic_state *kapic, int reg_id) -{ - return *((uint32_t *) (kapic->regs + (reg_id << 4))); -} - -static inline void kapic_set_reg(struct kvm_lapic_state *kapic, - int reg_id, uint32_t val) -{ - *((uint32_t *) (kapic->regs + (reg_id << 4))) = val; -} - -static void kvm_kernel_lapic_save_to_user(APICState *s) -{ - struct kvm_lapic_state apic; - struct kvm_lapic_state *kapic = &apic; - int i, v; - - kvm_get_lapic(kvm_context, s->cpu_env->cpu_index, kapic); - - s->id = kapic_reg(kapic, 0x2) >> 24; - s->tpr = kapic_reg(kapic, 0x8); - s->arb_id = kapic_reg(kapic, 0x9); - s->log_dest = kapic_reg(kapic, 0xd) >> 24; - s->dest_mode = kapic_reg(kapic, 0xe) >> 28; - s->spurious_vec = kapic_reg(kapic, 0xf); - for (i = 0; i < 8; i++) { - s->isr[i] = kapic_reg(kapic, 0x10 + i); - s->tmr[i] = kapic_reg(kapic, 0x18 + i); - s->irr[i] = kapic_reg(kapic, 0x20 + i); - } - s->esr = kapic_reg(kapic, 0x28); - s->icr[0] = kapic_reg(kapic, 0x30); - s->icr[1] = kapic_reg(kapic, 0x31); - for (i = 0; i < APIC_LVT_NB; i++) - s->lvt[i] = kapic_reg(kapic, 0x32 + i); - s->initial_count = kapic_reg(kapic, 0x38); - s->divide_conf = kapic_reg(kapic, 0x3e); - - v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4); - s->count_shift = (v + 1) & 7; - - s->initial_count_load_time = qemu_get_clock(vm_clock); - apic_timer_update(s, s->initial_count_load_time); -} - -static void kvm_kernel_lapic_load_from_user(APICState *s) -{ - struct kvm_lapic_state apic; - struct kvm_lapic_state *klapic = &apic; - int i; - - memset(klapic, 0, sizeof apic); - kapic_set_reg(klapic, 0x2, s->id << 24); - kapic_set_reg(klapic, 0x8, s->tpr); - kapic_set_reg(klapic, 0xd, s->log_dest << 24); - kapic_set_reg(klapic, 0xe, s->dest_mode << 28 | 0x0fffffff); - kapic_set_reg(klapic, 0xf, s->spurious_vec); - for (i = 0; i < 8; i++) { - kapic_set_reg(klapic, 0x10 + i, s->isr[i]); - kapic_set_reg(klapic, 0x18 + i, s->tmr[i]); - kapic_set_reg(klapic, 0x20 + i, s->irr[i]); - } - kapic_set_reg(klapic, 0x28, s->esr); - kapic_set_reg(klapic, 0x30, s->icr[0]); - kapic_set_reg(klapic, 0x31, s->icr[1]); - for (i = 0; i < APIC_LVT_NB; i++) - kapic_set_reg(klapic, 0x32 + i, s->lvt[i]); - kapic_set_reg(klapic, 0x38, s->initial_count); - kapic_set_reg(klapic, 0x3e, s->divide_conf); - - kvm_set_lapic(kvm_context, s->cpu_env->cpu_index, klapic); -} - -#endif - -void qemu_kvm_load_lapic(CPUState *env) -{ -#ifdef KVM_CAP_IRQCHIP - if (kvm_enabled() && kvm_vcpu_inited(env) && qemu_kvm_irqchip_in_kernel()) { - kvm_kernel_lapic_load_from_user(env->apic_state); - } -#endif -} - static void apic_save(QEMUFile *f, void *opaque) { APICState *s = opaque; int i; -#ifdef KVM_CAP_IRQCHIP - if (kvm_enabled() && qemu_kvm_irqchip_in_kernel()) { - kvm_kernel_lapic_save_to_user(s); - } -#endif - qemu_put_be32s(f, &s->apicbase); qemu_put_8s(f, &s->id); qemu_put_8s(f, &s->arb_id); @@ -1017,8 +925,6 @@ static int apic_load(QEMUFile *f, void *opaque, int version_id) if (version_id >= 2) qemu_get_timer(f, s->timer); - qemu_kvm_load_lapic(s->cpu_env); - return 0; } @@ -1039,7 +945,6 @@ static void apic_reset(void *opaque) */ s->lvt[APIC_LVT_LINT0] = 0x700; } - qemu_kvm_load_lapic(s->cpu_env); } static CPUReadMemoryFunc *apic_mem_read[3] = { @@ -1086,3 +991,149 @@ int apic_init(CPUState *env) return 0; } +#ifdef KVM_CAP_IRQCHIP + +static inline uint32_t kapic_reg(struct kvm_lapic_state *kapic, int reg_id) +{ + return *((uint32_t *) (kapic->regs + (reg_id << 4))); +} + +static inline void kapic_set_reg(struct kvm_lapic_state *kapic, + int reg_id, uint32_t val) +{ + *((uint32_t *) (kapic->regs + (reg_id << 4))) = val; +} + +static void kvm_kernel_lapic_save_to_user(APICState *s) +{ + struct kvm_lapic_state apic; + struct kvm_lapic_state *kapic = &apic; + int i, v; + + kvm_get_lapic(kvm_context, s->cpu_env->cpu_index, kapic); + + s->id = kapic_reg(kapic, 0x2) >> 24; + s->tpr = kapic_reg(kapic, 0x8); + s->arb_id = kapic_reg(kapic, 0x9); + s->log_dest = kapic_reg(kapic, 0xd) >> 24; + s->dest_mode = kapic_reg(kapic, 0xe) >> 28; + s->spurious_vec = kapic_reg(kapic, 0xf); + for (i = 0; i < 8; i++) { + s->isr[i] = kapic_reg(kapic, 0x10 + i); + s->tmr[i] = kapic_reg(kapic, 0x18 + i); + s->irr[i] = kapic_reg(kapic, 0x20 + i); + } + s->esr = kapic_reg(kapic, 0x28); + s->icr[0] = kapic_reg(kapic, 0x30); + s->icr[1] = kapic_reg(kapic, 0x31); + for (i = 0; i < APIC_LVT_NB; i++) + s->lvt[i] = kapic_reg(kapic, 0x32 + i); + s->initial_count = kapic_reg(kapic, 0x38); + s->divide_conf = kapic_reg(kapic, 0x3e); + + v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4); + s->count_shift = (v + 1) & 7; + + s->initial_count_load_time = qemu_get_clock(vm_clock); + apic_timer_update(s, s->initial_count_load_time); +} + +static void kvm_kernel_lapic_load_from_user(APICState *s) +{ + struct kvm_lapic_state apic; + struct kvm_lapic_state *klapic = &apic; + int i; + + memset(klapic, 0, sizeof apic); + kapic_set_reg(klapic, 0x2, s->id << 24); + kapic_set_reg(klapic, 0x8, s->tpr); + kapic_set_reg(klapic, 0xd, s->log_dest << 24); + kapic_set_reg(klapic, 0xe, s->dest_mode << 28 | 0x0fffffff); + kapic_set_reg(klapic, 0xf, s->spurious_vec); + for (i = 0; i < 8; i++) { + kapic_set_reg(klapic, 0x10 + i, s->isr[i]); + kapic_set_reg(klapic, 0x18 + i, s->tmr[i]); + kapic_set_reg(klapic, 0x20 + i, s->irr[i]); + } + kapic_set_reg(klapic, 0x28, s->esr); + kapic_set_reg(klapic, 0x30, s->icr[0]); + kapic_set_reg(klapic, 0x31, s->icr[1]); + for (i = 0; i < APIC_LVT_NB; i++) + kapic_set_reg(klapic, 0x32 + i, s->lvt[i]); + kapic_set_reg(klapic, 0x38, s->initial_count); + kapic_set_reg(klapic, 0x3e, s->divide_conf); + + kvm_set_lapic(kvm_context, s->cpu_env->cpu_index, klapic); +} + +#endif + +static void kvm_apic_save(QEMUFile *f, void *opaque) +{ + APICState *s = opaque; + + kvm_kernel_lapic_save_to_user(s); + apic_save(f, opaque); +} + +static int kvm_apic_load(QEMUFile *f, void *opaque, int version_id) +{ + APICState *s = opaque; + int r = apic_load(f, opaque, version_id); + + if (r == 0) + qemu_kvm_load_lapic(s->cpu_env); + return r; +} + + +void qemu_kvm_load_lapic(CPUState *env) +{ + if (kvm_vcpu_inited(env)) { + kvm_kernel_lapic_load_from_user(env->apic_state); + } +} + +static void kvm_apic_reset(void *opaque) +{ + APICState *s = opaque; + + s->apicbase = 0xfee00000 | + (s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE; + + apic_init_ipi_state(s); + + if (s->id == 0) { + /* + * LINT0 delivery mode on CPU #0 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; + } + + qemu_kvm_load_lapic(s->cpu_env); +} + +int kvm_apic_init(CPUState *env) +{ + APICState *s; + + if (last_apic_id >= MAX_APICS) + return -1; + s = qemu_mallocz(sizeof(APICState)); + env->apic_state = s; + s->id = last_apic_id++; + env->cpuid_apic_id = s->id; + s->cpu_env = env; + + kvm_apic_reset(s); + + s->timer = qemu_new_timer(vm_clock, apic_timer, s); + + register_savevm("apic", s->id, 2, kvm_apic_save, kvm_apic_load, s); + qemu_register_reset(kvm_apic_reset, 0, s); + + local_apics[s->id] = s; + return 0; +} diff --git a/hw/pc.c b/hw/pc.c index 66f4635..a99ab07 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -842,7 +842,12 @@ CPUState *pc_new_cpu(int cpu, const char *cpu_model, int pci_enabled) } qemu_register_reset(main_cpu_reset, 0, env); if (pci_enabled) { - apic_init(env); +#ifdef KVM_CAP_IRQCHIP + if (kvm_enabled() && qemu_kvm_irqchip_in_kernel()) { + kvm_apic_init(env); + } else +#endif + apic_init(env); } /* kvm needs this to run after the apic is initialized. Otherwise, diff --git a/hw/pc.h b/hw/pc.h index 3af22f2..ab847b9 100644 --- a/hw/pc.h +++ b/hw/pc.h @@ -48,6 +48,7 @@ void apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t vector_num, uint8_t polarity, uint8_t trigger_mode); int apic_init(CPUState *env); +int kvm_apic_init(CPUState *env); int apic_accept_pic_intr(CPUState *env); void apic_deliver_pic_intr(CPUState *env, int level); int apic_get_interrupt(CPUState *env); diff --git a/qemu-kvm-x86.c b/qemu-kvm-x86.c index 98aa530..925d70e 100644 --- a/qemu-kvm-x86.c +++ b/qemu-kvm-x86.c @@ -527,7 +527,10 @@ int kvm_arch_qemu_init_env(CPUState *cenv) CPUState copy; uint32_t i, j, limit; - qemu_kvm_load_lapic(cenv); +#ifdef KVM_CAP_IRQCHIP + if (qemu_kvm_irqchip_in_kernel()) + qemu_kvm_load_lapic(cenv); +#endif copy = *cenv; -- 1.5.6.6 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html