powerpc: Introduce function emulate_math()
authorKevin Hao <haokexin@gmail.com>
Sun, 14 Jul 2013 08:40:07 +0000 (16:40 +0800)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Wed, 14 Aug 2013 04:59:12 +0000 (14:59 +1000)
There are two invocations of do_mathemu() in traps.c. And the codes
in these two places are almost the same. Introduce a locale function
to eliminate the duplication. With this change we can also make sure
that in program_check_exception() the PPC_WARN_EMULATED is invoked for
the correctly emulated math instructions.

Signed-off-by: Kevin Hao <haokexin@gmail.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/kernel/traps.c

index 82df498069bc47495f5d46651437aea405b2833d..e6fac2102b067540bffdae07e7222d3dec0183ab 100644 (file)
@@ -1055,11 +1055,41 @@ int is_valid_bugaddr(unsigned long addr)
        return is_kernel_addr(addr);
 }
 
+#ifdef CONFIG_MATH_EMULATION
+static int emulate_math(struct pt_regs *regs)
+{
+       int ret;
+       extern int do_mathemu(struct pt_regs *regs);
+
+       ret = do_mathemu(regs);
+       if (ret >= 0)
+               PPC_WARN_EMULATED(math, regs);
+
+       switch (ret) {
+       case 0:
+               emulate_single_step(regs);
+               return 0;
+       case 1: {
+                       int code = 0;
+                       code = __parse_fpscr(current->thread.fpscr.val);
+                       _exception(SIGFPE, regs, code, regs->nip);
+                       return 0;
+               }
+       case -EFAULT:
+               _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip);
+               return 0;
+       }
+
+       return -1;
+}
+#else
+static inline int emulate_math(struct pt_regs *regs) { return -1; }
+#endif
+
 void __kprobes program_check_exception(struct pt_regs *regs)
 {
        enum ctx_state prev_state = exception_enter();
        unsigned int reason = get_reason(regs);
-       extern int do_mathemu(struct pt_regs *regs);
 
        /* We can now get here via a FP Unavailable exception if the core
         * has no FPU, in that case the reason flags will be 0 */
@@ -1125,7 +1155,6 @@ void __kprobes program_check_exception(struct pt_regs *regs)
        if (!arch_irq_disabled_regs(regs))
                local_irq_enable();
 
-#ifdef CONFIG_MATH_EMULATION
        /* (reason & REASON_ILLEGAL) would be the obvious thing here,
         * but there seems to be a hardware bug on the 405GP (RevD)
         * that means ESR is sometimes set incorrectly - either to
@@ -1134,22 +1163,8 @@ void __kprobes program_check_exception(struct pt_regs *regs)
         * instruction or only on FP instructions, whether there is a
         * pattern to occurrences etc. -dgibson 31/Mar/2003
         */
-       switch (do_mathemu(regs)) {
-       case 0:
-               emulate_single_step(regs);
-               goto bail;
-       case 1: {
-                       int code = 0;
-                       code = __parse_fpscr(current->thread.fpscr.val);
-                       _exception(SIGFPE, regs, code, regs->nip);
-                       goto bail;
-               }
-       case -EFAULT:
-               _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip);
+       if (!emulate_math(regs))
                goto bail;
-       }
-       /* fall through on any other errors */
-#endif /* CONFIG_MATH_EMULATION */
 
        /* Try to emulate it if we should. */
        if (reason & (REASON_ILLEGAL | REASON_PRIVILEGED)) {
@@ -1428,11 +1443,6 @@ void performance_monitor_exception(struct pt_regs *regs)
 #ifdef CONFIG_8xx
 void SoftwareEmulation(struct pt_regs *regs)
 {
-       extern int do_mathemu(struct pt_regs *);
-#if defined(CONFIG_MATH_EMULATION)
-       int errcode;
-#endif
-
        CHECK_FULL_REGS(regs);
 
        if (!user_mode(regs)) {
@@ -1440,31 +1450,10 @@ void SoftwareEmulation(struct pt_regs *regs)
                die("Kernel Mode Software FPU Emulation", regs, SIGFPE);
        }
 
-#ifdef CONFIG_MATH_EMULATION
-       errcode = do_mathemu(regs);
-       if (errcode >= 0)
-               PPC_WARN_EMULATED(math, regs);
-
-       switch (errcode) {
-       case 0:
-               emulate_single_step(regs);
-               return;
-       case 1: {
-                       int code = 0;
-                       code = __parse_fpscr(current->thread.fpscr.val);
-                       _exception(SIGFPE, regs, code, regs->nip);
-                       return;
-               }
-       case -EFAULT:
-               _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip);
+       if (!emulate_math(regs))
                return;
-       default:
-               _exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
-               return;
-       }
-#else
+
        _exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
-#endif
 }
 #endif /* CONFIG_8xx */