.. | .. |
---|
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 | */ |
---|