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