From patchwork Wed Jun 3 21:19:29 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Glauber Costa X-Patchwork-Id: 27740 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n53LJrWF011560 for ; Wed, 3 Jun 2009 21:19:54 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754557AbZFCVTi (ORCPT ); Wed, 3 Jun 2009 17:19:38 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1753587AbZFCVTh (ORCPT ); Wed, 3 Jun 2009 17:19:37 -0400 Received: from mx2.redhat.com ([66.187.237.31]:38134 "EHLO mx2.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754557AbZFCVTb (ORCPT ); Wed, 3 Jun 2009 17:19:31 -0400 Received: from int-mx2.corp.redhat.com (int-mx2.corp.redhat.com [172.16.27.26]) by mx2.redhat.com (8.13.8/8.13.8) with ESMTP id n53LJXPl008282 for ; Wed, 3 Jun 2009 17:19:33 -0400 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx2.corp.redhat.com (8.13.1/8.13.1) with ESMTP id n53LJWvI001490; Wed, 3 Jun 2009 17:19:32 -0400 Received: from localhost.localdomain (virtlab1.virt.bos.redhat.com [10.16.72.21]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id n53LJUTV025663; Wed, 3 Jun 2009 17:19:31 -0400 From: Glauber Costa To: kvm@vger.kernel.org Cc: avi@redhat.com Subject: [PATCH 3/4] provide a kvm-free implementation of apic Date: Wed, 3 Jun 2009 17:19:29 -0400 Message-Id: <1244063970-13913-4-git-send-email-glommer@redhat.com> In-Reply-To: <1244063970-13913-3-git-send-email-glommer@redhat.com> References: <1244063970-13913-1-git-send-email-glommer@redhat.com> <1244063970-13913-2-git-send-email-glommer@redhat.com> <1244063970-13913-3-git-send-email-glommer@redhat.com> X-Scanned-By: MIMEDefang 2.58 on 172.16.27.26 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Also, provide a kvm_apic that does not depend highly on common code. Signed-off-by: Glauber Costa --- 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;