📄 fpu.c
字号:
/* $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>voidsave_fpu(struct task_struct *tsk){ asm volatile("sts.l $fpul, @-%0\n\t" "sts.l $fpscr, @-%0\n\t" "lds %1, $fpscr\n\t" "frchg\n\t" "fmov.s $fr15, @-%0\n\t" "fmov.s $fr14, @-%0\n\t" "fmov.s $fr13, @-%0\n\t" "fmov.s $fr12, @-%0\n\t" "fmov.s $fr11, @-%0\n\t" "fmov.s $fr10, @-%0\n\t" "fmov.s $fr9, @-%0\n\t" "fmov.s $fr8, @-%0\n\t" "fmov.s $fr7, @-%0\n\t" "fmov.s $fr6, @-%0\n\t" "fmov.s $fr5, @-%0\n\t" "fmov.s $fr4, @-%0\n\t" "fmov.s $fr3, @-%0\n\t" "fmov.s $fr2, @-%0\n\t" "fmov.s $fr1, @-%0\n\t" "fmov.s $fr0, @-%0\n\t" "frchg\n\t" "fmov.s $fr15, @-%0\n\t" "fmov.s $fr14, @-%0\n\t" "fmov.s $fr13, @-%0\n\t" "fmov.s $fr12, @-%0\n\t" "fmov.s $fr11, @-%0\n\t" "fmov.s $fr10, @-%0\n\t" "fmov.s $fr9, @-%0\n\t" "fmov.s $fr8, @-%0\n\t" "fmov.s $fr7, @-%0\n\t" "fmov.s $fr6, @-%0\n\t" "fmov.s $fr5, @-%0\n\t" "fmov.s $fr4, @-%0\n\t" "fmov.s $fr3, @-%0\n\t" "fmov.s $fr2, @-%0\n\t" "fmov.s $fr1, @-%0\n\t" "fmov.s $fr0, @-%0" : /* no output */ : "r" ((char *)(&tsk->thread.fpu.hard.status)), "r" (FPSCR_INIT) : "memory"); tsk->flags &= ~PF_USEDFPU; release_fpu();}static voidrestore_fpu(struct task_struct *tsk){ asm volatile("lds %1, $fpscr\n\t" "fmov.s @%0+, $fr0\n\t" "fmov.s @%0+, $fr1\n\t" "fmov.s @%0+, $fr2\n\t" "fmov.s @%0+, $fr3\n\t" "fmov.s @%0+, $fr4\n\t" "fmov.s @%0+, $fr5\n\t" "fmov.s @%0+, $fr6\n\t" "fmov.s @%0+, $fr7\n\t" "fmov.s @%0+, $fr8\n\t" "fmov.s @%0+, $fr9\n\t" "fmov.s @%0+, $fr10\n\t" "fmov.s @%0+, $fr11\n\t" "fmov.s @%0+, $fr12\n\t" "fmov.s @%0+, $fr13\n\t" "fmov.s @%0+, $fr14\n\t" "fmov.s @%0+, $fr15\n\t" "frchg\n\t" "fmov.s @%0+, $fr0\n\t" "fmov.s @%0+, $fr1\n\t" "fmov.s @%0+, $fr2\n\t" "fmov.s @%0+, $fr3\n\t" "fmov.s @%0+, $fr4\n\t" "fmov.s @%0+, $fr5\n\t" "fmov.s @%0+, $fr6\n\t" "fmov.s @%0+, $fr7\n\t" "fmov.s @%0+, $fr8\n\t" "fmov.s @%0+, $fr9\n\t" "fmov.s @%0+, $fr10\n\t" "fmov.s @%0+, $fr11\n\t" "fmov.s @%0+, $fr12\n\t" "fmov.s @%0+, $fr13\n\t" "fmov.s @%0+, $fr14\n\t" "fmov.s @%0+, $fr15\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_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, $fpul\n\t" "lds %1, $fpscr\n\t" "fsts $fpul, $fr0\n\t" "fsts $fpul, $fr1\n\t" "fsts $fpul, $fr2\n\t" "fsts $fpul, $fr3\n\t" "fsts $fpul, $fr4\n\t" "fsts $fpul, $fr5\n\t" "fsts $fpul, $fr6\n\t" "fsts $fpul, $fr7\n\t" "fsts $fpul, $fr8\n\t" "fsts $fpul, $fr9\n\t" "fsts $fpul, $fr10\n\t" "fsts $fpul, $fr11\n\t" "fsts $fpul, $fr12\n\t" "fsts $fpul, $fr13\n\t" "fsts $fpul, $fr14\n\t" "fsts $fpul, $fr15\n\t" "frchg\n\t" "fsts $fpul, $fr0\n\t" "fsts $fpul, $fr1\n\t" "fsts $fpul, $fr2\n\t" "fsts $fpul, $fr3\n\t" "fsts $fpul, $fr4\n\t" "fsts $fpul, $fr5\n\t" "fsts $fpul, $fr6\n\t" "fsts $fpul, $fr7\n\t" "fsts $fpul, $fr8\n\t" "fsts $fpul, $fr9\n\t" "fsts $fpul, $fr10\n\t" "fsts $fpul, $fr11\n\t" "fsts $fpul, $fr12\n\t" "fsts $fpul, $fr13\n\t" "fsts $fpul, $fr14\n\t" "fsts $fpul, $fr15\n\t" "frchg" : /* no output */ : "r" (0), "r" (FPSCR_INIT));}asmlinkage voiddo_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 voiddo_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 voidfpu_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 voidenable_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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -