| .. | .. |
|---|
| 468 | 468 | } |
|---|
| 469 | 469 | |
|---|
| 470 | 470 | /** |
|---|
| 471 | | - * denormal_to_double - Given denormalized float number, |
|---|
| 472 | | - * store double float |
|---|
| 473 | | - * |
|---|
| 474 | | - * @fpu: Pointer to sh_fpu_soft structure |
|---|
| 475 | | - * @n: Index to FP register |
|---|
| 476 | | - */ |
|---|
| 477 | | -static void denormal_to_double(struct sh_fpu_soft_struct *fpu, int n) |
|---|
| 478 | | -{ |
|---|
| 479 | | - unsigned long du, dl; |
|---|
| 480 | | - unsigned long x = fpu->fpul; |
|---|
| 481 | | - int exp = 1023 - 126; |
|---|
| 482 | | - |
|---|
| 483 | | - if (x != 0 && (x & 0x7f800000) == 0) { |
|---|
| 484 | | - du = (x & 0x80000000); |
|---|
| 485 | | - while ((x & 0x00800000) == 0) { |
|---|
| 486 | | - x <<= 1; |
|---|
| 487 | | - exp--; |
|---|
| 488 | | - } |
|---|
| 489 | | - x &= 0x007fffff; |
|---|
| 490 | | - du |= (exp << 20) | (x >> 3); |
|---|
| 491 | | - dl = x << 29; |
|---|
| 492 | | - |
|---|
| 493 | | - fpu->fp_regs[n] = du; |
|---|
| 494 | | - fpu->fp_regs[n+1] = dl; |
|---|
| 495 | | - } |
|---|
| 496 | | -} |
|---|
| 497 | | - |
|---|
| 498 | | -/** |
|---|
| 499 | | - * ieee_fpe_handler - Handle denormalized number exception |
|---|
| 500 | | - * |
|---|
| 501 | | - * @regs: Pointer to register structure |
|---|
| 502 | | - * |
|---|
| 503 | | - * Returns 1 when it's handled (should not cause exception). |
|---|
| 504 | | - */ |
|---|
| 505 | | -static int ieee_fpe_handler(struct pt_regs *regs) |
|---|
| 506 | | -{ |
|---|
| 507 | | - unsigned short insn = *(unsigned short *)regs->pc; |
|---|
| 508 | | - unsigned short finsn; |
|---|
| 509 | | - unsigned long nextpc; |
|---|
| 510 | | - int nib[4] = { |
|---|
| 511 | | - (insn >> 12) & 0xf, |
|---|
| 512 | | - (insn >> 8) & 0xf, |
|---|
| 513 | | - (insn >> 4) & 0xf, |
|---|
| 514 | | - insn & 0xf}; |
|---|
| 515 | | - |
|---|
| 516 | | - if (nib[0] == 0xb || |
|---|
| 517 | | - (nib[0] == 0x4 && nib[2] == 0x0 && nib[3] == 0xb)) /* bsr & jsr */ |
|---|
| 518 | | - regs->pr = regs->pc + 4; |
|---|
| 519 | | - |
|---|
| 520 | | - if (nib[0] == 0xa || nib[0] == 0xb) { /* bra & bsr */ |
|---|
| 521 | | - nextpc = regs->pc + 4 + ((short) ((insn & 0xfff) << 4) >> 3); |
|---|
| 522 | | - finsn = *(unsigned short *) (regs->pc + 2); |
|---|
| 523 | | - } else if (nib[0] == 0x8 && nib[1] == 0xd) { /* bt/s */ |
|---|
| 524 | | - if (regs->sr & 1) |
|---|
| 525 | | - nextpc = regs->pc + 4 + ((char) (insn & 0xff) << 1); |
|---|
| 526 | | - else |
|---|
| 527 | | - nextpc = regs->pc + 4; |
|---|
| 528 | | - finsn = *(unsigned short *) (regs->pc + 2); |
|---|
| 529 | | - } else if (nib[0] == 0x8 && nib[1] == 0xf) { /* bf/s */ |
|---|
| 530 | | - if (regs->sr & 1) |
|---|
| 531 | | - nextpc = regs->pc + 4; |
|---|
| 532 | | - else |
|---|
| 533 | | - nextpc = regs->pc + 4 + ((char) (insn & 0xff) << 1); |
|---|
| 534 | | - finsn = *(unsigned short *) (regs->pc + 2); |
|---|
| 535 | | - } else if (nib[0] == 0x4 && nib[3] == 0xb && |
|---|
| 536 | | - (nib[2] == 0x0 || nib[2] == 0x2)) { /* jmp & jsr */ |
|---|
| 537 | | - nextpc = regs->regs[nib[1]]; |
|---|
| 538 | | - finsn = *(unsigned short *) (regs->pc + 2); |
|---|
| 539 | | - } else if (nib[0] == 0x0 && nib[3] == 0x3 && |
|---|
| 540 | | - (nib[2] == 0x0 || nib[2] == 0x2)) { /* braf & bsrf */ |
|---|
| 541 | | - nextpc = regs->pc + 4 + regs->regs[nib[1]]; |
|---|
| 542 | | - finsn = *(unsigned short *) (regs->pc + 2); |
|---|
| 543 | | - } else if (insn == 0x000b) { /* rts */ |
|---|
| 544 | | - nextpc = regs->pr; |
|---|
| 545 | | - finsn = *(unsigned short *) (regs->pc + 2); |
|---|
| 546 | | - } else { |
|---|
| 547 | | - nextpc = regs->pc + 2; |
|---|
| 548 | | - finsn = insn; |
|---|
| 549 | | - } |
|---|
| 550 | | - |
|---|
| 551 | | - if ((finsn & 0xf1ff) == 0xf0ad) { /* fcnvsd */ |
|---|
| 552 | | - struct task_struct *tsk = current; |
|---|
| 553 | | - |
|---|
| 554 | | - if ((tsk->thread.xstate->softfpu.fpscr & (1 << 17))) { |
|---|
| 555 | | - /* FPU error */ |
|---|
| 556 | | - denormal_to_double (&tsk->thread.xstate->softfpu, |
|---|
| 557 | | - (finsn >> 8) & 0xf); |
|---|
| 558 | | - tsk->thread.xstate->softfpu.fpscr &= |
|---|
| 559 | | - ~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK); |
|---|
| 560 | | - task_thread_info(tsk)->status |= TS_USEDFPU; |
|---|
| 561 | | - } else { |
|---|
| 562 | | - force_sig_fault(SIGFPE, FPE_FLTINV, |
|---|
| 563 | | - (void __user *)regs->pc, tsk); |
|---|
| 564 | | - } |
|---|
| 565 | | - |
|---|
| 566 | | - regs->pc = nextpc; |
|---|
| 567 | | - return 1; |
|---|
| 568 | | - } |
|---|
| 569 | | - |
|---|
| 570 | | - return 0; |
|---|
| 571 | | -} |
|---|
| 572 | | - |
|---|
| 573 | | -/** |
|---|
| 574 | 471 | * fpu_init - Initialize FPU registers |
|---|
| 575 | 472 | * @fpu: Pointer to software emulated FPU registers. |
|---|
| 576 | 473 | */ |
|---|