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>
This commit is contained in:
Kevin Hao 2013-07-14 16:40:07 +08:00 committed by Benjamin Herrenschmidt
parent 6761ee3d7e
commit 3a3b5aa63f
1 changed files with 34 additions and 45 deletions

View 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);
if (!emulate_math(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);
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);
if (!emulate_math(regs))
return;
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);
return;
default:
_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
return;
}
#else
_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
#endif
}
#endif /* CONFIG_8xx */