]>
Commit | Line | Data |
---|---|---|
74d99a5e PM |
1 | /* |
2 | * Save/restore floating point context for signal handlers. | |
3 | * | |
4 | * Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka | |
5 | * | |
6 | * This file is subject to the terms and conditions of the GNU General Public | |
7 | * License. See the file "COPYING" in the main directory of this archive | |
8 | * for more details. | |
9 | * | |
10 | * FIXME! These routines can be optimized in big endian case. | |
11 | */ | |
3f07c014 | 12 | #include <linux/sched/signal.h> |
74d99a5e PM |
13 | #include <linux/signal.h> |
14 | #include <asm/processor.h> | |
15 | #include <asm/io.h> | |
9bbafce2 | 16 | #include <asm/fpu.h> |
f03c4866 | 17 | #include <asm/traps.h> |
74d99a5e PM |
18 | |
19 | /* The PR (precision) bit in the FP Status Register must be clear when | |
20 | * an frchg instruction is executed, otherwise the instruction is undefined. | |
21 | * Executing frchg with PR set causes a trap on some SH4 implementations. | |
22 | */ | |
23 | ||
24 | #define FPSCR_RCHG 0x00000000 | |
25 | ||
26 | ||
27 | /* | |
28 | * Save FPU registers onto task structure. | |
74d99a5e | 29 | */ |
0ea820cf | 30 | void save_fpu(struct task_struct *tsk) |
74d99a5e PM |
31 | { |
32 | unsigned long dummy; | |
33 | ||
74d99a5e PM |
34 | enable_fpu(); |
35 | asm volatile("sts.l fpul, @-%0\n\t" | |
36 | "sts.l fpscr, @-%0\n\t" | |
37 | "fmov.s fr15, @-%0\n\t" | |
38 | "fmov.s fr14, @-%0\n\t" | |
39 | "fmov.s fr13, @-%0\n\t" | |
40 | "fmov.s fr12, @-%0\n\t" | |
41 | "fmov.s fr11, @-%0\n\t" | |
42 | "fmov.s fr10, @-%0\n\t" | |
43 | "fmov.s fr9, @-%0\n\t" | |
44 | "fmov.s fr8, @-%0\n\t" | |
45 | "fmov.s fr7, @-%0\n\t" | |
46 | "fmov.s fr6, @-%0\n\t" | |
47 | "fmov.s fr5, @-%0\n\t" | |
48 | "fmov.s fr4, @-%0\n\t" | |
49 | "fmov.s fr3, @-%0\n\t" | |
50 | "fmov.s fr2, @-%0\n\t" | |
51 | "fmov.s fr1, @-%0\n\t" | |
52 | "fmov.s fr0, @-%0\n\t" | |
53 | "lds %3, fpscr\n\t" | |
54 | : "=r" (dummy) | |
0ea820cf | 55 | : "0" ((char *)(&tsk->thread.xstate->hardfpu.status)), |
74d99a5e PM |
56 | "r" (FPSCR_RCHG), |
57 | "r" (FPSCR_INIT) | |
58 | : "memory"); | |
59 | ||
60 | disable_fpu(); | |
74d99a5e PM |
61 | } |
62 | ||
0ea820cf | 63 | void restore_fpu(struct task_struct *tsk) |
74d99a5e PM |
64 | { |
65 | unsigned long dummy; | |
66 | ||
67 | enable_fpu(); | |
68 | asm volatile("fmov.s @%0+, fr0\n\t" | |
69 | "fmov.s @%0+, fr1\n\t" | |
70 | "fmov.s @%0+, fr2\n\t" | |
71 | "fmov.s @%0+, fr3\n\t" | |
72 | "fmov.s @%0+, fr4\n\t" | |
73 | "fmov.s @%0+, fr5\n\t" | |
74 | "fmov.s @%0+, fr6\n\t" | |
75 | "fmov.s @%0+, fr7\n\t" | |
76 | "fmov.s @%0+, fr8\n\t" | |
77 | "fmov.s @%0+, fr9\n\t" | |
78 | "fmov.s @%0+, fr10\n\t" | |
79 | "fmov.s @%0+, fr11\n\t" | |
80 | "fmov.s @%0+, fr12\n\t" | |
81 | "fmov.s @%0+, fr13\n\t" | |
82 | "fmov.s @%0+, fr14\n\t" | |
83 | "fmov.s @%0+, fr15\n\t" | |
84 | "lds.l @%0+, fpscr\n\t" | |
85 | "lds.l @%0+, fpul\n\t" | |
86 | : "=r" (dummy) | |
0ea820cf | 87 | : "0" (tsk->thread.xstate), "r" (FPSCR_RCHG) |
74d99a5e PM |
88 | : "memory"); |
89 | disable_fpu(); | |
90 | } | |
91 | ||
74d99a5e PM |
92 | /* |
93 | * Emulate arithmetic ops on denormalized number for some FPU insns. | |
94 | */ | |
95 | ||
96 | /* denormalized float * float */ | |
97 | static int denormal_mulf(int hx, int hy) | |
98 | { | |
99 | unsigned int ix, iy; | |
100 | unsigned long long m, n; | |
101 | int exp, w; | |
102 | ||
103 | ix = hx & 0x7fffffff; | |
104 | iy = hy & 0x7fffffff; | |
105 | if (iy < 0x00800000 || ix == 0) | |
106 | return ((hx ^ hy) & 0x80000000); | |
107 | ||
108 | exp = (iy & 0x7f800000) >> 23; | |
109 | ix &= 0x007fffff; | |
110 | iy = (iy & 0x007fffff) | 0x00800000; | |
111 | m = (unsigned long long)ix * iy; | |
112 | n = m; | |
113 | w = -1; | |
114 | while (n) { n >>= 1; w++; } | |
115 | ||
116 | /* FIXME: use guard bits */ | |
117 | exp += w - 126 - 46; | |
118 | if (exp > 0) | |
119 | ix = ((int) (m >> (w - 23)) & 0x007fffff) | (exp << 23); | |
120 | else if (exp + 22 >= 0) | |
121 | ix = (int) (m >> (w - 22 - exp)) & 0x007fffff; | |
122 | else | |
123 | ix = 0; | |
124 | ||
125 | ix |= (hx ^ hy) & 0x80000000; | |
126 | return ix; | |
127 | } | |
128 | ||
129 | /* denormalized double * double */ | |
130 | static void mult64(unsigned long long x, unsigned long long y, | |
131 | unsigned long long *highp, unsigned long long *lowp) | |
132 | { | |
133 | unsigned long long sub0, sub1, sub2, sub3; | |
134 | unsigned long long high, low; | |
135 | ||
136 | sub0 = (x >> 32) * (unsigned long) (y >> 32); | |
137 | sub1 = (x & 0xffffffffLL) * (unsigned long) (y >> 32); | |
138 | sub2 = (x >> 32) * (unsigned long) (y & 0xffffffffLL); | |
139 | sub3 = (x & 0xffffffffLL) * (unsigned long) (y & 0xffffffffLL); | |
140 | low = sub3; | |
141 | high = 0LL; | |
142 | sub3 += (sub1 << 32); | |
143 | if (low > sub3) | |
144 | high++; | |
145 | low = sub3; | |
146 | sub3 += (sub2 << 32); | |
147 | if (low > sub3) | |
148 | high++; | |
149 | low = sub3; | |
150 | high += (sub1 >> 32) + (sub2 >> 32); | |
151 | high += sub0; | |
152 | *lowp = low; | |
153 | *highp = high; | |
154 | } | |
155 | ||
156 | static inline long long rshift64(unsigned long long mh, | |
157 | unsigned long long ml, int n) | |
158 | { | |
159 | if (n >= 64) | |
160 | return mh >> (n - 64); | |
161 | return (mh << (64 - n)) | (ml >> n); | |
162 | } | |
163 | ||
164 | static long long denormal_muld(long long hx, long long hy) | |
165 | { | |
166 | unsigned long long ix, iy; | |
167 | unsigned long long mh, ml, nh, nl; | |
168 | int exp, w; | |
169 | ||
170 | ix = hx & 0x7fffffffffffffffLL; | |
171 | iy = hy & 0x7fffffffffffffffLL; | |
172 | if (iy < 0x0010000000000000LL || ix == 0) | |
173 | return ((hx ^ hy) & 0x8000000000000000LL); | |
174 | ||
175 | exp = (iy & 0x7ff0000000000000LL) >> 52; | |
176 | ix &= 0x000fffffffffffffLL; | |
177 | iy = (iy & 0x000fffffffffffffLL) | 0x0010000000000000LL; | |
178 | mult64(ix, iy, &mh, &ml); | |
179 | nh = mh; | |
180 | nl = ml; | |
181 | w = -1; | |
182 | if (nh) { | |
183 | while (nh) { nh >>= 1; w++;} | |
184 | w += 64; | |
185 | } else | |
186 | while (nl) { nl >>= 1; w++;} | |
187 | ||
188 | /* FIXME: use guard bits */ | |
189 | exp += w - 1022 - 52 * 2; | |
190 | if (exp > 0) | |
191 | ix = (rshift64(mh, ml, w - 52) & 0x000fffffffffffffLL) | |
192 | | ((long long)exp << 52); | |
193 | else if (exp + 51 >= 0) | |
194 | ix = rshift64(mh, ml, w - 51 - exp) & 0x000fffffffffffffLL; | |
195 | else | |
196 | ix = 0; | |
197 | ||
198 | ix |= (hx ^ hy) & 0x8000000000000000LL; | |
199 | return ix; | |
200 | } | |
201 | ||
202 | /* ix - iy where iy: denormal and ix, iy >= 0 */ | |
203 | static int denormal_subf1(unsigned int ix, unsigned int iy) | |
204 | { | |
205 | int frac; | |
206 | int exp; | |
207 | ||
208 | if (ix < 0x00800000) | |
209 | return ix - iy; | |
210 | ||
211 | exp = (ix & 0x7f800000) >> 23; | |
212 | if (exp - 1 > 31) | |
213 | return ix; | |
214 | iy >>= exp - 1; | |
215 | if (iy == 0) | |
216 | return ix; | |
217 | ||
218 | frac = (ix & 0x007fffff) | 0x00800000; | |
219 | frac -= iy; | |
220 | while (frac < 0x00800000) { | |
221 | if (--exp == 0) | |
222 | return frac; | |
223 | frac <<= 1; | |
224 | } | |
225 | ||
226 | return (exp << 23) | (frac & 0x007fffff); | |
227 | } | |
228 | ||
229 | /* ix + iy where iy: denormal and ix, iy >= 0 */ | |
230 | static int denormal_addf1(unsigned int ix, unsigned int iy) | |
231 | { | |
232 | int frac; | |
233 | int exp; | |
234 | ||
235 | if (ix < 0x00800000) | |
236 | return ix + iy; | |
237 | ||
238 | exp = (ix & 0x7f800000) >> 23; | |
239 | if (exp - 1 > 31) | |
240 | return ix; | |
241 | iy >>= exp - 1; | |
242 | if (iy == 0) | |
243 | return ix; | |
244 | ||
245 | frac = (ix & 0x007fffff) | 0x00800000; | |
246 | frac += iy; | |
247 | if (frac >= 0x01000000) { | |
248 | frac >>= 1; | |
249 | ++exp; | |
250 | } | |
251 | ||
252 | return (exp << 23) | (frac & 0x007fffff); | |
253 | } | |
254 | ||
255 | static int denormal_addf(int hx, int hy) | |
256 | { | |
257 | unsigned int ix, iy; | |
258 | int sign; | |
259 | ||
260 | if ((hx ^ hy) & 0x80000000) { | |
261 | sign = hx & 0x80000000; | |
262 | ix = hx & 0x7fffffff; | |
263 | iy = hy & 0x7fffffff; | |
264 | if (iy < 0x00800000) { | |
265 | ix = denormal_subf1(ix, iy); | |
9731e287 | 266 | if ((int) ix < 0) { |
74d99a5e PM |
267 | ix = -ix; |
268 | sign ^= 0x80000000; | |
269 | } | |
270 | } else { | |
271 | ix = denormal_subf1(iy, ix); | |
272 | sign ^= 0x80000000; | |
273 | } | |
274 | } else { | |
275 | sign = hx & 0x80000000; | |
276 | ix = hx & 0x7fffffff; | |
277 | iy = hy & 0x7fffffff; | |
278 | if (iy < 0x00800000) | |
279 | ix = denormal_addf1(ix, iy); | |
280 | else | |
281 | ix = denormal_addf1(iy, ix); | |
282 | } | |
283 | ||
284 | return sign | ix; | |
285 | } | |
286 | ||
287 | /* ix - iy where iy: denormal and ix, iy >= 0 */ | |
288 | static long long denormal_subd1(unsigned long long ix, unsigned long long iy) | |
289 | { | |
290 | long long frac; | |
291 | int exp; | |
292 | ||
293 | if (ix < 0x0010000000000000LL) | |
294 | return ix - iy; | |
295 | ||
296 | exp = (ix & 0x7ff0000000000000LL) >> 52; | |
297 | if (exp - 1 > 63) | |
298 | return ix; | |
299 | iy >>= exp - 1; | |
300 | if (iy == 0) | |
301 | return ix; | |
302 | ||
303 | frac = (ix & 0x000fffffffffffffLL) | 0x0010000000000000LL; | |
304 | frac -= iy; | |
305 | while (frac < 0x0010000000000000LL) { | |
306 | if (--exp == 0) | |
307 | return frac; | |
308 | frac <<= 1; | |
309 | } | |
310 | ||
311 | return ((long long)exp << 52) | (frac & 0x000fffffffffffffLL); | |
312 | } | |
313 | ||
314 | /* ix + iy where iy: denormal and ix, iy >= 0 */ | |
315 | static long long denormal_addd1(unsigned long long ix, unsigned long long iy) | |
316 | { | |
317 | long long frac; | |
318 | long long exp; | |
319 | ||
320 | if (ix < 0x0010000000000000LL) | |
321 | return ix + iy; | |
322 | ||
323 | exp = (ix & 0x7ff0000000000000LL) >> 52; | |
324 | if (exp - 1 > 63) | |
325 | return ix; | |
326 | iy >>= exp - 1; | |
327 | if (iy == 0) | |
328 | return ix; | |
329 | ||
330 | frac = (ix & 0x000fffffffffffffLL) | 0x0010000000000000LL; | |
331 | frac += iy; | |
332 | if (frac >= 0x0020000000000000LL) { | |
333 | frac >>= 1; | |
334 | ++exp; | |
335 | } | |
336 | ||
337 | return (exp << 52) | (frac & 0x000fffffffffffffLL); | |
338 | } | |
339 | ||
340 | static long long denormal_addd(long long hx, long long hy) | |
341 | { | |
342 | unsigned long long ix, iy; | |
343 | long long sign; | |
344 | ||
345 | if ((hx ^ hy) & 0x8000000000000000LL) { | |
346 | sign = hx & 0x8000000000000000LL; | |
347 | ix = hx & 0x7fffffffffffffffLL; | |
348 | iy = hy & 0x7fffffffffffffffLL; | |
349 | if (iy < 0x0010000000000000LL) { | |
350 | ix = denormal_subd1(ix, iy); | |
9731e287 | 351 | if ((int) ix < 0) { |
74d99a5e PM |
352 | ix = -ix; |
353 | sign ^= 0x8000000000000000LL; | |
354 | } | |
355 | } else { | |
356 | ix = denormal_subd1(iy, ix); | |
357 | sign ^= 0x8000000000000000LL; | |
358 | } | |
359 | } else { | |
360 | sign = hx & 0x8000000000000000LL; | |
361 | ix = hx & 0x7fffffffffffffffLL; | |
362 | iy = hy & 0x7fffffffffffffffLL; | |
363 | if (iy < 0x0010000000000000LL) | |
364 | ix = denormal_addd1(ix, iy); | |
365 | else | |
366 | ix = denormal_addd1(iy, ix); | |
367 | } | |
368 | ||
369 | return sign | ix; | |
370 | } | |
371 | ||
372 | /** | |
373 | * denormal_to_double - Given denormalized float number, | |
374 | * store double float | |
375 | * | |
376 | * @fpu: Pointer to sh_fpu_hard structure | |
377 | * @n: Index to FP register | |
378 | */ | |
379 | static void | |
380 | denormal_to_double (struct sh_fpu_hard_struct *fpu, int n) | |
381 | { | |
382 | unsigned long du, dl; | |
383 | unsigned long x = fpu->fpul; | |
384 | int exp = 1023 - 126; | |
385 | ||
386 | if (x != 0 && (x & 0x7f800000) == 0) { | |
387 | du = (x & 0x80000000); | |
388 | while ((x & 0x00800000) == 0) { | |
389 | x <<= 1; | |
390 | exp--; | |
391 | } | |
392 | x &= 0x007fffff; | |
393 | du |= (exp << 20) | (x >> 3); | |
394 | dl = x << 29; | |
395 | ||
396 | fpu->fp_regs[n] = du; | |
397 | fpu->fp_regs[n+1] = dl; | |
398 | } | |
399 | } | |
400 | ||
401 | /** | |
402 | * ieee_fpe_handler - Handle denormalized number exception | |
403 | * | |
404 | * @regs: Pointer to register structure | |
405 | * | |
406 | * Returns 1 when it's handled (should not cause exception). | |
407 | */ | |
408 | static int | |
409 | ieee_fpe_handler (struct pt_regs *regs) | |
410 | { | |
411 | unsigned short insn = *(unsigned short *) regs->pc; | |
412 | unsigned short finsn; | |
413 | unsigned long nextpc; | |
414 | int nib[4] = { | |
415 | (insn >> 12) & 0xf, | |
416 | (insn >> 8) & 0xf, | |
417 | (insn >> 4) & 0xf, | |
418 | insn & 0xf}; | |
419 | ||
420 | if (nib[0] == 0xb || | |
421 | (nib[0] == 0x4 && nib[2] == 0x0 && nib[3] == 0xb)) /* bsr & jsr */ | |
422 | regs->pr = regs->pc + 4; | |
423 | if (nib[0] == 0xa || nib[0] == 0xb) { /* bra & bsr */ | |
424 | nextpc = regs->pc + 4 + ((short) ((insn & 0xfff) << 4) >> 3); | |
425 | finsn = *(unsigned short *) (regs->pc + 2); | |
426 | } else if (nib[0] == 0x8 && nib[1] == 0xd) { /* bt/s */ | |
427 | if (regs->sr & 1) | |
428 | nextpc = regs->pc + 4 + ((char) (insn & 0xff) << 1); | |
429 | else | |
430 | nextpc = regs->pc + 4; | |
431 | finsn = *(unsigned short *) (regs->pc + 2); | |
432 | } else if (nib[0] == 0x8 && nib[1] == 0xf) { /* bf/s */ | |
433 | if (regs->sr & 1) | |
434 | nextpc = regs->pc + 4; | |
435 | else | |
436 | nextpc = regs->pc + 4 + ((char) (insn & 0xff) << 1); | |
437 | finsn = *(unsigned short *) (regs->pc + 2); | |
438 | } else if (nib[0] == 0x4 && nib[3] == 0xb && | |
439 | (nib[2] == 0x0 || nib[2] == 0x2)) { /* jmp & jsr */ | |
440 | nextpc = regs->regs[nib[1]]; | |
441 | finsn = *(unsigned short *) (regs->pc + 2); | |
442 | } else if (nib[0] == 0x0 && nib[3] == 0x3 && | |
443 | (nib[2] == 0x0 || nib[2] == 0x2)) { /* braf & bsrf */ | |
444 | nextpc = regs->pc + 4 + regs->regs[nib[1]]; | |
445 | finsn = *(unsigned short *) (regs->pc + 2); | |
446 | } else if (insn == 0x000b) { /* rts */ | |
447 | nextpc = regs->pr; | |
448 | finsn = *(unsigned short *) (regs->pc + 2); | |
449 | } else { | |
450 | nextpc = regs->pc + 2; | |
451 | finsn = insn; | |
452 | } | |
453 | ||
454 | #define FPSCR_FPU_ERROR (1 << 17) | |
455 | ||
456 | if ((finsn & 0xf1ff) == 0xf0ad) { /* fcnvsd */ | |
457 | struct task_struct *tsk = current; | |
458 | ||
0ea820cf | 459 | if ((tsk->thread.xstate->hardfpu.fpscr & FPSCR_FPU_ERROR)) { |
74d99a5e | 460 | /* FPU error */ |
0ea820cf | 461 | denormal_to_double (&tsk->thread.xstate->hardfpu, |
74d99a5e PM |
462 | (finsn >> 8) & 0xf); |
463 | } else | |
464 | return 0; | |
465 | ||
466 | regs->pc = nextpc; | |
467 | return 1; | |
468 | } else if ((finsn & 0xf00f) == 0xf002) { /* fmul */ | |
469 | struct task_struct *tsk = current; | |
470 | int fpscr; | |
471 | int n, m, prec; | |
472 | unsigned int hx, hy; | |
473 | ||
474 | n = (finsn >> 8) & 0xf; | |
475 | m = (finsn >> 4) & 0xf; | |
0ea820cf PM |
476 | hx = tsk->thread.xstate->hardfpu.fp_regs[n]; |
477 | hy = tsk->thread.xstate->hardfpu.fp_regs[m]; | |
478 | fpscr = tsk->thread.xstate->hardfpu.fpscr; | |
74d99a5e PM |
479 | prec = fpscr & (1 << 19); |
480 | ||
481 | if ((fpscr & FPSCR_FPU_ERROR) | |
482 | && (prec && ((hx & 0x7fffffff) < 0x00100000 | |
483 | || (hy & 0x7fffffff) < 0x00100000))) { | |
484 | long long llx, lly; | |
485 | ||
486 | /* FPU error because of denormal */ | |
487 | llx = ((long long) hx << 32) | |
0ea820cf | 488 | | tsk->thread.xstate->hardfpu.fp_regs[n+1]; |
74d99a5e | 489 | lly = ((long long) hy << 32) |
0ea820cf | 490 | | tsk->thread.xstate->hardfpu.fp_regs[m+1]; |
74d99a5e PM |
491 | if ((hx & 0x7fffffff) >= 0x00100000) |
492 | llx = denormal_muld(lly, llx); | |
493 | else | |
494 | llx = denormal_muld(llx, lly); | |
0ea820cf PM |
495 | tsk->thread.xstate->hardfpu.fp_regs[n] = llx >> 32; |
496 | tsk->thread.xstate->hardfpu.fp_regs[n+1] = llx & 0xffffffff; | |
74d99a5e PM |
497 | } else if ((fpscr & FPSCR_FPU_ERROR) |
498 | && (!prec && ((hx & 0x7fffffff) < 0x00800000 | |
499 | || (hy & 0x7fffffff) < 0x00800000))) { | |
500 | /* FPU error because of denormal */ | |
501 | if ((hx & 0x7fffffff) >= 0x00800000) | |
502 | hx = denormal_mulf(hy, hx); | |
503 | else | |
504 | hx = denormal_mulf(hx, hy); | |
0ea820cf | 505 | tsk->thread.xstate->hardfpu.fp_regs[n] = hx; |
74d99a5e PM |
506 | } else |
507 | return 0; | |
508 | ||
509 | regs->pc = nextpc; | |
510 | return 1; | |
511 | } else if ((finsn & 0xf00e) == 0xf000) { /* fadd, fsub */ | |
512 | struct task_struct *tsk = current; | |
513 | int fpscr; | |
514 | int n, m, prec; | |
515 | unsigned int hx, hy; | |
516 | ||
517 | n = (finsn >> 8) & 0xf; | |
518 | m = (finsn >> 4) & 0xf; | |
0ea820cf PM |
519 | hx = tsk->thread.xstate->hardfpu.fp_regs[n]; |
520 | hy = tsk->thread.xstate->hardfpu.fp_regs[m]; | |
521 | fpscr = tsk->thread.xstate->hardfpu.fpscr; | |
74d99a5e PM |
522 | prec = fpscr & (1 << 19); |
523 | ||
524 | if ((fpscr & FPSCR_FPU_ERROR) | |
525 | && (prec && ((hx & 0x7fffffff) < 0x00100000 | |
526 | || (hy & 0x7fffffff) < 0x00100000))) { | |
527 | long long llx, lly; | |
528 | ||
529 | /* FPU error because of denormal */ | |
530 | llx = ((long long) hx << 32) | |
0ea820cf | 531 | | tsk->thread.xstate->hardfpu.fp_regs[n+1]; |
74d99a5e | 532 | lly = ((long long) hy << 32) |
0ea820cf | 533 | | tsk->thread.xstate->hardfpu.fp_regs[m+1]; |
74d99a5e PM |
534 | if ((finsn & 0xf00f) == 0xf000) |
535 | llx = denormal_addd(llx, lly); | |
536 | else | |
537 | llx = denormal_addd(llx, lly ^ (1LL << 63)); | |
0ea820cf PM |
538 | tsk->thread.xstate->hardfpu.fp_regs[n] = llx >> 32; |
539 | tsk->thread.xstate->hardfpu.fp_regs[n+1] = llx & 0xffffffff; | |
74d99a5e PM |
540 | } else if ((fpscr & FPSCR_FPU_ERROR) |
541 | && (!prec && ((hx & 0x7fffffff) < 0x00800000 | |
542 | || (hy & 0x7fffffff) < 0x00800000))) { | |
543 | /* FPU error because of denormal */ | |
544 | if ((finsn & 0xf00f) == 0xf000) | |
545 | hx = denormal_addf(hx, hy); | |
546 | else | |
547 | hx = denormal_addf(hx, hy ^ 0x80000000); | |
0ea820cf | 548 | tsk->thread.xstate->hardfpu.fp_regs[n] = hx; |
74d99a5e PM |
549 | } else |
550 | return 0; | |
551 | ||
552 | regs->pc = nextpc; | |
553 | return 1; | |
554 | } | |
555 | ||
556 | return 0; | |
557 | } | |
558 | ||
559 | BUILD_TRAP_HANDLER(fpu_error) | |
560 | { | |
561 | struct task_struct *tsk = current; | |
562 | TRAP_HANDLER_DECL; | |
563 | ||
d3ea9fa0 | 564 | __unlazy_fpu(tsk, regs); |
74d99a5e | 565 | if (ieee_fpe_handler(regs)) { |
0ea820cf | 566 | tsk->thread.xstate->hardfpu.fpscr &= |
74d99a5e PM |
567 | ~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK); |
568 | grab_fpu(regs); | |
569 | restore_fpu(tsk); | |
d3ea9fa0 | 570 | task_thread_info(tsk)->status |= TS_USEDFPU; |
74d99a5e PM |
571 | return; |
572 | } | |
573 | ||
574 | force_sig(SIGFPE, tsk); | |
575 | } |