Commit 3a3b5aa6 authored by Kevin Hao's avatar Kevin Hao Committed by Benjamin Herrenschmidt

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: default avatarKevin Hao <haokexin@gmail.com>
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent 6761ee3d
...@@ -1055,11 +1055,41 @@ int is_valid_bugaddr(unsigned long addr) ...@@ -1055,11 +1055,41 @@ int is_valid_bugaddr(unsigned long addr)
return is_kernel_addr(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) void __kprobes program_check_exception(struct pt_regs *regs)
{ {
enum ctx_state prev_state = exception_enter(); enum ctx_state prev_state = exception_enter();
unsigned int reason = get_reason(regs); 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 /* 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 */ * 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) ...@@ -1125,7 +1155,6 @@ void __kprobes program_check_exception(struct pt_regs *regs)
if (!arch_irq_disabled_regs(regs)) if (!arch_irq_disabled_regs(regs))
local_irq_enable(); local_irq_enable();
#ifdef CONFIG_MATH_EMULATION
/* (reason & REASON_ILLEGAL) would be the obvious thing here, /* (reason & REASON_ILLEGAL) would be the obvious thing here,
* but there seems to be a hardware bug on the 405GP (RevD) * but there seems to be a hardware bug on the 405GP (RevD)
* that means ESR is sometimes set incorrectly - either to * that means ESR is sometimes set incorrectly - either to
...@@ -1134,22 +1163,8 @@ void __kprobes program_check_exception(struct pt_regs *regs) ...@@ -1134,22 +1163,8 @@ void __kprobes program_check_exception(struct pt_regs *regs)
* instruction or only on FP instructions, whether there is a * instruction or only on FP instructions, whether there is a
* pattern to occurrences etc. -dgibson 31/Mar/2003 * pattern to occurrences etc. -dgibson 31/Mar/2003
*/ */
switch (do_mathemu(regs)) { if (!emulate_math(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);
goto bail; goto bail;
}
/* fall through on any other errors */
#endif /* CONFIG_MATH_EMULATION */
/* Try to emulate it if we should. */ /* Try to emulate it if we should. */
if (reason & (REASON_ILLEGAL | REASON_PRIVILEGED)) { if (reason & (REASON_ILLEGAL | REASON_PRIVILEGED)) {
...@@ -1428,11 +1443,6 @@ void performance_monitor_exception(struct pt_regs *regs) ...@@ -1428,11 +1443,6 @@ void performance_monitor_exception(struct pt_regs *regs)
#ifdef CONFIG_8xx #ifdef CONFIG_8xx
void SoftwareEmulation(struct pt_regs *regs) 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); CHECK_FULL_REGS(regs);
if (!user_mode(regs)) { if (!user_mode(regs)) {
...@@ -1440,31 +1450,10 @@ void SoftwareEmulation(struct pt_regs *regs) ...@@ -1440,31 +1450,10 @@ void SoftwareEmulation(struct pt_regs *regs)
die("Kernel Mode Software FPU Emulation", regs, SIGFPE); die("Kernel Mode Software FPU Emulation", regs, SIGFPE);
} }
#ifdef CONFIG_MATH_EMULATION if (!emulate_math(regs))
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);
return; return;
default:
_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
return;
}
#else
_exception(SIGILL, regs, ILL_ILLOPC, regs->nip); _exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
#endif
} }
#endif /* CONFIG_8xx */ #endif /* CONFIG_8xx */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment