aboutsummaryrefslogtreecommitdiff
path: root/arch/powerpc/kernel/machine_kexec_64.c
diff options
context:
space:
mode:
authorMatt Evans2010-07-07 21:55:37 +0000
committerBenjamin Herrenschmidt2010-07-31 14:56:30 +1000
commitfc53b4202e61c7e9008c241933ae282aab8a6082 (patch)
treec279a5256ba18a27ca0b785ecf6819f592a23509 /arch/powerpc/kernel/machine_kexec_64.c
parent7e3f36c3e107bd76b6709e358b1e7c703fb6f81a (diff)
powerpc/kexec: Switch to a static PACA on the way out
With dynamic PACAs, the kexecing CPU's PACA won't lie within the kernel static data and there is a chance that something may stomp it when preparing to kexec. This patch switches this final CPU to a static PACA just before we pull the switch. Signed-off-by: Matt Evans <matt@ozlabs.org> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel/machine_kexec_64.c')
-rw-r--r--arch/powerpc/kernel/machine_kexec_64.c20
1 files changed, 20 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c
index de6b70eac51d..022d2f613b7b 100644
--- a/arch/powerpc/kernel/machine_kexec_64.c
+++ b/arch/powerpc/kernel/machine_kexec_64.c
@@ -260,6 +260,12 @@ static void kexec_prepare_cpus(void)
static union thread_union kexec_stack __init_task_data =
{ };
+/*
+ * For similar reasons to the stack above, the kexecing CPU needs to be on a
+ * static PACA; we switch to kexec_paca.
+ */
+struct paca_struct kexec_paca;
+
/* Our assembly helper, in kexec_stub.S */
extern NORET_TYPE void kexec_sequence(void *newstack, unsigned long start,
void *image, void *control,
@@ -287,6 +293,20 @@ void default_machine_kexec(struct kimage *image)
kexec_stack.thread_info.task = current_thread_info()->task;
kexec_stack.thread_info.flags = 0;
+ /* 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
+ * data.
+ */
+ memcpy(&kexec_paca, get_paca(), sizeof(struct paca_struct));
+ kexec_paca.data_offset = 0xedeaddeadeeeeeeeUL;
+ paca = (struct paca_struct *)RELOC_HIDE(&kexec_paca, 0) -
+ kexec_paca.paca_index;
+ setup_paca(&kexec_paca);
+
+ /* XXX: If anyone does 'dynamic lppacas' this will also need to be
+ * switched to a static version!
+ */
+
/* Some things are best done in assembly. Finding globals with
* a toc is easier in C, so pass in what we can.
*/