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 */ 12#include <linux/sched.h> 13#include <linux/signal.h> 14#include <asm/processor.h> 15#include <asm/io.h> 16#include <asm/fpu.h> 17#include <asm/traps.h> 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. 29 */ 30void save_fpu(struct task_struct *tsk) 31{ 32 unsigned long dummy; 33 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) 55 : "0" ((char *)(&tsk->thread.xstate->hardfpu.status)), 56 "r" (FPSCR_RCHG), 57 "r" (FPSCR_INIT) 58 : "memory"); 59 60 disable_fpu(); 61} 62 63void restore_fpu(struct task_struct *tsk) 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) 87 : "0" (tsk->thread.xstate), "r" (FPSCR_RCHG) 88 : "memory"); 89 disable_fpu(); 90} 91 92/* 93 * Emulate arithmetic ops on denormalized number for some FPU insns. 94 */ 95 96/* denormalized float * float */ 97static 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 */ 130static 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 156static 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 164static 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 */ 203static 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 */ 230static 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 255static 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); 266 if ((int) ix < 0) { 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 */ 288static 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 */ 315static 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 340static 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); 351 if ((int) ix < 0) { 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 */ 379static void 380denormal_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 */ 408static int 409ieee_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 459 if ((tsk->thread.xstate->hardfpu.fpscr & FPSCR_FPU_ERROR)) { 460 /* FPU error */ 461 denormal_to_double (&tsk->thread.xstate->hardfpu, 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; 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; 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) 488 | tsk->thread.xstate->hardfpu.fp_regs[n+1]; 489 lly = ((long long) hy << 32) 490 | tsk->thread.xstate->hardfpu.fp_regs[m+1]; 491 if ((hx & 0x7fffffff) >= 0x00100000) 492 llx = denormal_muld(lly, llx); 493 else 494 llx = denormal_muld(llx, lly); 495 tsk->thread.xstate->hardfpu.fp_regs[n] = llx >> 32; 496 tsk->thread.xstate->hardfpu.fp_regs[n+1] = llx & 0xffffffff; 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); 505 tsk->thread.xstate->hardfpu.fp_regs[n] = hx; 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; 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; 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) 531 | tsk->thread.xstate->hardfpu.fp_regs[n+1]; 532 lly = ((long long) hy << 32) 533 | tsk->thread.xstate->hardfpu.fp_regs[m+1]; 534 if ((finsn & 0xf00f) == 0xf000) 535 llx = denormal_addd(llx, lly); 536 else 537 llx = denormal_addd(llx, lly ^ (1LL << 63)); 538 tsk->thread.xstate->hardfpu.fp_regs[n] = llx >> 32; 539 tsk->thread.xstate->hardfpu.fp_regs[n+1] = llx & 0xffffffff; 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); 548 tsk->thread.xstate->hardfpu.fp_regs[n] = hx; 549 } else 550 return 0; 551 552 regs->pc = nextpc; 553 return 1; 554 } 555 556 return 0; 557} 558 559BUILD_TRAP_HANDLER(fpu_error) 560{ 561 struct task_struct *tsk = current; 562 TRAP_HANDLER_DECL; 563 564 __unlazy_fpu(tsk, regs); 565 if (ieee_fpe_handler(regs)) { 566 tsk->thread.xstate->hardfpu.fpscr &= 567 ~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK); 568 grab_fpu(regs); 569 restore_fpu(tsk); 570 task_thread_info(tsk)->status |= TS_USEDFPU; 571 return; 572 } 573 574 force_sig(SIGFPE, tsk); 575} 576