Skip to content

Commit

Permalink
sh: Fix occasional FPU register corruption under preempt.
Browse files Browse the repository at this point in the history
Presently with preempt enabled there's the possibility to be preempted
after the TIF_USEDFPU test and the register save, leading to bogus
state post-__switch_to(). Use an explicit preempt_disable()/enable()
pair around unlazy_fpu()/clear_fpu() to avoid this. Follows the x86
change.

Reported-by: Takuo Koguchi <takuo.koguchi.sw@hitachi.com>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
  • Loading branch information
Paul Mundt committed Mar 26, 2008
1 parent 05dda97 commit 9bbafce
Show file tree
Hide file tree
Showing 10 changed files with 26 additions and 15 deletions.
1 change: 1 addition & 0 deletions arch/sh/kernel/cpu/sh2a/fpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <linux/signal.h>
#include <asm/processor.h>
#include <asm/io.h>
#include <asm/fpu.h>

/* The PR (precision) bit in the FP Status Register must be clear when
* an frchg instruction is executed, otherwise the instruction is undefined.
Expand Down
1 change: 1 addition & 0 deletions arch/sh/kernel/cpu/sh4/fpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <asm/cpu/fpu.h>
#include <asm/processor.h>
#include <asm/system.h>
#include <asm/fpu.h>

/* The PR (precision) bit in the FP Status Register must be clear when
* an frchg instruction is executed, otherwise the instruction is undefined.
Expand Down
1 change: 1 addition & 0 deletions arch/sh/kernel/cpu/sh5/fpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <asm/processor.h>
#include <asm/user.h>
#include <asm/io.h>
#include <asm/fpu.h>

/*
* Initially load the FPU with signalling NANS. This bit pattern
Expand Down
1 change: 1 addition & 0 deletions arch/sh/kernel/dump_task.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <linux/elfcore.h>
#include <linux/sched.h>
#include <asm/fpu.h>

/*
* Capture the user space registers if the task is not running (in user space)
Expand Down
1 change: 1 addition & 0 deletions arch/sh/kernel/process_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <asm/pgalloc.h>
#include <asm/system.h>
#include <asm/ubc.h>
#include <asm/fpu.h>

static int hlt_counter;
int ubc_usercnt = 0;
Expand Down
1 change: 1 addition & 0 deletions arch/sh/kernel/signal_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/cacheflush.h>
#include <asm/fpu.h>

#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))

Expand Down
32 changes: 18 additions & 14 deletions include/asm-sh/fpu.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
#ifndef __ASM_SH_FPU_H
#define __ASM_SH_FPU_H

#define SR_FD 0x00008000

#ifndef __ASSEMBLY__
#include <linux/preempt.h>
#include <asm/ptrace.h>

#ifdef CONFIG_SH_FPU
Expand All @@ -28,18 +27,23 @@ extern void save_fpu(struct task_struct *__tsk, struct pt_regs *regs);

extern int do_fpu_inst(unsigned short, struct pt_regs *);

#define unlazy_fpu(tsk, regs) do { \
if (test_tsk_thread_flag(tsk, TIF_USEDFPU)) { \
save_fpu(tsk, regs); \
} \
} while (0)

#define clear_fpu(tsk, regs) do { \
if (test_tsk_thread_flag(tsk, TIF_USEDFPU)) { \
clear_tsk_thread_flag(tsk, TIF_USEDFPU); \
release_fpu(regs); \
} \
} while (0)
static inline void unlazy_fpu(struct task_struct *tsk, struct pt_regs *regs)
{
preempt_disable();
if (test_tsk_thread_flag(tsk, TIF_USEDFPU))
save_fpu(tsk, regs);
preempt_enable();
}

static inline void clear_fpu(struct task_struct *tsk, struct pt_regs *regs)
{
preempt_disable();
if (test_tsk_thread_flag(tsk, TIF_USEDFPU)) {
clear_tsk_thread_flag(tsk, TIF_USEDFPU);
release_fpu(regs);
}
preempt_enable();
}

#endif /* __ASSEMBLY__ */

Expand Down
1 change: 0 additions & 1 deletion include/asm-sh/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
#define __ASM_SH_PROCESSOR_H

#include <asm/cpu-features.h>
#include <asm/fpu.h>

#ifndef __ASSEMBLY__
/*
Expand Down
1 change: 1 addition & 0 deletions include/asm-sh/processor_32.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ extern struct sh_cpuinfo cpu_data[];
*/
#define SR_DSP 0x00001000
#define SR_IMASK 0x000000f0
#define SR_FD 0x00008000

/*
* FPU structure and data
Expand Down
1 change: 1 addition & 0 deletions include/asm-sh/processor_64.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ extern struct sh_cpuinfo cpu_data[];
#endif

#define SR_IMASK 0x000000f0
#define SR_FD 0x00008000
#define SR_SSTEP 0x08000000

#ifndef __ASSEMBLY__
Expand Down

0 comments on commit 9bbafce

Please sign in to comment.