From: takahiro.akashi@linaro.org (AKASHI Takahiro)
To: linux-arm-kernel@lists.infradead.org
Subject: Kexec and KVM not working gracefully together
Date: Fri, 06 Feb 2015 13:13:06 +0900 [thread overview]
Message-ID: <54D43F52.7030606@linaro.org> (raw)
In-Reply-To: <CAHt6W4eQ3iC+sqWAn5LkkfC-XBgGWR0i6TXjWvzEsUqFh75fwQ@mail.gmail.com>
Hi Frediano
[add Geoff to cc]
I still have to compare my code with yours, but please note that
some files in arch/arm/kvm are shared with arm64, especially
arm.c, mmu.c and related headers.
So can you please
- submit your new patch without including old e-mail threads.
(don't forget RFC or PATCH.)
- break it up into two pieces, one for common, the other for arm
and a few more comments below:
On 02/06/2015 01:56 AM, Frediano Ziglio wrote:
[snip]
> New version. Changes:
> - removed saved value and test again
> - remove vm flush, useless
> - correct compile check on header
> - try KVM enabled and not, compile link and tests
> - rewrite comments, add more where necessary
> - remove code to free and allocate again boot PGD and related, keep in
> memory if KEXEC is enabled
>
> Still not trying SMP. Still to be considered RFC. I tried different
> compile options (KEXEC and KVM turned on/off). I realized that I
> should test if kernel is started with SVC mode code still works
> correctly. ARM_VIRT_EXT is always turned on for V7 CPU.
>
>
> diff --git a/arch/arm/include/asm/kvm_asm.h b/arch/arm/include/asm/kvm_asm.h
> index 3a67bec..985f0a3 100644
> --- a/arch/arm/include/asm/kvm_asm.h
> +++ b/arch/arm/include/asm/kvm_asm.h
> @@ -97,7 +97,19 @@ extern char __kvm_hyp_code_end[];
> extern void __kvm_flush_vm_context(void);
> extern void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
>
> +extern void __kvm_set_vectors(unsigned long phys_vector_base);
> +
> extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
> +
> +#ifndef CONFIG_ARM_VIRT_EXT
Arm64 doesn't have CONFIG_ARM_VIRT_EXT. Why don't use CONFIG_KVM?
I'd rather put this conditional into the place where the function is
actually called for flexible implementation. (See below)
> +static void kvm_cpu_reset(void (*phys_reset)(void *), void *addr)
> +{
> + phys_reset(addr);
> +}
> +#else
> +extern void kvm_cpu_reset(void (*phys_reset)(void *), void *addr);
> +#endif
> +
> #endif
>
> #endif /* __ARM_KVM_ASM_H__ */
> diff --git a/arch/arm/kernel/hyp-stub.S b/arch/arm/kernel/hyp-stub.S
> index 2a55373..30339ad 100644
> --- a/arch/arm/kernel/hyp-stub.S
> +++ b/arch/arm/kernel/hyp-stub.S
> @@ -164,13 +164,63 @@ ARM_BE8(orr r7, r7, #(1 << 25)) @ HSCTLR.EE
> bx lr @ The boot CPU mode is left in r4.
> ENDPROC(__hyp_stub_install_secondary)
>
> +#undef CPU_RESET
> +#if defined(CONFIG_ARM_VIRT_EXT) && !defined(CONFIG_KVM) && !defined(ZIMAGE)
> +# define CPU_RESET 1
> +#endif
> +
> __hyp_stub_do_trap:
> +#ifdef CPU_RESET
> + cmp r0, #-2
> + bne 1f
> +
> + mrc p15, 4, r0, c1, c0, 0 @ HSCR
> + ldr r2, =0x40003807
> + bic r0, r0, r2
> + mcr p15, 4, r0, c1, c0, 0 @ HSCR
> + isb
> +
> + @ Disable MMU, caches and Thumb in SCTLR
> + mrc p15, 0, r0, c1, c0, 0 @ SCTLR
> + bic r0, r0, r2
> + mcr p15, 0, r0, c1, c0, 0
> +
> + bx r1
> + .ltorg
> +1:
> +#endif
> cmp r0, #-1
> mrceq p15, 4, r0, c12, c0, 0 @ get HVBAR
> mcrne p15, 4, r0, c12, c0, 0 @ set HVBAR
> __ERET
> ENDPROC(__hyp_stub_do_trap)
>
> +#ifdef CPU_RESET
> +/*
> + * r0 cpu_reset function
> + * r1 address to jump to
> + */
> +ENTRY(kvm_cpu_reset)
> + mov r2, r0
> +
> + @ __boot_cpu_mode should be HYP_MODE
> + adr r0, .L__boot_cpu_mode_offset
> + ldr r3, [r0]
> + ldr r0, [r0, r3]
> + cmp r0, #HYP_MODE
> + beq reset_to_hyp
> +
> + @ Call SVC mode cpu_reset
> + mov r0, r1
> +THUMB( orr r2, r2, 1 )
> + bx r2
> +
> +reset_to_hyp:
> + mov r0, #-2
> + b __hyp_set_vectors
> +ENDPROC(kvm_cpu_reset)
> +#endif
> +
> /*
> * __hyp_set_vectors: Call this after boot to set the initial hypervisor
> * vectors as part of hypervisor installation. On an SMP system, this should
> diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
> index fdfa3a7..c018719 100644
> --- a/arch/arm/kernel/process.c
> +++ b/arch/arm/kernel/process.c
> @@ -41,6 +41,7 @@
> #include <asm/system_misc.h>
> #include <asm/mach/time.h>
> #include <asm/tls.h>
> +#include <asm/kvm_asm.h>
>
> #ifdef CONFIG_CC_STACKPROTECTOR
> #include <linux/stackprotector.h>
> @@ -60,7 +61,7 @@ static const char *isa_modes[] __maybe_unused = {
> };
>
> extern void call_with_stack(void (*fn)(void *), void *arg, void *sp);
> -typedef void (*phys_reset_t)(unsigned long);
> +typedef void (*phys_reset_t)(void *);
>
> /*
> * A temporary stack to use for CPU reset. This is static so that we
> @@ -89,7 +90,8 @@ static void __soft_restart(void *addr)
>
> /* Switch to the identity mapping. */
> phys_reset = (phys_reset_t)(unsigned long)virt_to_phys(cpu_reset);
> - phys_reset((unsigned long)addr);
> +
> + kvm_cpu_reset(phys_reset, addr);
How about this?
#ifdef CONFIG_KVM
kvm_cpu_reset(...);
#endif
phys_reset(addr);
It will clearify the purpose of kvm_cpu_reset().
The name of kvm_cpu_reset() might better be cpu_*de*init_hyp_mode or similar
given that the function would be called in hyp_init_cpu_notify()
once kvm supports cpu hotplug in the future.
> /* Should never get here. */
> BUG();
> diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
> index 0b0d58a..e4d4a2b 100644
> --- a/arch/arm/kvm/arm.c
> +++ b/arch/arm/kvm/arm.c
> @@ -1009,7 +1009,7 @@ static int init_hyp_mode(void)
> if (err)
> goto out_free_mappings;
>
> -#ifndef CONFIG_HOTPLUG_CPU
> +#if !defined(CONFIG_HOTPLUG_CPU) && !defined(CONFIG_KEXEC)
> free_boot_hyp_pgd();
> #endif
>
> @@ -1079,6 +1079,53 @@ out_err:
> return err;
> }
>
> +void kvm_cpu_reset(void (*phys_reset)(void *), void *addr)
I'm not sure, but it might be better to put this code into arm/kernel/init.S
as it is a counterpart of _do_hyp_init from cpu_init_hyp_mode().
> +{
> + unsigned long vector;
> +
> + if (!is_hyp_mode_available()) {
> + phys_reset(addr);
> + return;
> + }
> +
> + vector = (unsigned long) kvm_get_idmap_vector();
> +
> + /*
> + * Set vectors so we call initialization routines.
> + * trampoline is mapped at TRAMPOLINE_VA but not at its physical
> + * address so we don't have an identity map to be able to
> + * disable MMU. We need to set exception vector at trampoline
> + * at TRAMPOLINE_VA address which is mapped.
> + */
> + kvm_call_hyp(__kvm_set_vectors,(unsigned long) (TRAMPOLINE_VA +
> (vector & (PAGE_SIZE-1))));
> +
> + /*
> + * Set HVBAR to physical address, page table to identity to do the switch
> + */
> + kvm_call_hyp((void*) 4, (unsigned long) vector, kvm_mmu_get_boot_httbr());
> +
> + /*
> + * Flush to make sure code after the cache are disabled see updated values
> + */
> + flush_cache_all();
> +
> + /*
> + * Turn off caching on Hypervisor mode
> + */
> + kvm_call_hyp((void*) 1);
> +
> + /*
> + * Flush to make sude code don't see old cached values after cache is
> + * enabled
> + */
> + flush_cache_all();
> +
> + /*
> + * Restore execution
> + */
> + kvm_call_hyp((void*) 3, addr);
> +}
> +
If you like kvm_call_hyp-like sequences, please specify what each kvm_call_hyp() should do.
(we can do all in one kvm_call_hyp() though.)
Thanks,
-Takahiro AKASHI
> /* NOP: Compiling as a module not supported */
> void kvm_arch_exit(void)
> {
> diff --git a/arch/arm/kvm/init.S b/arch/arm/kvm/init.S
> index 3988e72..c2f1d4d 100644
> --- a/arch/arm/kvm/init.S
> +++ b/arch/arm/kvm/init.S
> @@ -68,6 +68,12 @@ __kvm_hyp_init:
> W(b) .
>
> __do_hyp_init:
> + @ check for special values, odd numbers can't be a stack pointer
> + cmp r0, #1
> + beq cpu_proc_fin
> + cmp r0, #3
> + beq restore
> +
> cmp r0, #0 @ We have a SP?
> bne phase2 @ Yes, second stage init
>
> @@ -151,6 +157,33 @@ target: @ We're now in the trampoline code,
> switch page tables
>
> eret
>
> +cpu_proc_fin:
> + mrc p15, 4, r0, c1, c0, 0 @ ctrl register
> + bic r0, r0, #0x1000 @ ...i............
> + bic r0, r0, #0x0006 @ .............ca.
> + mcr p15, 4, r0, c1, c0, 0 @ disable caches
> + eret
> +
> +restore:
> + @ Disable MMU, caches and Thumb in HSCTLR
> + mrc p15, 4, r0, c1, c0, 0 @ HSCR
> + ldr r2, =0x40003807
> + bic r0, r0, r2
> + mcr p15, 4, r0, c1, c0, 0 @ HSCR
> + isb
> +
> + @ Invalidate old TLBs
> + mcr p15, 4, r0, c8, c7, 0 @ TLBIALLH
> + isb
> + dsb ish
> +
> + @ Disable MMU, caches and Thumb in SCTLR
> + mrc p15, 0, r0, c1, c0, 0 @ SCTLR
> + bic r0, r0, r2
> + mcr p15, 0, r0, c1, c0, 0
> +
> + bx r1
> +
> .ltorg
>
> .globl __kvm_hyp_init_end
> diff --git a/arch/arm/kvm/interrupts.S b/arch/arm/kvm/interrupts.S
> index 01dcb0e..449e7dd 100644
> --- a/arch/arm/kvm/interrupts.S
> +++ b/arch/arm/kvm/interrupts.S
> @@ -87,6 +87,18 @@ ENDPROC(__kvm_flush_vm_context)
>
>
> /********************************************************************
> + * Set HVBAR
> + *
> + * void __kvm_set_vectors(unsigned long phys_vector_base);
> + */
> +ENTRY(__kvm_set_vectors)
> + mcr p15, 4, r0, c12, c0, 0 @ set HVBAR
> + dsb ish
> + isb
> + bx lr
> +ENDPROC(__kvm_set_vectors)
> +
> +/********************************************************************
> * Hypervisor world-switch code
> *
> *
> diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
> index 1366625..f853858 100644
> --- a/arch/arm/kvm/mmu.c
> +++ b/arch/arm/kvm/mmu.c
> @@ -369,6 +369,11 @@ void free_boot_hyp_pgd(void)
> free_page((unsigned long)init_bounce_page);
> init_bounce_page = NULL;
>
> + /* avoid to reuse possibly invalid values if bounce page is freed */
> + hyp_idmap_start = 0;
> + hyp_idmap_end = 0;
> + hyp_idmap_vector = 0;
> +
> mutex_unlock(&kvm_hyp_pgd_mutex);
> }
>
>
> Frediano
>
next prev parent reply other threads:[~2015-02-06 4:13 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-01-27 15:07 Kexec and KVM not working gracefully together Frediano Ziglio
2015-01-27 15:25 ` Marc Zyngier
2015-02-05 6:17 ` AKASHI Takahiro
2015-02-05 9:43 ` Marc Zyngier
2015-02-05 10:27 ` AKASHI Takahiro
2015-02-05 10:51 ` Frediano Ziglio
2015-02-05 13:32 ` Marc Zyngier
2015-02-05 14:27 ` Frediano Ziglio
2015-02-05 16:56 ` Frediano Ziglio
2015-02-06 4:13 ` AKASHI Takahiro [this message]
2015-02-06 9:50 ` Frediano Ziglio
2015-02-06 10:56 ` AKASHI Takahiro
2015-02-06 12:14 ` Frediano Ziglio
2015-02-06 14:09 ` Marc Zyngier
2015-02-09 3:54 ` Geoff Levand
2015-02-09 15:51 ` Frediano Ziglio
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=54D43F52.7030606@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.