From mboxrd@z Thu Jan 1 00:00:00 1970 From: Alexander Graf Subject: [PATCH RFC v2 2/2] ARM: KVM: Enable in-kernel timers with user space gic Date: Mon, 14 Nov 2016 15:32:15 +0100 Message-ID: <1479133935-63848-3-git-send-email-agraf@suse.de> References: <1479133935-63848-1-git-send-email-agraf@suse.de> Cc: Peter Maydell , Paolo Bonzini , kvm-devel , qemu-arm To: QEMU Developers Return-path: Received: from mx2.suse.de ([195.135.220.15]:57068 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751971AbcKNOcI (ORCPT ); Mon, 14 Nov 2016 09:32:08 -0500 In-Reply-To: <1479133935-63848-1-git-send-email-agraf@suse.de> Sender: kvm-owner@vger.kernel.org List-ID: When running with KVM enabled, you can choose between emulating the gic in kernel or user space. If the kernel supports in-kernel virtualization of the interrupt controller, it will default to that. If not, if will default to user space emulation. Unfortunately when running in user mode gic emulation, we miss out on timer events which are only available from kernel space. This patch leverages the new kernel/user space pending line synchronization for those timer events. Signed-off-by: Alexander Graf --- rfc1 -> rfc2: - use local variable for ARM_CPU - remove bear trap - move timer warning to gic device --- hw/intc/arm_gic.c | 7 +++++++ include/sysemu/kvm.h | 11 +++++++++++ kvm-all.c | 5 +++++ kvm-stub.c | 5 +++++ target-arm/cpu.h | 3 +++ target-arm/kvm.c | 20 ++++++++++++++++++++ 6 files changed, 51 insertions(+) diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index 521aac3..1f3aacf 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -25,6 +25,7 @@ #include "qom/cpu.h" #include "qemu/log.h" #include "trace.h" +#include "sysemu/kvm.h" //#define DEBUG_GIC @@ -1428,6 +1429,12 @@ static void arm_gic_realize(DeviceState *dev, Error **errp) return; } + if (kvm_enabled() && !kvm_arm_supports_timer()) { + error_setg(errp, "KVM with user space irqchip only works when the " + "host kernel supports KVM_CAP_ARM_TIMER"); + return; + } + /* This creates distributor and main CPU interface (s->cpuiomem[0]) */ gic_init_irqs_and_mmio(s, gic_set_irq, gic_ops); diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index df67cc0..9715fee 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -227,6 +227,17 @@ int kvm_init_vcpu(CPUState *cpu); int kvm_cpu_exec(CPUState *cpu); int kvm_destroy_vcpu(CPUState *cpu); +/** + * kvm_arm_supports_timer + * + * Not all KVM implementations support notifications for the CP15 timers to + * user space. This function indicates whether the current KVM implementation + * does support them. + * + * Returns: true if KVM supports using ARM core timers from user space + */ +bool kvm_arm_supports_timer(void); + #ifdef NEED_CPU_H #include "cpu.h" diff --git a/kvm-all.c b/kvm-all.c index 330219e..8d4696c 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -2194,6 +2194,11 @@ int kvm_has_intx_set_mask(void) return kvm_state->intx_set_mask; } +bool kvm_arm_supports_timer(void) +{ + return kvm_check_extension(kvm_state, KVM_CAP_ARM_TIMER); +} + #ifdef KVM_CAP_SET_GUEST_DEBUG struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *cpu, target_ulong pc) diff --git a/kvm-stub.c b/kvm-stub.c index b1b6b96..a4d408b 100644 --- a/kvm-stub.c +++ b/kvm-stub.c @@ -157,4 +157,9 @@ bool kvm_has_free_slot(MachineState *ms) { return false; } + +bool kvm_arm_supports_timer(void) +{ + return false; +} #endif diff --git a/target-arm/cpu.h b/target-arm/cpu.h index ca5c849..2c379a3 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -659,6 +659,9 @@ struct ARMCPU { ARMELChangeHook *el_change_hook; void *el_change_hook_opaque; + + /* Used to synchronize KVM and QEMU timer levels */ + uint8_t timer_irq_level; }; static inline ARMCPU *arm_env_get_cpu(CPUARMState *env) diff --git a/target-arm/kvm.c b/target-arm/kvm.c index c00b94e..c5f0d37 100644 --- a/target-arm/kvm.c +++ b/target-arm/kvm.c @@ -527,6 +527,26 @@ void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run) { + ARMCPU *cpu; + bool vtimer_high; + + if (kvm_irqchip_in_kernel()) { + /* + * We only need to sync timer states with user-space interrupt + * controllers, so return early and save cycles if we don't. + */ + return MEMTXATTRS_UNSPECIFIED; + } + + cpu = ARM_CPU(cs); + + /* Synchronize our internal vtimer irq line with the kvm one */ + if (run->s.regs.timer_irq_level != cpu->timer_irq_level) { + vtimer_high = run->s.regs.timer_irq_level & KVM_ARM_TIMER_VTIMER; + qemu_set_irq(cpu->gt_timer_outputs[GTIMER_VIRT], vtimer_high ? 1 : 0); + cpu->timer_irq_level = run->s.regs.timer_irq_level; + } + return MEMTXATTRS_UNSPECIFIED; } -- 1.8.5.6 From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:45928) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1c6IIz-0000cU-B9 for qemu-devel@nongnu.org; Mon, 14 Nov 2016 09:32:18 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1c6IIy-0008JE-7m for qemu-devel@nongnu.org; Mon, 14 Nov 2016 09:32:17 -0500 From: Alexander Graf Date: Mon, 14 Nov 2016 15:32:15 +0100 Message-Id: <1479133935-63848-3-git-send-email-agraf@suse.de> In-Reply-To: <1479133935-63848-1-git-send-email-agraf@suse.de> References: <1479133935-63848-1-git-send-email-agraf@suse.de> Subject: [Qemu-devel] [PATCH RFC v2 2/2] ARM: KVM: Enable in-kernel timers with user space gic List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: QEMU Developers Cc: Peter Maydell , Paolo Bonzini , kvm-devel , qemu-arm When running with KVM enabled, you can choose between emulating the gic in kernel or user space. If the kernel supports in-kernel virtualization of the interrupt controller, it will default to that. If not, if will default to user space emulation. Unfortunately when running in user mode gic emulation, we miss out on timer events which are only available from kernel space. This patch leverages the new kernel/user space pending line synchronization for those timer events. Signed-off-by: Alexander Graf --- rfc1 -> rfc2: - use local variable for ARM_CPU - remove bear trap - move timer warning to gic device --- hw/intc/arm_gic.c | 7 +++++++ include/sysemu/kvm.h | 11 +++++++++++ kvm-all.c | 5 +++++ kvm-stub.c | 5 +++++ target-arm/cpu.h | 3 +++ target-arm/kvm.c | 20 ++++++++++++++++++++ 6 files changed, 51 insertions(+) diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index 521aac3..1f3aacf 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -25,6 +25,7 @@ #include "qom/cpu.h" #include "qemu/log.h" #include "trace.h" +#include "sysemu/kvm.h" //#define DEBUG_GIC @@ -1428,6 +1429,12 @@ static void arm_gic_realize(DeviceState *dev, Error **errp) return; } + if (kvm_enabled() && !kvm_arm_supports_timer()) { + error_setg(errp, "KVM with user space irqchip only works when the " + "host kernel supports KVM_CAP_ARM_TIMER"); + return; + } + /* This creates distributor and main CPU interface (s->cpuiomem[0]) */ gic_init_irqs_and_mmio(s, gic_set_irq, gic_ops); diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index df67cc0..9715fee 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -227,6 +227,17 @@ int kvm_init_vcpu(CPUState *cpu); int kvm_cpu_exec(CPUState *cpu); int kvm_destroy_vcpu(CPUState *cpu); +/** + * kvm_arm_supports_timer + * + * Not all KVM implementations support notifications for the CP15 timers to + * user space. This function indicates whether the current KVM implementation + * does support them. + * + * Returns: true if KVM supports using ARM core timers from user space + */ +bool kvm_arm_supports_timer(void); + #ifdef NEED_CPU_H #include "cpu.h" diff --git a/kvm-all.c b/kvm-all.c index 330219e..8d4696c 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -2194,6 +2194,11 @@ int kvm_has_intx_set_mask(void) return kvm_state->intx_set_mask; } +bool kvm_arm_supports_timer(void) +{ + return kvm_check_extension(kvm_state, KVM_CAP_ARM_TIMER); +} + #ifdef KVM_CAP_SET_GUEST_DEBUG struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *cpu, target_ulong pc) diff --git a/kvm-stub.c b/kvm-stub.c index b1b6b96..a4d408b 100644 --- a/kvm-stub.c +++ b/kvm-stub.c @@ -157,4 +157,9 @@ bool kvm_has_free_slot(MachineState *ms) { return false; } + +bool kvm_arm_supports_timer(void) +{ + return false; +} #endif diff --git a/target-arm/cpu.h b/target-arm/cpu.h index ca5c849..2c379a3 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -659,6 +659,9 @@ struct ARMCPU { ARMELChangeHook *el_change_hook; void *el_change_hook_opaque; + + /* Used to synchronize KVM and QEMU timer levels */ + uint8_t timer_irq_level; }; static inline ARMCPU *arm_env_get_cpu(CPUARMState *env) diff --git a/target-arm/kvm.c b/target-arm/kvm.c index c00b94e..c5f0d37 100644 --- a/target-arm/kvm.c +++ b/target-arm/kvm.c @@ -527,6 +527,26 @@ void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run) { + ARMCPU *cpu; + bool vtimer_high; + + if (kvm_irqchip_in_kernel()) { + /* + * We only need to sync timer states with user-space interrupt + * controllers, so return early and save cycles if we don't. + */ + return MEMTXATTRS_UNSPECIFIED; + } + + cpu = ARM_CPU(cs); + + /* Synchronize our internal vtimer irq line with the kvm one */ + if (run->s.regs.timer_irq_level != cpu->timer_irq_level) { + vtimer_high = run->s.regs.timer_irq_level & KVM_ARM_TIMER_VTIMER; + qemu_set_irq(cpu->gt_timer_outputs[GTIMER_VIRT], vtimer_high ? 1 : 0); + cpu->timer_irq_level = run->s.regs.timer_irq_level; + } + return MEMTXATTRS_UNSPECIFIED; } -- 1.8.5.6