aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Hao <haokexin@gmail.com>2013-07-14 04:40:07 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-08-14 00:59:12 -0400
commit3a3b5aa63fad4911e239055c2c0a89ce2dac62ce (patch)
tree0254800fc0cb0f73eaa1d8a1ca3bfe96f47d1708
parent6761ee3d7e139ec8728e1515bfc5fdcaf3be317e (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.c79
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
1059static 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
1086static inline int emulate_math(struct pt_regs *regs) { return -1; }
1087#endif
1088
1058void __kprobes program_check_exception(struct pt_regs *regs) 1089void __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
1429void SoftwareEmulation(struct pt_regs *regs) 1444void 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