aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/traps.c
diff options
context:
space:
mode:
authorKumar Gala <galak@kernel.crashing.org>2007-02-07 02:47:59 -0500
committerKumar Gala <galak@kernel.crashing.org>2007-02-07 02:47:59 -0500
commit5fad293bcbd48d9a2370020cf60e4b4a42559b12 (patch)
treef6bb8c466410dead0471583ec874ca3244c3902b /arch/powerpc/kernel/traps.c
parent04903a30a327513b97c1271fc6bc4dad6502d1b8 (diff)
[POWERPC] Fixup error handling when emulating a floating point instruction
When we do full FP emulation its possible that we need to post a SIGFPE based on the results of the emulation. The previous code ignored this case completely. Additionally, the Soft_emulate_8xx case had two issues. One, we should never generate a SIGFPE since the code only does data movement. Second, we were interpreting the return codes incorrectly, it returns 0 on success, 1 on illop and -EFAULT on a data access error. Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel/traps.c')
-rw-r--r--arch/powerpc/kernel/traps.c82
1 files changed, 60 insertions, 22 deletions
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index f038caa3c2b9..dcc6f159fd94 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -535,34 +535,40 @@ static void emulate_single_step(struct pt_regs *regs)
535 } 535 }
536} 536}
537 537
538static void parse_fpe(struct pt_regs *regs) 538static inline int __parse_fpscr(unsigned long fpscr)
539{ 539{
540 int code = 0; 540 int ret = 0;
541 unsigned long fpscr;
542
543 flush_fp_to_thread(current);
544
545 fpscr = current->thread.fpscr.val;
546 541
547 /* Invalid operation */ 542 /* Invalid operation */
548 if ((fpscr & FPSCR_VE) && (fpscr & FPSCR_VX)) 543 if ((fpscr & FPSCR_VE) && (fpscr & FPSCR_VX))
549 code = FPE_FLTINV; 544 ret = FPE_FLTINV;
550 545
551 /* Overflow */ 546 /* Overflow */
552 else if ((fpscr & FPSCR_OE) && (fpscr & FPSCR_OX)) 547 else if ((fpscr & FPSCR_OE) && (fpscr & FPSCR_OX))
553 code = FPE_FLTOVF; 548 ret = FPE_FLTOVF;
554 549
555 /* Underflow */ 550 /* Underflow */
556 else if ((fpscr & FPSCR_UE) && (fpscr & FPSCR_UX)) 551 else if ((fpscr & FPSCR_UE) && (fpscr & FPSCR_UX))
557 code = FPE_FLTUND; 552 ret = FPE_FLTUND;
558 553
559 /* Divide by zero */ 554 /* Divide by zero */
560 else if ((fpscr & FPSCR_ZE) && (fpscr & FPSCR_ZX)) 555 else if ((fpscr & FPSCR_ZE) && (fpscr & FPSCR_ZX))
561 code = FPE_FLTDIV; 556 ret = FPE_FLTDIV;
562 557
563 /* Inexact result */ 558 /* Inexact result */
564 else if ((fpscr & FPSCR_XE) && (fpscr & FPSCR_XX)) 559 else if ((fpscr & FPSCR_XE) && (fpscr & FPSCR_XX))
565 code = FPE_FLTRES; 560 ret = FPE_FLTRES;
561
562 return ret;
563}
564
565static void parse_fpe(struct pt_regs *regs)
566{
567 int code = 0;
568
569 flush_fp_to_thread(current);
570
571 code = __parse_fpscr(current->thread.fpscr.val);
566 572
567 _exception(SIGFPE, regs, code, regs->nip); 573 _exception(SIGFPE, regs, code, regs->nip);
568} 574}
@@ -773,10 +779,21 @@ void __kprobes program_check_exception(struct pt_regs *regs)
773 * hardware people - not sure if it can happen on any illegal 779 * hardware people - not sure if it can happen on any illegal
774 * instruction or only on FP instructions, whether there is a 780 * instruction or only on FP instructions, whether there is a
775 * pattern to occurences etc. -dgibson 31/Mar/2003 */ 781 * pattern to occurences etc. -dgibson 31/Mar/2003 */
776 if (do_mathemu(regs) == 0) { 782 switch (do_mathemu(regs)) {
783 case 0:
777 emulate_single_step(regs); 784 emulate_single_step(regs);
778 return; 785 return;
786 case 1: {
787 int code = 0;
788 code = __parse_fpscr(current->thread.fpscr.val);
789 _exception(SIGFPE, regs, code, regs->nip);
790 return;
791 }
792 case -EFAULT:
793 _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip);
794 return;
779 } 795 }
796 /* fall through on any other errors */
780#endif /* CONFIG_MATH_EMULATION */ 797#endif /* CONFIG_MATH_EMULATION */
781 798
782 /* Try to emulate it if we should. */ 799 /* Try to emulate it if we should. */
@@ -892,18 +909,39 @@ void SoftwareEmulation(struct pt_regs *regs)
892 909
893#ifdef CONFIG_MATH_EMULATION 910#ifdef CONFIG_MATH_EMULATION
894 errcode = do_mathemu(regs); 911 errcode = do_mathemu(regs);
912
913 switch (errcode) {
914 case 0:
915 emulate_single_step(regs);
916 return;
917 case 1: {
918 int code = 0;
919 code = __parse_fpscr(current->thread.fpscr.val);
920 _exception(SIGFPE, regs, code, regs->nip);
921 return;
922 }
923 case -EFAULT:
924 _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip);
925 return;
926 default:
927 _exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
928 return;
929 }
930
895#else 931#else
896 errcode = Soft_emulate_8xx(regs); 932 errcode = Soft_emulate_8xx(regs);
897#endif 933 switch (errcode) {
898 if (errcode) { 934 case 0:
899 if (errcode > 0)
900 _exception(SIGFPE, regs, 0, 0);
901 else if (errcode == -EFAULT)
902 _exception(SIGSEGV, regs, 0, 0);
903 else
904 _exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
905 } else
906 emulate_single_step(regs); 935 emulate_single_step(regs);
936 return;
937 case 1:
938 _exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
939 return;
940 case -EFAULT:
941 _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip);
942 return;
943 }
944#endif
907} 945}
908#endif /* CONFIG_8xx */ 946#endif /* CONFIG_8xx */
909 947