Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+34 −45
Original line number Diff line number Diff line
@@ -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);

	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 */