On 24/11/15 22:25, Geoff Levand wrote:
> From: AKASHI Takahiro <[email protected]>
> 
> 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, especially, kexec from rebooting the system on a boot
> core in 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 arm64-specific cpu hotplug hook any more.
> 
> Since this patch modifies common part of code between arm and arm64, one
> stub definition, __cpu_reset_hyp_mode(), is added on arm side to avoid
> compiling errors.
> 
> Signed-off-by: AKASHI Takahiro <[email protected]>
> ---
>  arch/arm/include/asm/kvm_host.h   | 10 ++++-
>  arch/arm/include/asm/kvm_mmu.h    |  1 +
>  arch/arm/kvm/arm.c                | 79 
> ++++++++++++++++++---------------------
>  arch/arm/kvm/mmu.c                |  5 +++
>  arch/arm64/include/asm/kvm_host.h | 16 +++++++-
>  arch/arm64/include/asm/kvm_mmu.h  |  1 +
>  arch/arm64/include/asm/virt.h     |  9 +++++
>  arch/arm64/kvm/hyp-init.S         | 33 ++++++++++++++++
>  arch/arm64/kvm/hyp.S              | 32 ++++++++++++++--
>  9 files changed, 138 insertions(+), 48 deletions(-)
> 
> diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
> index 6692982..9242765 100644
> --- a/arch/arm/include/asm/kvm_host.h
> +++ b/arch/arm/include/asm/kvm_host.h
> @@ -214,6 +214,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;
> @@ -226,7 +235,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 405aa18..dc6fadf 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 eab83b2..a5d9d74 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>
> @@ -61,6 +60,8 @@ static atomic64_t kvm_vmid_gen = ATOMIC64_INIT(1);
>  static u8 kvm_next_vmid;
>  static DEFINE_SPINLOCK(kvm_vmid_lock);
>  
> +static DEFINE_PER_CPU(unsigned char, kvm_arm_hardware_enabled);
> +
>  static void kvm_arm_set_running_vcpu(struct kvm_vcpu *vcpu)
>  {
>       BUG_ON(preemptible());
> @@ -85,11 +86,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;
> @@ -959,7 +955,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
>       }
>  }
>  
> -static void cpu_init_hyp_mode(void *dummy)
> +int kvm_arch_hardware_enable(void)
>  {
>       phys_addr_t boot_pgd_ptr;
>       phys_addr_t pgd_ptr;
> @@ -967,6 +963,9 @@ static void cpu_init_hyp_mode(void *dummy)
>       unsigned long stack_page;
>       unsigned long vector_ptr;
>  
> +     if (__hyp_get_vectors() != hyp_default_vectors)
> +             return 0;
> +
>       /* Switch from the HYP stub to our own HYP init vector */
>       __hyp_set_vectors(kvm_get_idmap_vector());
>  
> @@ -979,38 +978,50 @@ static void cpu_init_hyp_mode(void *dummy)
>       __cpu_init_hyp_mode(boot_pgd_ptr, pgd_ptr, hyp_stack_ptr, vector_ptr);
>  
>       kvm_arm_init_debug();
> +
> +     return 0;
>  }
>  
> -static int hyp_init_cpu_notify(struct notifier_block *self,
> -                            unsigned long action, void *cpu)
> +void kvm_arch_hardware_disable(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;
>  
> -     return NOTIFY_OK;
> -}
> +     if (__hyp_get_vectors() == hyp_default_vectors)
> +             return;
>  
> -static struct notifier_block hyp_init_cpu_nb = {
> -     .notifier_call = hyp_init_cpu_notify,
> -};
> +     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);
> +}
>  
>  #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);
> +     switch (cmd) {
> +     case CPU_PM_ENTER:
> +             if (__hyp_get_vectors() != hyp_default_vectors)
> +                     __this_cpu_write(kvm_arm_hardware_enabled, 1);
> +             else
> +                     __this_cpu_write(kvm_arm_hardware_enabled, 0);
> +             /*
> +              * don't call kvm_arch_hardware_disable() in case of
> +              * CPU_PM_ENTER because it does't actually save any state.
> +              */
> +
> +             return NOTIFY_OK;
> +     case CPU_PM_EXIT:
> +             if (__this_cpu_read(kvm_arm_hardware_enabled))
> +                     kvm_arch_hardware_enable();
> +
>               return NOTIFY_OK;
> -     }
>  
> -     return NOTIFY_DONE;
> +     default:
> +             return NOTIFY_DONE;
> +     }
>  }
>  
>  static struct notifier_block hyp_init_cpu_pm_nb = {
> @@ -1108,11 +1119,6 @@ static int init_hyp_mode(void)
>       }
>  
>       /*
> -      * Execute the init code on each CPU.
> -      */
> -     on_each_cpu(cpu_init_hyp_mode, NULL, 1);
> -
> -     /*
>        * Init HYP view of VGIC
>        */
>       err = kvm_vgic_hyp_init();
> @@ -1186,26 +1192,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 6984342..69b4a33 100644
> --- a/arch/arm/kvm/mmu.c
> +++ b/arch/arm/kvm/mmu.c
> @@ -1644,6 +1644,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 a35ce72..0b540f8 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -223,6 +223,7 @@ struct kvm_vcpu *kvm_arm_get_running_vcpu(void);
>  struct kvm_vcpu * __percpu *kvm_get_running_vcpus(void);
>  
>  u64 kvm_call_hyp(void *hypfn, ...);
> +void kvm_call_reset(phys_addr_t boot_pgd_ptr, phys_addr_t phys_idmap_start);
>  void force_vm_exit(const cpumask_t *mask);
>  void kvm_mmu_wp_memory_region(struct kvm *kvm, int slot);
>  
> @@ -247,7 +248,20 @@ 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 __cpu_reset_hyp_mode(phys_addr_t boot_pgd_ptr,
> +                                     phys_addr_t phys_idmap_start)
> +{
> +     /*
> +      * Call reset code, and switch back to stub hyp vectors.
> +      */
> +     kvm_call_reset(boot_pgd_ptr, phys_idmap_start);
> +}
> +
> +struct vgic_sr_vectors {
> +     void    *save_vgic;
> +     void    *restore_vgic;
> +};
> +

