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:
parent
6761ee3d7e
commit
3a3b5aa63f
|
@ -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 */
|
||||
|
||||
|
|
Loading…
Reference in New Issue