diff options
author | Kevin Hao <haokexin@gmail.com> | 2013-07-14 04:40:07 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2013-08-14 00:59:12 -0400 |
commit | 3a3b5aa63fad4911e239055c2c0a89ce2dac62ce (patch) | |
tree | 0254800fc0cb0f73eaa1d8a1ca3bfe96f47d1708 | |
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>
-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) | |||
1055 | return is_kernel_addr(addr); | 1055 | return is_kernel_addr(addr); |
1056 | } | 1056 | } |
1057 | 1057 | ||
1058 | #ifdef CONFIG_MATH_EMULATION | ||
1059 | static int emulate_math(struct pt_regs *regs) | ||
1060 | { | ||
1061 | int ret; | ||
1062 | extern int do_mathemu(struct pt_regs *regs); | ||
1063 | |||
1064 | ret = do_mathemu(regs); | ||
1065 | if (ret >= 0) | ||
1066 | PPC_WARN_EMULATED(math, regs); | ||
1067 | |||
1068 | switch (ret) { | ||
1069 | case 0: | ||
1070 | emulate_single_step(regs); | ||
1071 | return 0; | ||
1072 | case 1: { | ||
1073 | int code = 0; | ||
1074 | code = __parse_fpscr(current->thread.fpscr.val); | ||
1075 | _exception(SIGFPE, regs, code, regs->nip); | ||
1076 | return 0; | ||
1077 | } | ||
1078 | case -EFAULT: | ||
1079 | _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip); | ||
1080 | return 0; | ||
1081 | } | ||
1082 | |||
1083 | return -1; | ||
1084 | } | ||
1085 | #else | ||
1086 | static inline int emulate_math(struct pt_regs *regs) { return -1; } | ||
1087 | #endif | ||
1088 | |||
1058 | void __kprobes program_check_exception(struct pt_regs *regs) | 1089 | void __kprobes program_check_exception(struct pt_regs *regs) |
1059 | { | 1090 | { |
1060 | enum ctx_state prev_state = exception_enter(); | 1091 | enum ctx_state prev_state = exception_enter(); |
1061 | unsigned int reason = get_reason(regs); | 1092 | unsigned int reason = get_reason(regs); |
1062 | extern int do_mathemu(struct pt_regs *regs); | ||
1063 | 1093 | ||
1064 | /* We can now get here via a FP Unavailable exception if the core | 1094 | /* We can now get here via a FP Unavailable exception if the core |
1065 | * has no FPU, in that case the reason flags will be 0 */ | 1095 | * 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 | if (!arch_irq_disabled_regs(regs)) | 1155 | if (!arch_irq_disabled_regs(regs)) |
1126 | local_irq_enable(); | 1156 | local_irq_enable(); |
1127 | 1157 | ||
1128 | #ifdef CONFIG_MATH_EMULATION | ||
1129 | /* (reason & REASON_ILLEGAL) would be the obvious thing here, | 1158 | /* (reason & REASON_ILLEGAL) would be the obvious thing here, |
1130 | * but there seems to be a hardware bug on the 405GP (RevD) | 1159 | * but there seems to be a hardware bug on the 405GP (RevD) |
1131 | * that means ESR is sometimes set incorrectly - either to | 1160 | * that means ESR is sometimes set incorrectly - either to |
@@ -1134,22 +1163,8 @@ void __kprobes program_check_exception(struct pt_regs *regs) | |||
1134 | * instruction or only on FP instructions, whether there is a | 1163 | * instruction or only on FP instructions, whether there is a |
1135 | * pattern to occurrences etc. -dgibson 31/Mar/2003 | 1164 | * pattern to occurrences etc. -dgibson 31/Mar/2003 |
1136 | */ | 1165 | */ |
1137 | switch (do_mathemu(regs)) { | 1166 | if (!emulate_math(regs)) |
1138 | case 0: | ||
1139 | emulate_single_step(regs); | ||
1140 | goto bail; | ||
1141 | case 1: { | ||
1142 | int code = 0; | ||
1143 | code = __parse_fpscr(current->thread.fpscr.val); | ||
1144 | _exception(SIGFPE, regs, code, regs->nip); | ||
1145 | goto bail; | ||
1146 | } | ||
1147 | case -EFAULT: | ||
1148 | _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip); | ||
1149 | goto bail; | 1167 | goto bail; |
1150 | } | ||
1151 | /* fall through on any other errors */ | ||
1152 | #endif /* CONFIG_MATH_EMULATION */ | ||
1153 | 1168 | ||
1154 | /* Try to emulate it if we should. */ | 1169 | /* Try to emulate it if we should. */ |
1155 | if (reason & (REASON_ILLEGAL | REASON_PRIVILEGED)) { | 1170 | if (reason & (REASON_ILLEGAL | REASON_PRIVILEGED)) { |
@@ -1428,11 +1443,6 @@ void performance_monitor_exception(struct pt_regs *regs) | |||
1428 | #ifdef CONFIG_8xx | 1443 | #ifdef CONFIG_8xx |
1429 | void SoftwareEmulation(struct pt_regs *regs) | 1444 | void SoftwareEmulation(struct pt_regs *regs) |
1430 | { | 1445 | { |
1431 | extern int do_mathemu(struct pt_regs *); | ||
1432 | #if defined(CONFIG_MATH_EMULATION) | ||
1433 | int errcode; | ||
1434 | #endif | ||
1435 | |||
1436 | CHECK_FULL_REGS(regs); | 1446 | CHECK_FULL_REGS(regs); |
1437 | 1447 | ||
1438 | if (!user_mode(regs)) { | 1448 | if (!user_mode(regs)) { |
@@ -1440,31 +1450,10 @@ void SoftwareEmulation(struct pt_regs *regs) | |||
1440 | die("Kernel Mode Software FPU Emulation", regs, SIGFPE); | 1450 | die("Kernel Mode Software FPU Emulation", regs, SIGFPE); |
1441 | } | 1451 | } |
1442 | 1452 | ||
1443 | #ifdef CONFIG_MATH_EMULATION | 1453 | if (!emulate_math(regs)) |
1444 | errcode = do_mathemu(regs); | ||
1445 | if (errcode >= 0) | ||
1446 | PPC_WARN_EMULATED(math, regs); | ||
1447 | |||
1448 | switch (errcode) { | ||
1449 | case 0: | ||
1450 | emulate_single_step(regs); | ||
1451 | return; | ||
1452 | case 1: { | ||
1453 | int code = 0; | ||
1454 | code = __parse_fpscr(current->thread.fpscr.val); | ||
1455 | _exception(SIGFPE, regs, code, regs->nip); | ||
1456 | return; | ||
1457 | } | ||
1458 | case -EFAULT: | ||
1459 | _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip); | ||
1460 | return; | 1454 | return; |
1461 | default: | 1455 | |
1462 | _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); | ||
1463 | return; | ||
1464 | } | ||
1465 | #else | ||
1466 | _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); | 1456 | _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); |
1467 | #endif | ||
1468 | } | 1457 | } |
1469 | #endif /* CONFIG_8xx */ | 1458 | #endif /* CONFIG_8xx */ |
1470 | 1459 | ||