Why is this structure being re-introduced? It has been removed in 48f8bd5.

>  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 6150567..ff5a087 100644
> --- a/arch/arm64/include/asm/kvm_mmu.h
> +++ b/arch/arm64/include/asm/kvm_mmu.h
> @@ -98,6 +98,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/arm64/include/asm/virt.h b/arch/arm64/include/asm/virt.h
> index 3070096..bca79f9 100644
> --- a/arch/arm64/include/asm/virt.h
> +++ b/arch/arm64/include/asm/virt.h
> @@ -58,9 +58,18 @@
>  
>  #define HVC_CALL_FUNC 3
>  
> +/*
> + * HVC_RESET_CPU - Reset cpu in EL2 to initial state.
> + *
> + * @x0: entry address in trampoline code in va
> + * @x1: identical mapping page table in pa
> + */
> +
>  #define BOOT_CPU_MODE_EL1    (0xe11)
>  #define BOOT_CPU_MODE_EL2    (0xe12)
>  
> +#define HVC_RESET_CPU 4
> +

Why isn't this next to the comment that document it?

>  #ifndef __ASSEMBLY__
>  
>  /*
> diff --git a/arch/arm64/kvm/hyp-init.S b/arch/arm64/kvm/hyp-init.S
> index 2e67a48..1925163 100644
> --- a/arch/arm64/kvm/hyp-init.S
> +++ b/arch/arm64/kvm/hyp-init.S
> @@ -139,6 +139,39 @@ merged:
>       eret
>  ENDPROC(__kvm_hyp_init)
>  
> +     /*
> +      * x0: HYP boot pgd
> +      * x1: HYP phys_idmap_start
> +      */
> +ENTRY(__kvm_hyp_reset)
> +     /* We're in trampoline code in VA, switch back to boot page tables */
> +     msr     ttbr0_el2, x0
> +     isb
> +
> +     /* Invalidate the old TLBs */
> +     tlbi    alle2
> +     dsb     sy

I find the location of that TLBI a bit weird. If you want to do
something more useful, move it to after the MMU has been disabled.

> +
> +     /* 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_EL2_FLAGS
> +     bic     x0, x0, x1              // Clear SCTL_M and etc
> +     msr     sctlr_el2, x0
> +     isb
> +
> +     /* Install stub vectors */
> +     adrp    x0, __hyp_stub_vectors
> +     add     x0, x0, #:lo12:__hyp_stub_vectors
> +     msr     vbar_el2, x0
> +
> +     eret
> +ENDPROC(__kvm_hyp_reset)
> +
>       .ltorg
>  
>       .popsection
> diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S
> index 1bef8db..aca11d6 100644
> --- a/arch/arm64/kvm/hyp.S
> +++ b/arch/arm64/kvm/hyp.S
> @@ -939,6 +939,11 @@ ENTRY(kvm_call_hyp)
>       ret
>  ENDPROC(kvm_call_hyp)
>  
> +ENTRY(kvm_call_reset)
> +     hvc     #HVC_RESET_CPU
> +     ret
> +ENDPROC(kvm_call_reset)
> +
>  .macro invalid_vector        label, target
>       .align  2
>  \label:
> @@ -982,10 +987,27 @@ el1_sync:                                       // 
> Guest trapped into EL2
>       cmp     x18, #HVC_GET_VECTORS
>       b.ne    1f
>       mrs     x0, vbar_el2
> -     b       2f
> -
> -1:   /* Default to HVC_CALL_HYP. */
> +     b       do_eret
>  
> +     /* jump into trampoline code */
> +1:   cmp     x18, #HVC_RESET_CPU
> +     b.ne    2f
> +     /*
> +      * Entry point is:
> +      *      TRAMPOLINE_VA
> +      *      + (__kvm_hyp_reset - (__hyp_idmap_text_start & PAGE_MASK))
> +      */
> +     adrp    x2, __kvm_hyp_reset
> +     add     x2, x2, #:lo12:__kvm_hyp_reset
> +     adrp    x3, __hyp_idmap_text_start
> +     add     x3, x3, #:lo12:__hyp_idmap_text_start
> +     and     x3, x3, PAGE_MASK
> +     sub     x2, x2, x3
> +     ldr     x3, =TRAMPOLINE_VA

Nit: You should be able to do a "mov x3, #TRAMPOLINE_VA and avoid the
load from memory.

> +     add     x2, x2, x3
> +     br      x2                              // no return
> +
> +2:   /* Default to HVC_CALL_HYP. */
>       push    lr, xzr
>  
>       /*
> @@ -999,7 +1021,9 @@ el1_sync:                                        // 
> Guest trapped into EL2
>       blr     lr
>  
>       pop     lr, xzr
> -2:   eret
> +
> +do_eret:
> +     eret
>  
>  el1_trap:
>       /*
> 

Thanks,

        M.
-- 
Jazz is not dead. It just smells funny...

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

Reply via email to