Skip to content

Commit

Permalink
powerpc/kexec: Switch to a static PACA on the way out
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Matt Evans authored and Benjamin Herrenschmidt committed Jul 31, 2010
1 parent 7e3f36c commit fc53b42
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 11 deletions.
2 changes: 1 addition & 1 deletion arch/powerpc/include/asm/paca.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ struct paca_struct {
extern struct paca_struct *paca;
extern __initdata struct paca_struct boot_paca;
extern void initialise_paca(struct paca_struct *new_paca, int cpu);

extern void setup_paca(struct paca_struct *new_paca);
extern void allocate_pacas(void);
extern void free_unused_pacas(void);

Expand Down
20 changes: 20 additions & 0 deletions arch/powerpc/kernel/machine_kexec_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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.
*/
Expand Down
10 changes: 10 additions & 0 deletions arch/powerpc/kernel/paca.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,16 @@ void __init initialise_paca(struct paca_struct *new_paca, int cpu)
#endif /* CONFIG_PPC_STD_MMU_64 */
}

/* Put the paca pointer into r13 and SPRG_PACA */
void setup_paca(struct paca_struct *new_paca)
{
local_paca = new_paca;
mtspr(SPRN_SPRG_PACA, local_paca);
#ifdef CONFIG_PPC_BOOK3E
mtspr(SPRN_SPRG_TLB_EXFRAME, local_paca->extlb);
#endif
}

static int __initdata paca_size;

void __init allocate_pacas(void)
Expand Down
10 changes: 0 additions & 10 deletions arch/powerpc/kernel/setup_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,16 +142,6 @@ early_param("smt-enabled", early_smt_enabled);
#define check_smt_enabled()
#endif /* CONFIG_SMP */

/* Put the paca pointer into r13 and SPRG_PACA */
static void __init setup_paca(struct paca_struct *new_paca)
{
local_paca = new_paca;
mtspr(SPRN_SPRG_PACA, local_paca);
#ifdef CONFIG_PPC_BOOK3E
mtspr(SPRN_SPRG_TLB_EXFRAME, local_paca->extlb);
#endif
}

/*
* Early initialization entry point. This is called by head.S
* with MMU translation disabled. We rely on the "feature" of
Expand Down

0 comments on commit fc53b42

Please sign in to comment.