diff options
author | Kevin Hao | 2013-07-14 16:40:07 +0800 |
---|---|---|
committer | Benjamin Herrenschmidt | 2013-08-14 14:59:12 +1000 |
commit | 3a3b5aa63fad4911e239055c2c0a89ce2dac62ce (patch) | |
tree | 0254800fc0cb0f73eaa1d8a1ca3bfe96f47d1708 /arch/powerpc/kernel | |
parent | 6761ee3d7e139ec8728e1515bfc5fdcaf3be317e (diff) |
powerpc: Introduce function emulate_math()
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>
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r-- | arch/powerpc/kernel/traps.c | 79 |
1 files changed, 34 insertions, 45 deletions
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 82df498069bc..e6fac2102b06 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -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 */ |