From: takahiro.akashi@linaro.org (AKASHI Takahiro)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v4 05/13] arm64: kvm: allows kvm cpu hotplug
Date: Tue, 2 Feb 2016 15:46:13 +0900 [thread overview]
Message-ID: <56B050B5.2070202@linaro.org> (raw)
In-Reply-To: <1453977766-20907-6-git-send-email-james.morse@arm.com>
On 01/28/2016 07:42 PM, James Morse wrote:
> From: AKASHI Takahiro <takahiro.akashi@linaro.org>
>
> The current kvm implementation on arm64 does cpu-specific initialization
> at system boot, and has no way to gracefully shutdown a core in terms of
> kvm. This prevents kexec from rebooting the system at EL2.
>
> This patch adds a cpu tear-down function and also puts an existing cpu-init
> code into a separate function, kvm_arch_hardware_disable() and
> kvm_arch_hardware_enable() respectively.
> We don't need the arm64 specific cpu hotplug hook any more.
>
> Since this patch modifies common code between arm and arm64, one stub
> definition, __cpu_reset_hyp_mode(), is added on arm side to avoid
> compilation errors.
>
> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> [Moved __kvm_hyp_reset() to use kvm_call_hyp(), instead of having its own
> dedicated entry point in el1_sync. Added some comments and a tlbi.]
> Signed-off-by: James Morse <james.morse@arm.com>
> ---
> This patch is from v13 of kexec, see my [changes] above.
>
> arch/arm/include/asm/kvm_host.h | 10 +++-
> arch/arm/include/asm/kvm_mmu.h | 1 +
> arch/arm/kvm/arm.c | 98 ++++++++++++++++++++++++---------------
> arch/arm/kvm/mmu.c | 5 ++
> arch/arm64/include/asm/kvm_host.h | 1 -
> arch/arm64/include/asm/kvm_mmu.h | 19 ++++++++
> arch/arm64/kvm/hyp-init.S | 42 +++++++++++++++++
> 7 files changed, 136 insertions(+), 40 deletions(-)
>
> diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
> index f9f27792d8ed..8af531d64771 100644
> --- a/arch/arm/include/asm/kvm_host.h
> +++ b/arch/arm/include/asm/kvm_host.h
> @@ -220,6 +220,15 @@ static inline void __cpu_init_hyp_mode(phys_addr_t boot_pgd_ptr,
> kvm_call_hyp((void*)hyp_stack_ptr, vector_ptr, pgd_ptr);
> }
>
> +static inline void __cpu_reset_hyp_mode(phys_addr_t boot_pgd_ptr,
> + phys_addr_t phys_idmap_start)
> +{
> + /*
> + * TODO
> + * kvm_call_reset(boot_pgd_ptr, phys_idmap_start);
> + */
> +}
> +
> static inline int kvm_arch_dev_ioctl_check_extension(long ext)
> {
> return 0;
> @@ -232,7 +241,6 @@ void kvm_mmu_wp_memory_region(struct kvm *kvm, int slot);
>
> struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr);
>
> -static inline void kvm_arch_hardware_disable(void) {}
> static inline void kvm_arch_hardware_unsetup(void) {}
> static inline void kvm_arch_sync_events(struct kvm *kvm) {}
> static inline void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) {}
> diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
> index a520b7987a29..4fd9ddb48c0f 100644
> --- a/arch/arm/include/asm/kvm_mmu.h
> +++ b/arch/arm/include/asm/kvm_mmu.h
> @@ -66,6 +66,7 @@ void kvm_mmu_free_memory_caches(struct kvm_vcpu *vcpu);
> phys_addr_t kvm_mmu_get_httbr(void);
> phys_addr_t kvm_mmu_get_boot_httbr(void);
> phys_addr_t kvm_get_idmap_vector(void);
> +phys_addr_t kvm_get_idmap_start(void);
> int kvm_mmu_init(void);
> void kvm_clear_hyp_idmap(void);
>
> diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
> index dda1959f0dde..f060567e9c0a 100644
> --- a/arch/arm/kvm/arm.c
> +++ b/arch/arm/kvm/arm.c
> @@ -16,7 +16,6 @@
> * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> */
>
> -#include <linux/cpu.h>
> #include <linux/cpu_pm.h>
> #include <linux/errno.h>
> #include <linux/err.h>
> @@ -65,6 +64,8 @@ static DEFINE_SPINLOCK(kvm_vmid_lock);
>
> static bool vgic_present;
>
> +static DEFINE_PER_CPU(unsigned char, kvm_arm_hardware_enabled);
> +
> static void kvm_arm_set_running_vcpu(struct kvm_vcpu *vcpu)
> {
> BUG_ON(preemptible());
> @@ -89,11 +90,6 @@ struct kvm_vcpu * __percpu *kvm_get_running_vcpus(void)
> return &kvm_arm_running_vcpu;
> }
>
> -int kvm_arch_hardware_enable(void)
> -{
> - return 0;
> -}
> -
> int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
> {
> return kvm_vcpu_exiting_guest_mode(vcpu) == IN_GUEST_MODE;
> @@ -585,7 +581,13 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
> /*
> * Re-check atomic conditions
> */
> - if (signal_pending(current)) {
> + if (unlikely(!__this_cpu_read(kvm_arm_hardware_enabled))) {
> + /* cpu has been torn down */
> + ret = 0;
> + run->exit_reason = KVM_EXIT_FAIL_ENTRY;
> + run->fail_entry.hardware_entry_failure_reason
> + = (u64)-ENOEXEC;
> + } else if (signal_pending(current)) {
> ret = -EINTR;
> run->exit_reason = KVM_EXIT_INTR;
> }
> @@ -967,7 +969,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
> }
> }
>
> -static void cpu_init_hyp_mode(void *dummy)
> +static void cpu_init_hyp_mode(void)
> {
> phys_addr_t boot_pgd_ptr;
> phys_addr_t pgd_ptr;
> @@ -989,36 +991,61 @@ static void cpu_init_hyp_mode(void *dummy)
> kvm_arm_init_debug();
> }
>
> -static int hyp_init_cpu_notify(struct notifier_block *self,
> - unsigned long action, void *cpu)
> +static void cpu_reset_hyp_mode(void)
> {
> - switch (action) {
> - case CPU_STARTING:
> - case CPU_STARTING_FROZEN:
> - if (__hyp_get_vectors() == hyp_default_vectors)
> - cpu_init_hyp_mode(NULL);
> - break;
> + phys_addr_t boot_pgd_ptr;
> + phys_addr_t phys_idmap_start;
> +
> + boot_pgd_ptr = kvm_mmu_get_boot_httbr();
> + phys_idmap_start = kvm_get_idmap_start();
> +
> + __cpu_reset_hyp_mode(boot_pgd_ptr, phys_idmap_start);
> +}
> +
> +int kvm_arch_hardware_enable(void)
> +{
> + if (!__this_cpu_read(kvm_arm_hardware_enabled)) {
> + cpu_init_hyp_mode();
> + __this_cpu_write(kvm_arm_hardware_enabled, 1);
> }
>
> - return NOTIFY_OK;
> + return 0;
> }
>
> -static struct notifier_block hyp_init_cpu_nb = {
> - .notifier_call = hyp_init_cpu_notify,
> -};
> +void kvm_arch_hardware_disable(void)
> +{
> + if (!__this_cpu_read(kvm_arm_hardware_enabled))
> + return;
> +
> + cpu_reset_hyp_mode();
> + __this_cpu_write(kvm_arm_hardware_enabled, 0);
> +}
>
> #ifdef CONFIG_CPU_PM
> static int hyp_init_cpu_pm_notifier(struct notifier_block *self,
> unsigned long cmd,
> void *v)
> {
> - if (cmd == CPU_PM_EXIT &&
> - __hyp_get_vectors() == hyp_default_vectors) {
> - cpu_init_hyp_mode(NULL);
> + /*
> + * kvm_arm_hardware_enabled is left with its old value over
> + * PM_ENTER->PM_EXIT. It is used to indicate PM_EXIT should
> + * re-enable hyp.
> + */
> + switch (cmd) {
> + case CPU_PM_ENTER:
> + if (__this_cpu_read(kvm_arm_hardware_enabled))
> + cpu_reset_hyp_mode();
> +
> + return NOTIFY_OK;
> + case CPU_PM_EXIT:
> + if (__this_cpu_read(kvm_arm_hardware_enabled))
> + cpu_init_hyp_mode();
> +
> return NOTIFY_OK;
> - }
>
> - return NOTIFY_DONE;
> + default:
> + return NOTIFY_DONE;
> + }
> }
>
> static struct notifier_block hyp_init_cpu_pm_nb = {
> @@ -1122,14 +1149,20 @@ static int init_hyp_mode(void)
> }
>
> /*
> - * Execute the init code on each CPU.
> + * Init this CPU temporarily to execute kvm_hyp_call()
> + * during kvm_vgic_hyp_init().
> */
> - on_each_cpu(cpu_init_hyp_mode, NULL, 1);
> + preempt_disable();
> + cpu_init_hyp_mode();
>
> /*
> * Init HYP view of VGIC
> */
> err = kvm_vgic_hyp_init();
> +
> + cpu_reset_hyp_mode();
> + preempt_enable();
> +
> switch (err) {
> case 0:
> vgic_present = true;
> @@ -1213,26 +1246,15 @@ int kvm_arch_init(void *opaque)
> }
> }
>
> - cpu_notifier_register_begin();
> -
> err = init_hyp_mode();
> if (err)
> goto out_err;
>
> - err = __register_cpu_notifier(&hyp_init_cpu_nb);
> - if (err) {
> - kvm_err("Cannot register HYP init CPU notifier (%d)\n", err);
> - goto out_err;
> - }
> -
> - cpu_notifier_register_done();
> -
> hyp_cpu_pm_init();
>
> kvm_coproc_table_init();
> return 0;
> out_err:
> - cpu_notifier_register_done();
> return err;
> }
>
> diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
> index aba61fd3697a..7a3aed62499a 100644
> --- a/arch/arm/kvm/mmu.c
> +++ b/arch/arm/kvm/mmu.c
> @@ -1643,6 +1643,11 @@ phys_addr_t kvm_get_idmap_vector(void)
> return hyp_idmap_vector;
> }
>
> +phys_addr_t kvm_get_idmap_start(void)
> +{
> + return hyp_idmap_start;
> +}
> +
> int kvm_mmu_init(void)
> {
> int err;
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 689d4c95e12f..7d6d75616fb5 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -332,7 +332,6 @@ static inline void __cpu_init_hyp_mode(phys_addr_t boot_pgd_ptr,
> hyp_stack_ptr, vector_ptr);
> }
>
> -static inline void kvm_arch_hardware_disable(void) {}
> static inline void kvm_arch_hardware_unsetup(void) {}
> static inline void kvm_arch_sync_events(struct kvm *kvm) {}
> static inline void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) {}
> diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
> index 736433912a1e..1d48208a904a 100644
> --- a/arch/arm64/include/asm/kvm_mmu.h
> +++ b/arch/arm64/include/asm/kvm_mmu.h
> @@ -99,6 +99,7 @@ void kvm_mmu_free_memory_caches(struct kvm_vcpu *vcpu);
> phys_addr_t kvm_mmu_get_httbr(void);
> phys_addr_t kvm_mmu_get_boot_httbr(void);
> phys_addr_t kvm_get_idmap_vector(void);
> +phys_addr_t kvm_get_idmap_start(void);
> int kvm_mmu_init(void);
> void kvm_clear_hyp_idmap(void);
>
> @@ -310,5 +311,23 @@ static inline unsigned int kvm_get_vmid_bits(void)
> return (cpuid_feature_extract_field(reg, ID_AA64MMFR1_VMIDBITS_SHIFT) == 2) ? 16 : 8;
> }
>
> +void __kvm_hyp_reset(phys_addr_t boot_pgd_ptr, phys_addr_t phys_idmap_start);
> +
> +/*
> + * Call reset code, and switch back to stub hyp vectors. We need to execute
> + * __kvm_hyp_reset() from the trampoline page, we calculate its address here.
> + */
> +static inline void __cpu_reset_hyp_mode(phys_addr_t boot_pgd_ptr,
> + phys_addr_t phys_idmap_start)
> +{
> + unsigned long trampoline_hyp_reset;
> +
> + trampoline_hyp_reset = TRAMPOLINE_VA +
> + ((unsigned long)__kvm_hyp_reset & ~PAGE_MASK);
> +
> + kvm_call_hyp((void *)trampoline_hyp_reset,
> + boot_pgd_ptr, phys_idmap_start);
> +}
> +
I want to place this definition in kvm_host.h as its counterpart, __cpu_init_hyp_mode().
-Takahiro AKASHI
> #endif /* __ASSEMBLY__ */
> #endif /* __ARM64_KVM_MMU_H__ */
> diff --git a/arch/arm64/kvm/hyp-init.S b/arch/arm64/kvm/hyp-init.S
> index dc6335a7353e..d20d86c7f9d8 100644
> --- a/arch/arm64/kvm/hyp-init.S
> +++ b/arch/arm64/kvm/hyp-init.S
> @@ -150,6 +150,48 @@ merged:
> eret
> ENDPROC(__kvm_hyp_init)
>
> + /*
> + * x0: HYP boot pgd
> + * x1: HYP phys_idmap_start
> + */
> +ENTRY(__kvm_hyp_reset)
> + /*
> + * Retrieve lr from the stack (pushed by el1_sync()), so we can eret
> + * from here.
> + */
> + ldp lr, xzr, [sp], #16
> +
> + /* We're in trampoline code in VA, switch back to boot page tables */
> + msr ttbr0_el2, x0
> + isb
> +
> + /* Ensure the PA branch doesn't find a stale tlb entry. */
> + tlbi alle2
> + dsb sy
> +
> + /* Branch into PA space */
> + adr x0, 1f
> + bfi x1, x0, #0, #PAGE_SHIFT
> + br x1
> +
> + /* We're now in idmap, disable MMU */
> +1: mrs x0, sctlr_el2
> + ldr x1, =SCTLR_ELx_FLAGS
> + bic x0, x0, x1 // Clear SCTL_M and etc
> + msr sctlr_el2, x0
> + isb
> +
> + /* Invalidate the old TLBs */
> + tlbi alle2
> + dsb sy
> +
> + /* Install stub vectors */
> + adr_l x0, __hyp_stub_vectors
> + msr vbar_el2, x0
> +
> + eret
> +ENDPROC(__kvm_hyp_reset)
> +
> .ltorg
>
> .popsection
>
next prev parent reply other threads:[~2016-02-02 6:46 UTC|newest]
Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-01-28 10:42 [PATCH v4 00/13] arm64: kernel: Add support for hibernate/suspend-to-disk James Morse
2016-01-28 10:42 ` James Morse
2016-01-28 10:42 ` [PATCH v4 01/13] arm64: Fold proc-macros.S into assembler.h James Morse
2016-01-28 10:42 ` [PATCH v4 02/13] arm64: Cleanup SCTLR flags James Morse
2016-01-28 10:42 ` [PATCH v4 03/13] arm64: Convert hcalls to use HVC immediate value James Morse
2016-01-28 10:42 ` [PATCH v4 04/13] arm64: Add new hcall HVC_CALL_FUNC James Morse
2016-02-02 6:53 ` AKASHI Takahiro
2016-01-28 10:42 ` [PATCH v4 05/13] arm64: kvm: allows kvm cpu hotplug James Morse
2016-02-02 6:46 ` AKASHI Takahiro [this message]
2016-01-28 10:42 ` [PATCH v4 06/13] arm64: kernel: Rework finisher callback out of __cpu_suspend_enter() James Morse
2016-01-28 10:42 ` [PATCH v4 07/13] arm64: Change cpu_resume() to enable mmu early then access sleep_sp by va James Morse
2016-02-05 16:26 ` Lorenzo Pieralisi
2016-02-08 9:03 ` James Morse
2016-02-08 11:55 ` Lorenzo Pieralisi
2016-02-08 12:03 ` Mark Rutland
2016-01-28 10:42 ` [PATCH v4 08/13] arm64: kernel: Include _AC definition in page.h James Morse
2016-01-28 10:42 ` [PATCH v4 09/13] arm64: Promote KERNEL_START/KERNEL_END definitions to a header file James Morse
2016-01-28 10:42 ` [PATCH v4 10/13] arm64: Add new asm macro copy_page James Morse
2016-01-28 10:42 ` [PATCH v4 11/13] PM / Hibernate: Call flush_icache_range() on pages restored in-place James Morse
2016-01-28 10:42 ` James Morse
2016-01-31 17:25 ` Pavel Machek
2016-01-31 17:25 ` Pavel Machek
2016-01-28 10:42 ` [PATCH v4 12/13] arm64: kernel: Add support for hibernate/suspend-to-disk James Morse
2016-01-28 10:42 ` [PATCH v4 13/13] arm64: hibernate: Prevent resume from a different kernel version James Morse
2016-01-29 22:34 ` [PATCH v4 00/13] arm64: kernel: Add support for hibernate/suspend-to-disk Kevin Hilman
2016-01-29 22:34 ` Kevin Hilman
2016-02-01 8:53 ` James Morse
2016-02-01 8:53 ` James Morse
2016-02-03 0:42 ` Kevin Hilman
2016-02-03 0:42 ` Kevin Hilman
2016-02-05 14:18 ` James Morse
2016-02-05 14:18 ` James Morse
2016-02-08 21:20 ` Kevin Hilman
2016-02-08 21:20 ` Kevin Hilman
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=56B050B5.2070202@linaro.org \
--to=takahiro.akashi@linaro.org \
--cc=linux-arm-kernel@lists.infradead.org \
/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: link
Be 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.