From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1MsNZB-0008VA-Vv for qemu-devel@nongnu.org; Mon, 28 Sep 2009 17:15:30 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1MsNZ6-0008Te-PP for qemu-devel@nongnu.org; Mon, 28 Sep 2009 17:15:29 -0400 Received: from [199.232.76.173] (port=49503 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1MsNZ6-0008Tb-Kz for qemu-devel@nongnu.org; Mon, 28 Sep 2009 17:15:24 -0400 Received: from mx1.redhat.com ([209.132.183.28]:52915) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1MsNZ6-0001wf-1D for qemu-devel@nongnu.org; Mon, 28 Sep 2009 17:15:24 -0400 From: Glauber Costa Date: Mon, 28 Sep 2009 18:15:13 -0300 Message-Id: <1254172517-28216-3-git-send-email-glommer@redhat.com> In-Reply-To: <1254172517-28216-2-git-send-email-glommer@redhat.com> References: <1254172517-28216-1-git-send-email-glommer@redhat.com> <1254172517-28216-2-git-send-email-glommer@redhat.com> Subject: [Qemu-devel] [PATCH 2/6] provide in-kernel apic List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: aliguori@us.ibm.com This patch provides kvm with an in-kernel apic. We are currently not enabling it. The code is heavily based on what's in qemu-kvm.git. Signed-off-by: Glauber Costa --- hw/apic.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++++++-- kvm.h | 5 ++- target-i386/kvm.c | 18 +++++++ 3 files changed, 154 insertions(+), 5 deletions(-) diff --git a/hw/apic.c b/hw/apic.c index c89008e..b3f5179 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -299,7 +299,11 @@ void cpu_set_apic_base(CPUState *env, uint64_t val) #endif if (!s) return; - s->apicbase = (val & 0xfffff000) | + + if (kvm_enabled() && kvm_irqchip_in_kernel()) + s->apicbase = val; + else + 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)) { @@ -497,6 +501,13 @@ void apic_init_reset(CPUState *env) s->wait_for_sipi = 1; env->halted = !(s->apicbase & MSR_IA32_APICBASE_BSP); + +#ifdef KVM_CAP_MP_STATE + if (kvm_enabled() && kvm_irqchip_in_kernel()) + env->mp_state + = env->halted ? KVM_MP_STATE_UNINITIALIZED : KVM_MP_STATE_RUNNABLE; +#endif + } static void apic_startup(APICState *s, int vector_num) @@ -903,12 +914,121 @@ static int apic_load_old(QEMUFile *f, void *opaque, int version_id) return 0; } +#if defined(KVM_CAP_IRQCHIP) && defined(TARGET_I386) +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_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(s->cpu_env, klapic); +} + +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(s->cpu_env, 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); +} +#endif + +static void qemu_kvm_load_lapic(CPUState *env) +{ +#if defined(KVM_CAP_IRQCHIP) && defined(TARGET_I386) + if (kvm_enabled() && kvm_irqchip_in_kernel()) { + kvm_kernel_lapic_load_from_user(env->apic_state); + } +#endif +} + +static void apic_pre_save(const void *opaque) +{ +#if defined(KVM_CAP_IRQCHIP) && defined(TARGET_I386) + APICState *s = (void *)opaque; + + if (kvm_enabled() && kvm_irqchip_in_kernel()) { + kvm_kernel_lapic_save_to_user(s); + } +#endif +} + +static int apic_post_load(void *opaque) +{ +#if defined(KVM_CAP_IRQCHIP) && defined(TARGET_I386) + APICState *s = opaque; + + if (kvm_enabled() && kvm_irqchip_in_kernel()) { + kvm_kernel_lapic_load_from_user(s); + } +#endif + return 0; +} + static const VMStateDescription vmstate_apic = { .name = "apic", .version_id = 3, .minimum_version_id = 3, .minimum_version_id_old = 1, .load_state_old = apic_load_old, + .pre_save = apic_pre_save, + .post_load = apic_post_load, .fields = (VMStateField []) { VMSTATE_UINT32(apicbase, APICState), VMSTATE_UINT8(id, APICState), @@ -933,9 +1053,8 @@ static const VMStateDescription vmstate_apic = { } }; -static void apic_reset(void *opaque) +static void apic_do_reset(APICState *s) { - APICState *s = opaque; int bsp; cpu_synchronize_state(s->cpu_env); @@ -957,6 +1076,15 @@ static void apic_reset(void *opaque) } } +static void apic_reset(void *opaque) +{ + APICState *s = opaque; + + apic_do_reset(s); + + qemu_kvm_load_lapic(s->cpu_env); +} + static CPUReadMemoryFunc * const apic_mem_read[3] = { apic_mem_readb, apic_mem_readw, @@ -981,7 +1109,7 @@ int apic_init(CPUState *env) s->id = env->cpuid_apic_id; s->cpu_env = env; - apic_reset(s); + apic_do_reset(s); msix_supported = 1; /* XXX: mapping more APICs at the same memory location */ diff --git a/kvm.h b/kvm.h index 8d4afa0..ae5223b 100644 --- a/kvm.h +++ b/kvm.h @@ -66,7 +66,7 @@ int kvm_irqchip_in_kernel(void); int kvm_set_irqchip(struct kvm_irqchip *chip); int kvm_get_irqchip(struct kvm_irqchip *chip); - + /* internal API */ struct KVMState; @@ -97,6 +97,9 @@ int kvm_arch_init(KVMState *s, int smp_cpus); int kvm_arch_init_vcpu(CPUState *env); +int kvm_set_lapic(CPUState *env, struct kvm_lapic_state *s); +int kvm_get_lapic(CPUState *env, struct kvm_lapic_state *s); + struct kvm_guest_debug; struct kvm_debug_exit_arch; diff --git a/target-i386/kvm.c b/target-i386/kvm.c index a0e261c..14c9785 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -959,3 +959,21 @@ void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg) } } #endif /* KVM_CAP_SET_GUEST_DEBUG */ + +#ifdef KVM_CAP_IRQCHIP +int kvm_set_lapic(CPUState *env, struct kvm_lapic_state *s) +{ + if (!kvm_irqchip_in_kernel()) + return 0; + + return kvm_vcpu_ioctl(env, KVM_SET_LAPIC, s); +} + +int kvm_get_lapic(CPUState *env, struct kvm_lapic_state *s) +{ + if (!kvm_irqchip_in_kernel()) + return 0; + + return kvm_vcpu_ioctl(env, KVM_GET_LAPIC, s); +} +#endif -- 1.6.2.5