| From 79c66ce8f6448a3295a32efeac88c9debd7f7094 Mon Sep 17 00:00:00 2001 |
| From: Anton Blanchard <anton@au1.ibm.com> |
| Date: Sun, 12 May 2013 15:04:53 +0000 |
| Subject: powerpc/kexec: Fix kexec when using VMX optimised memcpy |
| |
| From: Anton Blanchard <anton@au1.ibm.com> |
| |
| commit 79c66ce8f6448a3295a32efeac88c9debd7f7094 upstream. |
| |
| commit b3f271e86e5a (powerpc: POWER7 optimised memcpy using VMX and |
| enhanced prefetch) uses VMX when it is safe to do so (ie not in |
| interrupt). It also looks at the task struct to decide if we have to |
| save the current tasks' VMX state. |
| |
| kexec calls memcpy() at a point where the task struct may have been |
| overwritten by the new kexec segments. If it has been overwritten |
| then when memcpy -> enable_altivec looks up current->thread.regs->msr |
| we get a cryptic oops or lockup. |
| |
| I also notice we aren't initialising thread_info->cpu, which means |
| smp_processor_id is broken. Fix that too. |
| |
| Signed-off-by: Anton Blanchard <anton@samba.org> |
| Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/powerpc/kernel/machine_kexec_64.c | 4 ++++ |
| 1 file changed, 4 insertions(+) |
| |
| --- a/arch/powerpc/kernel/machine_kexec_64.c |
| +++ b/arch/powerpc/kernel/machine_kexec_64.c |
| @@ -17,6 +17,7 @@ |
| #include <linux/errno.h> |
| #include <linux/kernel.h> |
| #include <linux/cpu.h> |
| +#include <linux/hardirq.h> |
| |
| #include <asm/page.h> |
| #include <asm/current.h> |
| @@ -335,10 +336,13 @@ void default_machine_kexec(struct kimage |
| pr_debug("kexec: Starting switchover sequence.\n"); |
| |
| /* switch to a staticly allocated stack. Based on irq stack code. |
| + * We setup preempt_count to avoid using VMX in memcpy. |
| * XXX: the task struct will likely be invalid once we do the copy! |
| */ |
| kexec_stack.thread_info.task = current_thread_info()->task; |
| kexec_stack.thread_info.flags = 0; |
| + kexec_stack.thread_info.preempt_count = HARDIRQ_OFFSET; |
| + kexec_stack.thread_info.cpu = current_thread_info()->cpu; |
| |
| /* We need a static PACA, too; copy this CPU's PACA over and switch to |
| * it. Also poison per_cpu_offset to catch anyone using non-static |