if (fpu_disabled) {
printk("FPU Disabled\n");
cpu_data->flags &= ~CPU_HAS_FPU;
- release_fpu();
+ disable_fpu();
}
/* FPU initialization */
-/* $Id: fpu.c,v 1.3 2003/09/23 23:15:44 lethal Exp $
+/* $Id: fpu.c,v 1.4 2004/01/13 05:52:11 kkojima Exp $
*
* linux/arch/sh/kernel/fpu.c
*
* Assume called with FPU enabled (SR.FD=0).
*/
void
-save_fpu(struct task_struct *tsk)
+save_fpu(struct task_struct *tsk, struct pt_regs *regs)
{
+ unsigned long dummy;
+
+ clear_tsk_thread_flag(tsk, TIF_USEDFPU);
+ enable_fpu();
asm volatile("sts.l fpul, @-%0\n\t"
"sts.l fpscr, @-%0\n\t"
- "lds %1, fpscr\n\t"
+ "lds %2, fpscr\n\t"
"frchg\n\t"
"fmov.s fr15, @-%0\n\t"
"fmov.s fr14, @-%0\n\t"
"fmov.s fr2, @-%0\n\t"
"fmov.s fr1, @-%0\n\t"
"fmov.s fr0, @-%0\n\t"
- "lds %2, fpscr\n\t"
- : /* no output */
- : "r" ((char *)(&tsk->thread.fpu.hard.status)),
+ "lds %3, fpscr\n\t"
+ : "=r" (dummy)
+ : "0" ((char *)(&tsk->thread.fpu.hard.status)),
"r" (FPSCR_RCHG),
"r" (FPSCR_INIT)
: "memory");
- clear_tsk_thread_flag(tsk, TIF_USEDFPU);
- release_fpu();
+ disable_fpu();
+ release_fpu(regs);
}
static void
restore_fpu(struct task_struct *tsk)
{
- asm volatile("lds %1, fpscr\n\t"
+ unsigned long dummy;
+
+ enable_fpu();
+ asm volatile("lds %2, fpscr\n\t"
"fmov.s @%0+, fr0\n\t"
"fmov.s @%0+, fr1\n\t"
"fmov.s @%0+, fr2\n\t"
"frchg\n\t"
"lds.l @%0+, fpscr\n\t"
"lds.l @%0+, fpul\n\t"
- : /* no output */
- : "r" (&tsk->thread.fpu), "r" (FPSCR_RCHG)
+ : "=r" (dummy)
+ : "0" (&tsk->thread.fpu), "r" (FPSCR_RCHG)
: "memory");
+ disable_fpu();
}
/*
static void
fpu_init(void)
{
+ enable_fpu();
asm volatile("lds %0, fpul\n\t"
"lds %1, fpscr\n\t"
"fsts fpul, fr0\n\t"
"lds %2, fpscr\n\t"
: /* no output */
: "r" (0), "r" (FPSCR_RCHG), "r" (FPSCR_INIT));
+ disable_fpu();
}
/**
if ((finsn & 0xf1ff) == 0xf0ad) { /* fcnvsd */
struct task_struct *tsk = current;
- save_fpu(tsk);
+ save_fpu(tsk, regs);
if ((tsk->thread.fpu.hard.fpscr & (1 << 17))) {
/* FPU error */
denormal_to_double (&tsk->thread.fpu.hard,
(finsn >> 8) & 0xf);
tsk->thread.fpu.hard.fpscr &=
~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK);
- grab_fpu();
+ grab_fpu(regs);
restore_fpu(tsk);
set_tsk_thread_flag(tsk, TIF_USEDFPU);
} else {
return;
regs.pc += 2;
- save_fpu(tsk);
+ save_fpu(tsk, ®s);
tsk->thread.trap_no = 11;
tsk->thread.error_code = 0;
force_sig(SIGFPE, tsk);
{
struct task_struct *tsk = current;
- grab_fpu();
+ grab_fpu(®s);
if (!user_mode(®s)) {
printk(KERN_ERR "BUG: FPU is used in kernel mode.\n");
return;
-/* $Id: process.c,v 1.24 2003/11/28 23:05:43 kkojima Exp $
+/* $Id: process.c,v 1.25 2004/01/13 05:52:11 kkojima Exp $
*
* linux/arch/sh/kernel/process.c
*
{
#if defined(CONFIG_CPU_SH4)
struct task_struct *tsk = current;
+ struct pt_regs *regs = (struct pt_regs *)
+ ((unsigned long)tsk->thread_info
+ + THREAD_SIZE - sizeof(struct pt_regs)
+ - sizeof(unsigned long));
/* Forget lazy FPU state */
- clear_fpu(tsk);
+ clear_fpu(tsk, regs);
tsk->used_math = 0;
#endif
}
fpvalid = tsk->used_math;
if (fpvalid) {
- unlazy_fpu(tsk);
+ unlazy_fpu(tsk, regs);
memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu));
}
#endif
struct pt_regs ptregs;
ptregs = *(struct pt_regs *)
- ((unsigned long)tsk->thread_info+THREAD_SIZE - sizeof(ptregs)
+ ((unsigned long)tsk->thread_info + THREAD_SIZE
+ - sizeof(struct pt_regs)
#ifdef CONFIG_SH_DSP
- sizeof(struct pt_dspregs)
#endif
#if defined(CONFIG_CPU_SH4)
fpvalid = tsk->used_math;
if (fpvalid) {
- unlazy_fpu(tsk);
+ struct pt_regs *regs = (struct pt_regs *)
+ ((unsigned long)tsk->thread_info
+ + THREAD_SIZE - sizeof(struct pt_regs)
+ - sizeof(unsigned long));
+ unlazy_fpu(tsk, regs);
memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu));
}
#endif
if (user_mode(regs)) {
childregs->regs[15] = usp;
} else {
- childregs->regs[15] = (unsigned long)p->thread_info+THREAD_SIZE;
+ childregs->regs[15] = (unsigned long)p->thread_info + THREAD_SIZE;
}
if (clone_flags & CLONE_SETTLS) {
childregs->gbr = childregs->regs[0];
}
childregs->regs[0] = 0; /* Set return value for child */
- childregs->sr |= SR_FD; /* Invalidate FPU flag */
p->set_child_tid = p->clear_child_tid = NULL;
p->thread.sp = (unsigned long) childregs;
{
struct task_struct *tsk = current;
- unlazy_fpu(tsk);
+ unlazy_fpu(tsk, regs);
p->thread.fpu = tsk->thread.fpu;
p->used_math = tsk->used_math;
clear_ti_thread_flag(p->thread_info, TIF_USEDFPU);
struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *next)
{
#if defined(CONFIG_CPU_SH4)
- unlazy_fpu(prev);
+ struct pt_regs *regs = (struct pt_regs *)
+ ((unsigned long)prev->thread_info
+ + THREAD_SIZE - sizeof(struct pt_regs)
+ - sizeof(unsigned long));
+ unlazy_fpu(prev, regs);
#endif
+
+#ifdef CONFIG_PREEMPT
+ {
+ unsigned long flags;
+ struct pt_regs *regs;
+
+ local_irq_save(flags);
+ regs = (struct pt_regs *)
+ ((unsigned long)prev->thread_info
+ + THREAD_SIZE - sizeof(struct pt_regs)
+#ifdef CONFIG_SH_DSP
+ - sizeof(struct pt_dspregs)
+#endif
+ - sizeof(unsigned long));
+ if (user_mode(regs) && regs->regs[15] >= 0xc0000000) {
+ int offset = (int)regs->regs[15];
+
+ /* Reset stack pointer: clear critical region mark */
+ regs->regs[15] = regs->regs[1];
+ if (regs->pc < regs->regs[0])
+ /* Go to rewind point */
+ regs->pc = regs->regs[0] + offset;
+ }
+ local_irq_restore(flags);
+ }
+#endif
+
/*
* Restore the kernel mode register
* k7 (r7_bank1)
-/* $Id: signal.c,v 1.19 2003/10/13 07:21:19 lethal Exp $
+/* $Id: signal.c,v 1.20 2004/01/13 05:52:11 kkojima Exp $
*
* linux/arch/sh/kernel/signal.c
*
sizeof(long)*(16*2+2));
}
-static inline int save_sigcontext_fpu(struct sigcontext __user *sc)
+static inline int save_sigcontext_fpu(struct sigcontext __user *sc,
+ struct pt_regs *regs)
{
struct task_struct *tsk = current;
*/
tsk->used_math = 0;
- unlazy_fpu(tsk);
+ unlazy_fpu(tsk, regs);
return __copy_to_user(&sc->sc_fpregs[0], &tsk->thread.fpu.hard,
sizeof(long)*(16*2+2));
}
struct task_struct *tsk = current;
regs->sr |= SR_FD; /* Release FPU */
- clear_fpu(tsk);
+ clear_fpu(tsk, regs);
tsk->used_math = 0;
__get_user (owned_fp, &sc->sc_ownedfp);
if (owned_fp)
#undef COPY
#ifdef CONFIG_CPU_SH4
- err |= save_sigcontext_fpu(sc);
+ err |= save_sigcontext_fpu(sc, regs);
#endif
/* non-iBCS2 extensions.. */
case -ERESTARTNOINTR:
regs->pc -= 2;
}
-#ifndef CONFIG_PREEMPT
} else {
/* gUSA handling */
+#ifdef CONFIG_PREEMPT
+ unsigned long flags;
+
+ local_irq_save(flags);
+#endif
if (regs->regs[15] >= 0xc0000000) {
int offset = (int)regs->regs[15];
/* Go to rewind point #1 */
regs->pc = regs->regs[0] + offset - 2;
}
+#ifdef CONFIG_PREEMPT
+ local_irq_restore(flags);
#endif
}
#include <asm/types.h>
#include <asm/cache.h>
#include <linux/threads.h>
+#include <asm/ptrace.h>
/*
* Default implementation of macro that returns current
#define start_thread(regs, new_pc, new_sp) \
set_fs(USER_DS); \
regs->pr = 0; \
- regs->sr = 0; /* User mode. */ \
+ regs->sr = SR_FD; /* User mode. */ \
regs->pc = new_pc; \
regs->regs[15] = new_sp
* FPU lazy state save handling.
*/
-static __inline__ void release_fpu(void)
+static __inline__ void disable_fpu(void)
{
unsigned long __dummy;
: "r" (SR_FD));
}
-static __inline__ void grab_fpu(void)
+static __inline__ void enable_fpu(void)
{
unsigned long __dummy;
: "r" (~SR_FD));
}
+static __inline__ void release_fpu(struct pt_regs *regs)
+{
+ regs->sr |= SR_FD;
+}
+
+static __inline__ void grab_fpu(struct pt_regs *regs)
+{
+ regs->sr &= ~SR_FD;
+}
+
#ifdef CONFIG_CPU_SH4
-extern void save_fpu(struct task_struct *__tsk);
+extern void save_fpu(struct task_struct *__tsk, struct pt_regs *regs);
#else
#define save_fpu(tsk) do { } while (0)
#endif
-#define unlazy_fpu(tsk) do { \
+#define unlazy_fpu(tsk, regs) do { \
if (test_tsk_thread_flag(tsk, TIF_USEDFPU)) { \
- save_fpu(tsk); \
+ save_fpu(tsk, regs); \
} \
} while (0)
-#define clear_fpu(tsk) do { \
+#define clear_fpu(tsk, regs) do { \
if (test_tsk_thread_flag(tsk, TIF_USEDFPU)) { \
clear_tsk_thread_flag(tsk, TIF_USEDFPU); \
- release_fpu(); \
+ release_fpu(regs); \
} \
} while (0)
#ifndef __ASM_SH_PTRACE_H
#define __ASM_SH_PTRACE_H
-#include <asm/processor.h>
#include <asm/ubc.h>
/*