File: /usr/src/linux/arch/sh/kernel/fpu.c

1     /* $Id: fpu.c,v 1.29 2000/03/22 13:42:10 gniibe Exp $
2      *
3      * linux/arch/sh/kernel/fpu.c
4      *
5      * Save/restore floating point context for signal handlers.
6      *
7      * This file is subject to the terms and conditions of the GNU General Public
8      * License.  See the file "COPYING" in the main directory of this archive
9      * for more details.
10      *
11      * Copyright (C) 1999, 2000  Kaz Kojima & Niibe Yutaka
12      *
13      * FIXME! These routines can be optimized in big endian case.
14      */
15     
16     #include <linux/sched.h>
17     #include <linux/signal.h>
18     #include <asm/processor.h>
19     #include <asm/io.h>
20     
21     void
22     save_fpu(struct task_struct *tsk)
23     {
24     	asm volatile("sts.l	fpul, @-%0\n\t"
25     		     "sts.l	fpscr, @-%0\n\t"
26     		     "lds	%1, fpscr\n\t"
27     		     "frchg\n\t"
28     		     "fmov.s	fr15, @-%0\n\t"
29     		     "fmov.s	fr14, @-%0\n\t"
30     		     "fmov.s	fr13, @-%0\n\t"
31     		     "fmov.s	fr12, @-%0\n\t"
32     		     "fmov.s	fr11, @-%0\n\t"
33     		     "fmov.s	fr10, @-%0\n\t"
34     		     "fmov.s	fr9, @-%0\n\t"
35     		     "fmov.s	fr8, @-%0\n\t"
36     		     "fmov.s	fr7, @-%0\n\t"
37     		     "fmov.s	fr6, @-%0\n\t"
38     		     "fmov.s	fr5, @-%0\n\t"
39     		     "fmov.s	fr4, @-%0\n\t"
40     		     "fmov.s	fr3, @-%0\n\t"
41     		     "fmov.s	fr2, @-%0\n\t"
42     		     "fmov.s	fr1, @-%0\n\t"
43     		     "fmov.s	fr0, @-%0\n\t"
44     		     "frchg\n\t"
45     		     "fmov.s	fr15, @-%0\n\t"
46     		     "fmov.s	fr14, @-%0\n\t"
47     		     "fmov.s	fr13, @-%0\n\t"
48     		     "fmov.s	fr12, @-%0\n\t"
49     		     "fmov.s	fr11, @-%0\n\t"
50     		     "fmov.s	fr10, @-%0\n\t"
51     		     "fmov.s	fr9, @-%0\n\t"
52     		     "fmov.s	fr8, @-%0\n\t"
53     		     "fmov.s	fr7, @-%0\n\t"
54     		     "fmov.s	fr6, @-%0\n\t"
55     		     "fmov.s	fr5, @-%0\n\t"
56     		     "fmov.s	fr4, @-%0\n\t"
57     		     "fmov.s	fr3, @-%0\n\t"
58     		     "fmov.s	fr2, @-%0\n\t"
59     		     "fmov.s	fr1, @-%0\n\t"
60     		     "fmov.s	fr0, @-%0"
61     		     : /* no output */
62     		     : "r" ((char *)(&tsk->thread.fpu.hard.status)),
63     		       "r" (FPSCR_INIT)
64     		     : "memory");
65     
66     	tsk->flags &= ~PF_USEDFPU;
67     	release_fpu();
68     }
69     
70     static void
71     restore_fpu(struct task_struct *tsk)
72     {
73     	asm volatile("lds	%1, fpscr\n\t"
74     		     "fmov.s	@%0+, fr0\n\t"
75     		     "fmov.s	@%0+, fr1\n\t"
76     		     "fmov.s	@%0+, fr2\n\t"
77     		     "fmov.s	@%0+, fr3\n\t"
78     		     "fmov.s	@%0+, fr4\n\t"
79     		     "fmov.s	@%0+, fr5\n\t"
80     		     "fmov.s	@%0+, fr6\n\t"
81     		     "fmov.s	@%0+, fr7\n\t"
82     		     "fmov.s	@%0+, fr8\n\t"
83     		     "fmov.s	@%0+, fr9\n\t"
84     		     "fmov.s	@%0+, fr10\n\t"
85     		     "fmov.s	@%0+, fr11\n\t"
86     		     "fmov.s	@%0+, fr12\n\t"
87     		     "fmov.s	@%0+, fr13\n\t"
88     		     "fmov.s	@%0+, fr14\n\t"
89     		     "fmov.s	@%0+, fr15\n\t"
90     		     "frchg\n\t"
91     		     "fmov.s	@%0+, fr0\n\t"
92     		     "fmov.s	@%0+, fr1\n\t"
93     		     "fmov.s	@%0+, fr2\n\t"
94     		     "fmov.s	@%0+, fr3\n\t"
95     		     "fmov.s	@%0+, fr4\n\t"
96     		     "fmov.s	@%0+, fr5\n\t"
97     		     "fmov.s	@%0+, fr6\n\t"
98     		     "fmov.s	@%0+, fr7\n\t"
99     		     "fmov.s	@%0+, fr8\n\t"
100     		     "fmov.s	@%0+, fr9\n\t"
101     		     "fmov.s	@%0+, fr10\n\t"
102     		     "fmov.s	@%0+, fr11\n\t"
103     		     "fmov.s	@%0+, fr12\n\t"
104     		     "fmov.s	@%0+, fr13\n\t"
105     		     "fmov.s	@%0+, fr14\n\t"
106     		     "fmov.s	@%0+, fr15\n\t"
107     		     "frchg\n\t"
108     		     "lds.l	@%0+, fpscr\n\t"
109     		     "lds.l	@%0+, fpul\n\t"
110     		     : /* no output */
111     		     : "r" (&tsk->thread.fpu), "r" (FPSCR_INIT)
112     		     : "memory");
113     }
114     
115     /*
116      * Load the FPU with signalling NANS.  This bit pattern we're using
117      * has the property that no matter wether considered as single or as
118      * double precission represents signaling NANS.  
119      */
120     
121     void fpu_init(void)
122     {
123     	asm volatile("lds	%0, fpul\n\t"
124     		     "lds	%1, fpscr\n\t"
125     		     "fsts	fpul, fr0\n\t"
126     		     "fsts	fpul, fr1\n\t"
127     		     "fsts	fpul, fr2\n\t"
128     		     "fsts	fpul, fr3\n\t"
129     		     "fsts	fpul, fr4\n\t"
130     		     "fsts	fpul, fr5\n\t"
131     		     "fsts	fpul, fr6\n\t"
132     		     "fsts	fpul, fr7\n\t"
133     		     "fsts	fpul, fr8\n\t"
134     		     "fsts	fpul, fr9\n\t"
135     		     "fsts	fpul, fr10\n\t"
136     		     "fsts	fpul, fr11\n\t"
137     		     "fsts	fpul, fr12\n\t"
138     		     "fsts	fpul, fr13\n\t"
139     		     "fsts	fpul, fr14\n\t"
140     		     "fsts	fpul, fr15\n\t"
141     		     "frchg\n\t"
142     		     "fsts	fpul, fr0\n\t"
143     		     "fsts	fpul, fr1\n\t"
144     		     "fsts	fpul, fr2\n\t"
145     		     "fsts	fpul, fr3\n\t"
146     		     "fsts	fpul, fr4\n\t"
147     		     "fsts	fpul, fr5\n\t"
148     		     "fsts	fpul, fr6\n\t"
149     		     "fsts	fpul, fr7\n\t"
150     		     "fsts	fpul, fr8\n\t"
151     		     "fsts	fpul, fr9\n\t"
152     		     "fsts	fpul, fr10\n\t"
153     		     "fsts	fpul, fr11\n\t"
154     		     "fsts	fpul, fr12\n\t"
155     		     "fsts	fpul, fr13\n\t"
156     		     "fsts	fpul, fr14\n\t"
157     		     "fsts	fpul, fr15\n\t"
158     		     "frchg"
159     		     : /* no output */
160     		     : "r" (0), "r" (FPSCR_INIT));
161     }
162     
163     asmlinkage void
164     do_fpu_error(unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7,
165     	     struct pt_regs regs)
166     {
167     	struct task_struct *tsk = current;
168     
169     	regs.pc += 2;
170     
171     	grab_fpu();
172     	save_fpu(tsk);
173     	tsk->thread.trap_no = 11;
174     	tsk->thread.error_code = 0;
175     	force_sig(SIGFPE, tsk);
176     }
177     
178     asmlinkage void
179     do_fpu_state_restore(unsigned long r4, unsigned long r5, unsigned long r6,
180     		     unsigned long r7, struct pt_regs regs)
181     {
182     	struct task_struct *tsk = current;
183     
184     	if (!user_mode(&regs)) {
185     		if (tsk != &init_task) {
186     			unlazy_fpu(tsk);
187     		}
188     		tsk = &init_task;
189     		if (tsk->flags & PF_USEDFPU) {
190     			/*
191     			 * This weird situation can be occurred.
192     			 *
193     			 * There's race condition in __cli:
194     			 *
195     			 *   (1) SR --> register
196     			 *   (2) Set IMASK of register
197     			 *   (3) SR <-- register
198     			 *
199     			 * Between (1) and (2), or (2) and (3) getting
200     			 * interrupt, and interrupt handler (or
201     			 * softirq) may use FPU.
202     			 *
203     			 * Then, SR.FD is overwritten by (3).
204     			 *
205     			 * This results init_task.PF_USEDFPU is on,
206     			 * with SR.FD == 1.
207     			 *
208     			 */
209     			release_fpu();
210     			return;
211     		}
212     	}
213     
214     	grab_fpu();
215     	if (tsk->used_math) {
216     		/* Using the FPU again.  */
217     		restore_fpu(tsk);
218     	} else	{
219     		/* First time FPU user.  */
220     		fpu_init();
221     		tsk->used_math = 1;
222     	}
223     	tsk->flags |= PF_USEDFPU;
224     	release_fpu();
225     }
226     
227     /*
228      * Change current FD flag to set FD flag back to exception
229      */
230     asmlinkage void
231     fpu_prepare_fd(unsigned long sr, unsigned long r5, unsigned long r6,
232     	       unsigned long r7, struct pt_regs regs)
233     {
234     	__cli();
235     	if (!user_mode(&regs)) {
236     		if (init_task.flags & PF_USEDFPU)
237     			grab_fpu();
238     		else {
239     			if (!(sr & SR_FD)) {
240     				BUG();
241     				release_fpu();
242     			}
243     		}
244     		return;
245     	}
246     
247     	if (sr & SR_FD) { /* Kernel doesn't grab FPU */
248     		if (current->flags & PF_USEDFPU)
249     			grab_fpu();
250     		else {
251     			if (init_task.flags & PF_USEDFPU) {
252     				/*
253     				 * This weird situation can be occurred.
254     				 * See the comment in do_fpu_state_restore.
255     				 */
256     				grab_fpu();
257     				save_fpu(&init_task);
258     			}
259     		}
260     	} else {
261     		if (init_task.flags & PF_USEDFPU)
262     			save_fpu(&init_task);
263     		else {
264     			BUG();
265     			release_fpu();
266     		}
267     	}
268     }
269     
270     /* Short cut for the FPU exception */
271     asmlinkage void
272     enable_fpu_in_danger(void)
273     {
274     	struct task_struct *tsk = current;
275     
276     	if (tsk != &init_task)
277     		unlazy_fpu(tsk);
278     
279     	tsk = &init_task;
280     	if (tsk->used_math) {
281     		/* Using the FPU again.  */
282     		restore_fpu(tsk);
283     	} else	{
284     		/* First time FPU user.  */
285     		fpu_init();
286     		tsk->used_math = 1;
287     	}
288     	tsk->flags |= PF_USEDFPU;
289     }
290