fpu.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:7k
- /* $Id: fpu.c,v 1.29 2000/03/22 13:42:10 gniibe Exp $
- *
- * linux/arch/sh/kernel/fpu.c
- *
- * Save/restore floating point context for signal handlers.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka
- *
- * FIXME! These routines can be optimized in big endian case.
- */
- #include <linux/sched.h>
- #include <linux/signal.h>
- #include <asm/processor.h>
- #include <asm/io.h>
- void
- save_fpu(struct task_struct *tsk)
- {
- asm volatile("sts.l fpul, @-%0nt"
- "sts.l fpscr, @-%0nt"
- "lds %1, fpscrnt"
- "frchgnt"
- "fmov.s fr15, @-%0nt"
- "fmov.s fr14, @-%0nt"
- "fmov.s fr13, @-%0nt"
- "fmov.s fr12, @-%0nt"
- "fmov.s fr11, @-%0nt"
- "fmov.s fr10, @-%0nt"
- "fmov.s fr9, @-%0nt"
- "fmov.s fr8, @-%0nt"
- "fmov.s fr7, @-%0nt"
- "fmov.s fr6, @-%0nt"
- "fmov.s fr5, @-%0nt"
- "fmov.s fr4, @-%0nt"
- "fmov.s fr3, @-%0nt"
- "fmov.s fr2, @-%0nt"
- "fmov.s fr1, @-%0nt"
- "fmov.s fr0, @-%0nt"
- "frchgnt"
- "fmov.s fr15, @-%0nt"
- "fmov.s fr14, @-%0nt"
- "fmov.s fr13, @-%0nt"
- "fmov.s fr12, @-%0nt"
- "fmov.s fr11, @-%0nt"
- "fmov.s fr10, @-%0nt"
- "fmov.s fr9, @-%0nt"
- "fmov.s fr8, @-%0nt"
- "fmov.s fr7, @-%0nt"
- "fmov.s fr6, @-%0nt"
- "fmov.s fr5, @-%0nt"
- "fmov.s fr4, @-%0nt"
- "fmov.s fr3, @-%0nt"
- "fmov.s fr2, @-%0nt"
- "fmov.s fr1, @-%0nt"
- "fmov.s fr0, @-%0"
- : /* no output */
- : "r" ((char *)(&tsk->thread.fpu.hard.status)),
- "r" (FPSCR_INIT)
- : "memory");
- tsk->flags &= ~PF_USEDFPU;
- release_fpu();
- }
- static void
- restore_fpu(struct task_struct *tsk)
- {
- asm volatile("lds %1, fpscrnt"
- "fmov.s @%0+, fr0nt"
- "fmov.s @%0+, fr1nt"
- "fmov.s @%0+, fr2nt"
- "fmov.s @%0+, fr3nt"
- "fmov.s @%0+, fr4nt"
- "fmov.s @%0+, fr5nt"
- "fmov.s @%0+, fr6nt"
- "fmov.s @%0+, fr7nt"
- "fmov.s @%0+, fr8nt"
- "fmov.s @%0+, fr9nt"
- "fmov.s @%0+, fr10nt"
- "fmov.s @%0+, fr11nt"
- "fmov.s @%0+, fr12nt"
- "fmov.s @%0+, fr13nt"
- "fmov.s @%0+, fr14nt"
- "fmov.s @%0+, fr15nt"
- "frchgnt"
- "fmov.s @%0+, fr0nt"
- "fmov.s @%0+, fr1nt"
- "fmov.s @%0+, fr2nt"
- "fmov.s @%0+, fr3nt"
- "fmov.s @%0+, fr4nt"
- "fmov.s @%0+, fr5nt"
- "fmov.s @%0+, fr6nt"
- "fmov.s @%0+, fr7nt"
- "fmov.s @%0+, fr8nt"
- "fmov.s @%0+, fr9nt"
- "fmov.s @%0+, fr10nt"
- "fmov.s @%0+, fr11nt"
- "fmov.s @%0+, fr12nt"
- "fmov.s @%0+, fr13nt"
- "fmov.s @%0+, fr14nt"
- "fmov.s @%0+, fr15nt"
- "frchgnt"
- "lds.l @%0+, fpscrnt"
- "lds.l @%0+, fpulnt"
- : /* no output */
- : "r" (&tsk->thread.fpu), "r" (FPSCR_INIT)
- : "memory");
- }
- /*
- * Load the FPU with signalling NANS. This bit pattern we're using
- * has the property that no matter wether considered as single or as
- * double precission represents signaling NANS.
- */
- void fpu_init(void)
- {
- asm volatile("lds %0, fpulnt"
- "lds %1, fpscrnt"
- "fsts fpul, fr0nt"
- "fsts fpul, fr1nt"
- "fsts fpul, fr2nt"
- "fsts fpul, fr3nt"
- "fsts fpul, fr4nt"
- "fsts fpul, fr5nt"
- "fsts fpul, fr6nt"
- "fsts fpul, fr7nt"
- "fsts fpul, fr8nt"
- "fsts fpul, fr9nt"
- "fsts fpul, fr10nt"
- "fsts fpul, fr11nt"
- "fsts fpul, fr12nt"
- "fsts fpul, fr13nt"
- "fsts fpul, fr14nt"
- "fsts fpul, fr15nt"
- "frchgnt"
- "fsts fpul, fr0nt"
- "fsts fpul, fr1nt"
- "fsts fpul, fr2nt"
- "fsts fpul, fr3nt"
- "fsts fpul, fr4nt"
- "fsts fpul, fr5nt"
- "fsts fpul, fr6nt"
- "fsts fpul, fr7nt"
- "fsts fpul, fr8nt"
- "fsts fpul, fr9nt"
- "fsts fpul, fr10nt"
- "fsts fpul, fr11nt"
- "fsts fpul, fr12nt"
- "fsts fpul, fr13nt"
- "fsts fpul, fr14nt"
- "fsts fpul, fr15nt"
- "frchg"
- : /* no output */
- : "r" (0), "r" (FPSCR_INIT));
- }
- asmlinkage void
- do_fpu_error(unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7,
- struct pt_regs regs)
- {
- struct task_struct *tsk = current;
- regs.pc += 2;
- grab_fpu();
- save_fpu(tsk);
- tsk->thread.trap_no = 11;
- tsk->thread.error_code = 0;
- force_sig(SIGFPE, tsk);
- }
- asmlinkage void
- do_fpu_state_restore(unsigned long r4, unsigned long r5, unsigned long r6,
- unsigned long r7, struct pt_regs regs)
- {
- struct task_struct *tsk = current;
- if (!user_mode(®s)) {
- if (tsk != &init_task) {
- unlazy_fpu(tsk);
- }
- tsk = &init_task;
- if (tsk->flags & PF_USEDFPU) {
- /*
- * This weird situation can be occurred.
- *
- * There's race condition in __cli:
- *
- * (1) SR --> register
- * (2) Set IMASK of register
- * (3) SR <-- register
- *
- * Between (1) and (2), or (2) and (3) getting
- * interrupt, and interrupt handler (or
- * softirq) may use FPU.
- *
- * Then, SR.FD is overwritten by (3).
- *
- * This results init_task.PF_USEDFPU is on,
- * with SR.FD == 1.
- *
- */
- release_fpu();
- return;
- }
- }
- grab_fpu();
- if (tsk->used_math) {
- /* Using the FPU again. */
- restore_fpu(tsk);
- } else {
- /* First time FPU user. */
- fpu_init();
- tsk->used_math = 1;
- }
- tsk->flags |= PF_USEDFPU;
- release_fpu();
- }
- /*
- * Change current FD flag to set FD flag back to exception
- */
- asmlinkage void
- fpu_prepare_fd(unsigned long sr, unsigned long r5, unsigned long r6,
- unsigned long r7, struct pt_regs regs)
- {
- __cli();
- if (!user_mode(®s)) {
- if (init_task.flags & PF_USEDFPU)
- grab_fpu();
- else {
- if (!(sr & SR_FD)) {
- BUG();
- release_fpu();
- }
- }
- return;
- }
- if (sr & SR_FD) { /* Kernel doesn't grab FPU */
- if (current->flags & PF_USEDFPU)
- grab_fpu();
- else {
- if (init_task.flags & PF_USEDFPU) {
- /*
- * This weird situation can be occurred.
- * See the comment in do_fpu_state_restore.
- */
- grab_fpu();
- save_fpu(&init_task);
- }
- }
- } else {
- if (init_task.flags & PF_USEDFPU)
- save_fpu(&init_task);
- else {
- BUG();
- release_fpu();
- }
- }
- }
- /* Short cut for the FPU exception */
- asmlinkage void
- enable_fpu_in_danger(void)
- {
- struct task_struct *tsk = current;
- if (tsk != &init_task)
- unlazy_fpu(tsk);
- tsk = &init_task;
- if (tsk->used_math) {
- /* Using the FPU again. */
- restore_fpu(tsk);
- } else {
- /* First time FPU user. */
- fpu_init();
- tsk->used_math = 1;
- }
- tsk->flags |= PF_USEDFPU;
- }