]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * This file is subject to the terms and conditions of the GNU General Public | |
3 | * License. See the file "COPYING" in the main directory of this archive | |
4 | * for more details. | |
5 | * | |
6 | * arch/sh64/kernel/fpu.c | |
7 | * | |
8 | * Copyright (C) 2001 Manuela Cirronis, Paolo Alberelli | |
9 | * Copyright (C) 2002 STMicroelectronics Limited | |
10 | * Author : Stuart Menefy | |
11 | * | |
12 | * Started from SH4 version: | |
13 | * Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka | |
14 | * | |
15 | */ | |
16 | ||
17 | #include <linux/sched.h> | |
18 | #include <linux/signal.h> | |
19 | #include <asm/processor.h> | |
20 | #include <asm/user.h> | |
21 | #include <asm/io.h> | |
22 | ||
23 | /* | |
24 | * Initially load the FPU with signalling NANS. This bit pattern | |
25 | * has the property that no matter whether considered as single or as | |
26 | * double precision, it still represents a signalling NAN. | |
27 | */ | |
28 | #define sNAN64 0xFFFFFFFFFFFFFFFFULL | |
29 | #define sNAN32 0xFFFFFFFFUL | |
30 | ||
31 | static union sh_fpu_union init_fpuregs = { | |
32 | .hard = { | |
332fd57b PM |
33 | .fp_regs = { [0 ... 63] = sNAN32 }, |
34 | .fpscr = FPSCR_INIT | |
1da177e4 LT |
35 | } |
36 | }; | |
37 | ||
332fd57b | 38 | void save_fpu(struct task_struct *tsk, struct pt_regs *regs) |
1da177e4 LT |
39 | { |
40 | asm volatile("fst.p %0, (0*8), fp0\n\t" | |
41 | "fst.p %0, (1*8), fp2\n\t" | |
42 | "fst.p %0, (2*8), fp4\n\t" | |
43 | "fst.p %0, (3*8), fp6\n\t" | |
44 | "fst.p %0, (4*8), fp8\n\t" | |
45 | "fst.p %0, (5*8), fp10\n\t" | |
46 | "fst.p %0, (6*8), fp12\n\t" | |
47 | "fst.p %0, (7*8), fp14\n\t" | |
48 | "fst.p %0, (8*8), fp16\n\t" | |
49 | "fst.p %0, (9*8), fp18\n\t" | |
50 | "fst.p %0, (10*8), fp20\n\t" | |
51 | "fst.p %0, (11*8), fp22\n\t" | |
52 | "fst.p %0, (12*8), fp24\n\t" | |
53 | "fst.p %0, (13*8), fp26\n\t" | |
54 | "fst.p %0, (14*8), fp28\n\t" | |
55 | "fst.p %0, (15*8), fp30\n\t" | |
56 | "fst.p %0, (16*8), fp32\n\t" | |
57 | "fst.p %0, (17*8), fp34\n\t" | |
58 | "fst.p %0, (18*8), fp36\n\t" | |
59 | "fst.p %0, (19*8), fp38\n\t" | |
60 | "fst.p %0, (20*8), fp40\n\t" | |
61 | "fst.p %0, (21*8), fp42\n\t" | |
62 | "fst.p %0, (22*8), fp44\n\t" | |
63 | "fst.p %0, (23*8), fp46\n\t" | |
64 | "fst.p %0, (24*8), fp48\n\t" | |
65 | "fst.p %0, (25*8), fp50\n\t" | |
66 | "fst.p %0, (26*8), fp52\n\t" | |
67 | "fst.p %0, (27*8), fp54\n\t" | |
68 | "fst.p %0, (28*8), fp56\n\t" | |
69 | "fst.p %0, (29*8), fp58\n\t" | |
70 | "fst.p %0, (30*8), fp60\n\t" | |
71 | "fst.p %0, (31*8), fp62\n\t" | |
72 | ||
73 | "fgetscr fr63\n\t" | |
74 | "fst.s %0, (32*8), fr63\n\t" | |
75 | : /* no output */ | |
332fd57b | 76 | : "r" (&tsk->thread.fpu.hard) |
1da177e4 LT |
77 | : "memory"); |
78 | } | |
79 | ||
1da177e4 LT |
80 | static inline void |
81 | fpload(struct sh_fpu_hard_struct *fpregs) | |
82 | { | |
83 | asm volatile("fld.p %0, (0*8), fp0\n\t" | |
84 | "fld.p %0, (1*8), fp2\n\t" | |
85 | "fld.p %0, (2*8), fp4\n\t" | |
86 | "fld.p %0, (3*8), fp6\n\t" | |
87 | "fld.p %0, (4*8), fp8\n\t" | |
88 | "fld.p %0, (5*8), fp10\n\t" | |
89 | "fld.p %0, (6*8), fp12\n\t" | |
90 | "fld.p %0, (7*8), fp14\n\t" | |
91 | "fld.p %0, (8*8), fp16\n\t" | |
92 | "fld.p %0, (9*8), fp18\n\t" | |
93 | "fld.p %0, (10*8), fp20\n\t" | |
94 | "fld.p %0, (11*8), fp22\n\t" | |
95 | "fld.p %0, (12*8), fp24\n\t" | |
96 | "fld.p %0, (13*8), fp26\n\t" | |
97 | "fld.p %0, (14*8), fp28\n\t" | |
98 | "fld.p %0, (15*8), fp30\n\t" | |
99 | "fld.p %0, (16*8), fp32\n\t" | |
100 | "fld.p %0, (17*8), fp34\n\t" | |
101 | "fld.p %0, (18*8), fp36\n\t" | |
102 | "fld.p %0, (19*8), fp38\n\t" | |
103 | "fld.p %0, (20*8), fp40\n\t" | |
104 | "fld.p %0, (21*8), fp42\n\t" | |
105 | "fld.p %0, (22*8), fp44\n\t" | |
106 | "fld.p %0, (23*8), fp46\n\t" | |
107 | "fld.p %0, (24*8), fp48\n\t" | |
108 | "fld.p %0, (25*8), fp50\n\t" | |
109 | "fld.p %0, (26*8), fp52\n\t" | |
110 | "fld.p %0, (27*8), fp54\n\t" | |
111 | "fld.p %0, (28*8), fp56\n\t" | |
112 | "fld.p %0, (29*8), fp58\n\t" | |
113 | "fld.p %0, (30*8), fp60\n\t" | |
114 | ||
115 | "fld.s %0, (32*8), fr63\n\t" | |
116 | "fputscr fr63\n\t" | |
117 | ||
118 | "fld.p %0, (31*8), fp62\n\t" | |
119 | : /* no output */ | |
120 | : "r" (fpregs) ); | |
121 | } | |
122 | ||
123 | void fpinit(struct sh_fpu_hard_struct *fpregs) | |
124 | { | |
125 | *fpregs = init_fpuregs.hard; | |
126 | } | |
127 | ||
128 | asmlinkage void | |
129 | do_fpu_error(unsigned long ex, struct pt_regs *regs) | |
130 | { | |
131 | struct task_struct *tsk = current; | |
132 | ||
133 | regs->pc += 4; | |
134 | ||
135 | tsk->thread.trap_no = 11; | |
136 | tsk->thread.error_code = 0; | |
137 | force_sig(SIGFPE, tsk); | |
138 | } | |
139 | ||
140 | ||
141 | asmlinkage void | |
142 | do_fpu_state_restore(unsigned long ex, struct pt_regs *regs) | |
143 | { | |
144 | void die(const char *str, struct pt_regs *regs, long err); | |
145 | ||
146 | if (! user_mode(regs)) | |
147 | die("FPU used in kernel", regs, ex); | |
148 | ||
149 | regs->sr &= ~SR_FD; | |
150 | ||
151 | if (last_task_used_math == current) | |
152 | return; | |
153 | ||
600ee240 | 154 | enable_fpu(); |
332fd57b | 155 | if (last_task_used_math != NULL) |
1da177e4 | 156 | /* Other processes fpu state, save away */ |
332fd57b PM |
157 | save_fpu(last_task_used_math, regs); |
158 | ||
1da177e4 LT |
159 | last_task_used_math = current; |
160 | if (used_math()) { | |
161 | fpload(¤t->thread.fpu.hard); | |
162 | } else { | |
163 | /* First time FPU user. */ | |
164 | fpload(&init_fpuregs.hard); | |
165 | set_used_math(); | |
166 | } | |
600ee240 | 167 | disable_fpu(); |
1da177e4 | 168 | } |