From: Steven Price <steven.price@arm.com> To: kvmarm@lists.cs.columbia.edu, linux-arm-kernel@lists.infradead.org Cc: Marc Zyngier <marc.zyngier@arm.com>, Catalin Marinas <catalin.marinas@arm.com>, Will Deacon <will.deacon@arm.com>, Steven Price <steven.price@arm.com> Subject: [RFC PATCH v2 07/12] arm64: Retrieve stolen time as paravirtualized guest Date: Wed, 12 Dec 2018 15:02:21 +0000 [thread overview] Message-ID: <20181212150226.38051-8-steven.price@arm.com> (raw) In-Reply-To: <20181212150226.38051-1-steven.price@arm.com> Enable paravirtualization features when running under a hypervisor supporting the PV_TIME_ST hypercall. For each (v)CPU, we ask the hypervisor for the location of a shared page which the hypervisor will use to report stolen time to us. We set pv_time_ops to the stolen time function which simply reads the stolen value from the shared page for a VCPU. We guarantee single-copy atomicity using READ_ONCE which means we can also read the stolen time for another VCPU than the currently running one while it is potentially being updated by the hypervisor. Signed-off-by: Steven Price <steven.price@arm.com> --- arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/kvm.c | 156 +++++++++++++++++++++++++++++++++++++ include/linux/cpuhotplug.h | 1 + 3 files changed, 158 insertions(+) create mode 100644 arch/arm64/kernel/kvm.c diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 4c8b13bede80..daaed14ed7a4 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -57,6 +57,7 @@ arm64-obj-$(CONFIG_CRASH_DUMP) += crash_dump.o arm64-obj-$(CONFIG_CRASH_CORE) += crash_core.o arm64-obj-$(CONFIG_ARM_SDE_INTERFACE) += sdei.o arm64-obj-$(CONFIG_ARM64_SSBD) += ssbd.o +arm64-obj-$(CONFIG_PARAVIRT) += kvm.o obj-y += $(arm64-obj-y) vdso/ probes/ obj-m += $(arm64-obj-m) diff --git a/arch/arm64/kernel/kvm.c b/arch/arm64/kernel/kvm.c new file mode 100644 index 000000000000..f7bc1f069dc0 --- /dev/null +++ b/arch/arm64/kernel/kvm.c @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2018 Arm Ltd. + +#define pr_fmt(fmt) "kvmarm-pv: " fmt + +#include <linux/arm-smccc.h> +#include <linux/cpuhotplug.h> +#include <linux/io.h> +#include <linux/printk.h> +#include <linux/psci.h> +#include <linux/reboot.h> +#include <linux/slab.h> + +#include <asm/paravirt.h> +#include <asm/pvclock-abi.h> +#include <asm/smp_plat.h> + +struct kvmarm_stolen_time_region { + struct pvclock_vcpu_stolen_time_info *kaddr; +}; + +static DEFINE_PER_CPU(struct kvmarm_stolen_time_region, stolen_time_region); + +static bool steal_acc = true; +static int __init parse_no_stealacc(char *arg) +{ + steal_acc = false; + return 0; +} +early_param("no-steal-acc", parse_no_stealacc); + +/* return stolen time in ns by asking the hypervisor */ +static u64 kvm_steal_clock(int cpu) +{ + struct kvmarm_stolen_time_region *reg; + + reg = per_cpu_ptr(&stolen_time_region, cpu); + if (!reg->kaddr) { + pr_warn_once("stolen time enabled but not configued for cpu %d\n", + cpu); + return 0; + } + + return le64_to_cpu(READ_ONCE(reg->kaddr->stolen_time)); +} + +static int disable_stolen_time_current_cpu(void) +{ + struct kvmarm_stolen_time_region *reg; + + reg = this_cpu_ptr(&stolen_time_region); + if (!reg->kaddr) + return 0; + + memunmap(reg->kaddr); + memset(reg, 0, sizeof(*reg)); + + return 0; +} + +static int stolen_time_dying_cpu(unsigned int cpu) +{ + return disable_stolen_time_current_cpu(); +} + +static int init_stolen_time_cpu(unsigned int cpu) +{ + struct kvmarm_stolen_time_region *reg; + int ret; + struct arm_smccc_res res; + + reg = this_cpu_ptr(&stolen_time_region); + + if (reg->kaddr) + return 0; + + ret = arm_smccc_1_1_call(ARM_SMCCC_HV_PV_TIME_ST, &res); + + if ((long)res.a0 < 0) + return -EINVAL; + + reg->kaddr = memremap(res.a0, + sizeof(struct pvclock_vcpu_stolen_time_info), + MEMREMAP_WB); + + if (reg->kaddr == NULL) { + pr_warn("Failed to map stolen time data structure\n"); + return -EINVAL; + } + + if (le32_to_cpu(reg->kaddr->revision) != 0 || + le32_to_cpu(reg->kaddr->attributes) != 0) { + pr_warn("Unexpected revision or attributes in stolen time data\n"); + return -ENXIO; + } + + return 0; +} + +static int kvm_arm_init_stolen_time(void) +{ + int ret; + + ret = cpuhp_setup_state(CPUHP_AP_ARM_KVMPV_STARTING, + "hypervisor/kvmarm/pv:starting", + init_stolen_time_cpu, stolen_time_dying_cpu); + if (ret < 0) + return ret; + return 0; +} + +static bool has_kvm_steal_clock(void) +{ + struct arm_smccc_res res; + + /* To detect the presence of PV time support we require SMCCC 1.1+ */ + if (psci_ops.smccc_version < SMCCC_VERSION_1_1) + return false; + + arm_smccc_1_1_call(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, + ARM_SMCCC_HV_PV_FEATURES, &res); + + if (res.a0 != SMCCC_RET_SUCCESS) + return false; + + arm_smccc_1_1_call(ARM_SMCCC_HV_PV_FEATURES, + ARM_SMCCC_HV_PV_TIME_ST, &res); + + if (res.a0 != SMCCC_RET_SUCCESS) + return false; + + return true; +} + +static int __init kvm_guest_init(void) +{ + int ret = 0; + + if (!has_kvm_steal_clock()) + return 0; + + ret = kvm_arm_init_stolen_time(); + if (ret) + return ret; + + pv_ops.time.steal_clock = kvm_steal_clock; + + static_key_slow_inc(¶virt_steal_enabled); + if (steal_acc) + static_key_slow_inc(¶virt_steal_rq_enabled); + + pr_info("using stolen time PV\n"); + + return 0; +} +early_initcall(kvm_guest_init); diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index e0cd2baa8380..5c176a31deb8 100644 --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h @@ -134,6 +134,7 @@ enum cpuhp_state { /* Must be the last timer callback */ CPUHP_AP_DUMMY_TIMER_STARTING, CPUHP_AP_ARM_XEN_STARTING, + CPUHP_AP_ARM_KVMPV_STARTING, CPUHP_AP_ARM_CORESIGHT_STARTING, CPUHP_AP_ARM64_ISNDEP_STARTING, CPUHP_AP_SMPCFD_DYING, -- 2.19.2
WARNING: multiple messages have this Message-ID (diff)
From: Steven Price <steven.price@arm.com> To: kvmarm@lists.cs.columbia.edu, linux-arm-kernel@lists.infradead.org Cc: Mark Rutland <mark.rutland@arm.com>, Marc Zyngier <marc.zyngier@arm.com>, Catalin Marinas <catalin.marinas@arm.com>, Will Deacon <will.deacon@arm.com>, Christoffer Dall <christoffer.dall@arm.com>, Steven Price <steven.price@arm.com> Subject: [RFC PATCH v2 07/12] arm64: Retrieve stolen time as paravirtualized guest Date: Wed, 12 Dec 2018 15:02:21 +0000 [thread overview] Message-ID: <20181212150226.38051-8-steven.price@arm.com> (raw) In-Reply-To: <20181212150226.38051-1-steven.price@arm.com> Enable paravirtualization features when running under a hypervisor supporting the PV_TIME_ST hypercall. For each (v)CPU, we ask the hypervisor for the location of a shared page which the hypervisor will use to report stolen time to us. We set pv_time_ops to the stolen time function which simply reads the stolen value from the shared page for a VCPU. We guarantee single-copy atomicity using READ_ONCE which means we can also read the stolen time for another VCPU than the currently running one while it is potentially being updated by the hypervisor. Signed-off-by: Steven Price <steven.price@arm.com> --- arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/kvm.c | 156 +++++++++++++++++++++++++++++++++++++ include/linux/cpuhotplug.h | 1 + 3 files changed, 158 insertions(+) create mode 100644 arch/arm64/kernel/kvm.c diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 4c8b13bede80..daaed14ed7a4 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -57,6 +57,7 @@ arm64-obj-$(CONFIG_CRASH_DUMP) += crash_dump.o arm64-obj-$(CONFIG_CRASH_CORE) += crash_core.o arm64-obj-$(CONFIG_ARM_SDE_INTERFACE) += sdei.o arm64-obj-$(CONFIG_ARM64_SSBD) += ssbd.o +arm64-obj-$(CONFIG_PARAVIRT) += kvm.o obj-y += $(arm64-obj-y) vdso/ probes/ obj-m += $(arm64-obj-m) diff --git a/arch/arm64/kernel/kvm.c b/arch/arm64/kernel/kvm.c new file mode 100644 index 000000000000..f7bc1f069dc0 --- /dev/null +++ b/arch/arm64/kernel/kvm.c @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2018 Arm Ltd. + +#define pr_fmt(fmt) "kvmarm-pv: " fmt + +#include <linux/arm-smccc.h> +#include <linux/cpuhotplug.h> +#include <linux/io.h> +#include <linux/printk.h> +#include <linux/psci.h> +#include <linux/reboot.h> +#include <linux/slab.h> + +#include <asm/paravirt.h> +#include <asm/pvclock-abi.h> +#include <asm/smp_plat.h> + +struct kvmarm_stolen_time_region { + struct pvclock_vcpu_stolen_time_info *kaddr; +}; + +static DEFINE_PER_CPU(struct kvmarm_stolen_time_region, stolen_time_region); + +static bool steal_acc = true; +static int __init parse_no_stealacc(char *arg) +{ + steal_acc = false; + return 0; +} +early_param("no-steal-acc", parse_no_stealacc); + +/* return stolen time in ns by asking the hypervisor */ +static u64 kvm_steal_clock(int cpu) +{ + struct kvmarm_stolen_time_region *reg; + + reg = per_cpu_ptr(&stolen_time_region, cpu); + if (!reg->kaddr) { + pr_warn_once("stolen time enabled but not configued for cpu %d\n", + cpu); + return 0; + } + + return le64_to_cpu(READ_ONCE(reg->kaddr->stolen_time)); +} + +static int disable_stolen_time_current_cpu(void) +{ + struct kvmarm_stolen_time_region *reg; + + reg = this_cpu_ptr(&stolen_time_region); + if (!reg->kaddr) + return 0; + + memunmap(reg->kaddr); + memset(reg, 0, sizeof(*reg)); + + return 0; +} + +static int stolen_time_dying_cpu(unsigned int cpu) +{ + return disable_stolen_time_current_cpu(); +} + +static int init_stolen_time_cpu(unsigned int cpu) +{ + struct kvmarm_stolen_time_region *reg; + int ret; + struct arm_smccc_res res; + + reg = this_cpu_ptr(&stolen_time_region); + + if (reg->kaddr) + return 0; + + ret = arm_smccc_1_1_call(ARM_SMCCC_HV_PV_TIME_ST, &res); + + if ((long)res.a0 < 0) + return -EINVAL; + + reg->kaddr = memremap(res.a0, + sizeof(struct pvclock_vcpu_stolen_time_info), + MEMREMAP_WB); + + if (reg->kaddr == NULL) { + pr_warn("Failed to map stolen time data structure\n"); + return -EINVAL; + } + + if (le32_to_cpu(reg->kaddr->revision) != 0 || + le32_to_cpu(reg->kaddr->attributes) != 0) { + pr_warn("Unexpected revision or attributes in stolen time data\n"); + return -ENXIO; + } + + return 0; +} + +static int kvm_arm_init_stolen_time(void) +{ + int ret; + + ret = cpuhp_setup_state(CPUHP_AP_ARM_KVMPV_STARTING, + "hypervisor/kvmarm/pv:starting", + init_stolen_time_cpu, stolen_time_dying_cpu); + if (ret < 0) + return ret; + return 0; +} + +static bool has_kvm_steal_clock(void) +{ + struct arm_smccc_res res; + + /* To detect the presence of PV time support we require SMCCC 1.1+ */ + if (psci_ops.smccc_version < SMCCC_VERSION_1_1) + return false; + + arm_smccc_1_1_call(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, + ARM_SMCCC_HV_PV_FEATURES, &res); + + if (res.a0 != SMCCC_RET_SUCCESS) + return false; + + arm_smccc_1_1_call(ARM_SMCCC_HV_PV_FEATURES, + ARM_SMCCC_HV_PV_TIME_ST, &res); + + if (res.a0 != SMCCC_RET_SUCCESS) + return false; + + return true; +} + +static int __init kvm_guest_init(void) +{ + int ret = 0; + + if (!has_kvm_steal_clock()) + return 0; + + ret = kvm_arm_init_stolen_time(); + if (ret) + return ret; + + pv_ops.time.steal_clock = kvm_steal_clock; + + static_key_slow_inc(¶virt_steal_enabled); + if (steal_acc) + static_key_slow_inc(¶virt_steal_rq_enabled); + + pr_info("using stolen time PV\n"); + + return 0; +} +early_initcall(kvm_guest_init); diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index e0cd2baa8380..5c176a31deb8 100644 --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h @@ -134,6 +134,7 @@ enum cpuhp_state { /* Must be the last timer callback */ CPUHP_AP_DUMMY_TIMER_STARTING, CPUHP_AP_ARM_XEN_STARTING, + CPUHP_AP_ARM_KVMPV_STARTING, CPUHP_AP_ARM_CORESIGHT_STARTING, CPUHP_AP_ARM64_ISNDEP_STARTING, CPUHP_AP_SMPCFD_DYING, -- 2.19.2 _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
next prev parent reply other threads:[~2018-12-12 15:03 UTC|newest] Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top 2018-12-12 15:02 [RFC PATCH v2 00/12] arm64: Paravirtualized time support Steven Price 2018-12-12 15:02 ` Steven Price 2018-12-12 15:02 ` [RFC PATCH v2 01/12] KVM: arm64: Document PV-time interface Steven Price 2018-12-12 15:02 ` Steven Price 2018-12-12 15:02 ` [RFC PATCH v2 02/12] KVM: arm/arm64: Factor out hypercall handling from PSCI code Steven Price 2018-12-12 15:02 ` Steven Price 2018-12-12 15:02 ` [RFC PATCH v2 03/12] arm/arm64: Provide a wrapper for SMCCC 1.1 calls Steven Price 2018-12-12 15:02 ` Steven Price 2018-12-12 15:02 ` [RFC PATCH v2 04/12] arm/arm64: Make use of the SMCCC 1.1 wrapper Steven Price 2018-12-12 15:02 ` Steven Price 2018-12-12 15:02 ` [RFC PATCH v2 05/12] KVM: arm64: Implement PV_FEATURES call Steven Price 2018-12-12 15:02 ` Steven Price 2018-12-12 15:02 ` [RFC PATCH v2 06/12] KVM: arm64: Support stolen time reporting via shared structure Steven Price 2018-12-12 15:02 ` Steven Price 2018-12-12 15:02 ` Steven Price [this message] 2018-12-12 15:02 ` [RFC PATCH v2 07/12] arm64: Retrieve stolen time as paravirtualized guest Steven Price 2018-12-12 15:02 ` [RFC PATCH v2 08/12] KVM: Allow kvm_device_ops to be const Steven Price 2018-12-12 15:02 ` Steven Price 2018-12-12 15:02 ` [RFC PATCH v2 09/12] KVM: arm64: Provide a PV_TIME device to user space Steven Price 2018-12-12 15:02 ` Steven Price 2018-12-12 15:02 ` [RFC PATCH v2 10/12] KVM: arm64: Support Live Physical Time reporting Steven Price 2018-12-12 15:02 ` Steven Price 2018-12-12 15:02 ` [RFC PATCH v2 11/12] clocksource: arm_arch_timer: Use paravirtualized LPT Steven Price 2018-12-12 15:02 ` Steven Price 2018-12-12 15:02 ` [RFC PATCH v2 12/12] KVM: arm64: Export LPT using PV_TIME device Steven Price 2018-12-12 15:02 ` Steven Price
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20181212150226.38051-8-steven.price@arm.com \ --to=steven.price@arm.com \ --cc=catalin.marinas@arm.com \ --cc=kvmarm@lists.cs.columbia.edu \ --cc=linux-arm-kernel@lists.infradead.org \ --cc=marc.zyngier@arm.com \ --cc=will.deacon@arm.com \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.