Skip to content

Commit 48abec0

Browse files
committed
powerpc: Fix bug causing FP registers corruption on UP + preempt
This fixes a bug noticed by Paolo Galtieri and fixed for ARCH=ppc in the previous commit (ppc: fix floating point register corruption). This fixes the arch/powerpc code by adding preempt_disable/enable, and also cleans it up a bit by pulling out the code that discards any lazily-switched CPU register state into a new function, rather than having that code repeated in three places. Signed-off-by: Paul Mackerras <[email protected]>
1 parent 8117ce7 commit 48abec0

File tree

1 file changed

+25
-37
lines changed

1 file changed

+25
-37
lines changed

arch/powerpc/kernel/process.c

Lines changed: 25 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,28 @@ int dump_spe(struct pt_regs *regs, elf_vrregset_t *evrregs)
201201
}
202202
#endif /* CONFIG_SPE */
203203

204+
/*
205+
* If we are doing lazy switching of CPU state (FP, altivec or SPE),
206+
* and the current task has some state, discard it.
207+
*/
208+
static inline void discard_lazy_cpu_state(void)
209+
{
210+
#ifndef CONFIG_SMP
211+
preempt_disable();
212+
if (last_task_used_math == current)
213+
last_task_used_math = NULL;
214+
#ifdef CONFIG_ALTIVEC
215+
if (last_task_used_altivec == current)
216+
last_task_used_altivec = NULL;
217+
#endif /* CONFIG_ALTIVEC */
218+
#ifdef CONFIG_SPE
219+
if (last_task_used_spe == current)
220+
last_task_used_spe = NULL;
221+
#endif
222+
preempt_enable();
223+
#endif /* CONFIG_SMP */
224+
}
225+
204226
int set_dabr(unsigned long dabr)
205227
{
206228
if (ppc_md.set_dabr)
@@ -434,19 +456,7 @@ void show_regs(struct pt_regs * regs)
434456
void exit_thread(void)
435457
{
436458
kprobe_flush_task(current);
437-
438-
#ifndef CONFIG_SMP
439-
if (last_task_used_math == current)
440-
last_task_used_math = NULL;
441-
#ifdef CONFIG_ALTIVEC
442-
if (last_task_used_altivec == current)
443-
last_task_used_altivec = NULL;
444-
#endif /* CONFIG_ALTIVEC */
445-
#ifdef CONFIG_SPE
446-
if (last_task_used_spe == current)
447-
last_task_used_spe = NULL;
448-
#endif
449-
#endif /* CONFIG_SMP */
459+
discard_lazy_cpu_state();
450460
}
451461

452462
void flush_thread(void)
@@ -458,18 +468,7 @@ void flush_thread(void)
458468
t->flags ^= (_TIF_ABI_PENDING | _TIF_32BIT);
459469
#endif
460470

461-
#ifndef CONFIG_SMP
462-
if (last_task_used_math == current)
463-
last_task_used_math = NULL;
464-
#ifdef CONFIG_ALTIVEC
465-
if (last_task_used_altivec == current)
466-
last_task_used_altivec = NULL;
467-
#endif /* CONFIG_ALTIVEC */
468-
#ifdef CONFIG_SPE
469-
if (last_task_used_spe == current)
470-
last_task_used_spe = NULL;
471-
#endif
472-
#endif /* CONFIG_SMP */
471+
discard_lazy_cpu_state();
473472

474473
#ifdef CONFIG_PPC64 /* for now */
475474
if (current->thread.dabr) {
@@ -635,18 +634,7 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
635634
}
636635
#endif
637636

638-
#ifndef CONFIG_SMP
639-
if (last_task_used_math == current)
640-
last_task_used_math = NULL;
641-
#ifdef CONFIG_ALTIVEC
642-
if (last_task_used_altivec == current)
643-
last_task_used_altivec = NULL;
644-
#endif
645-
#ifdef CONFIG_SPE
646-
if (last_task_used_spe == current)
647-
last_task_used_spe = NULL;
648-
#endif
649-
#endif /* CONFIG_SMP */
637+
discard_lazy_cpu_state();
650638
memset(current->thread.fpr, 0, sizeof(current->thread.fpr));
651639
current->thread.fpscr.val = 0;
652640
#ifdef CONFIG_ALTIVEC

0 commit comments

Comments
 (0)