diff options
Diffstat (limited to 'arch/powerpc/kernel/traps.c')
-rw-r--r-- | arch/powerpc/kernel/traps.c | 89 |
1 files changed, 59 insertions, 30 deletions
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index f18c79c324ef..bf33c22e38a4 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c | |||
@@ -866,6 +866,10 @@ static int emulate_string_inst(struct pt_regs *regs, u32 instword) | |||
866 | u8 val; | 866 | u8 val; |
867 | u32 shift = 8 * (3 - (pos & 0x3)); | 867 | u32 shift = 8 * (3 - (pos & 0x3)); |
868 | 868 | ||
869 | /* if process is 32-bit, clear upper 32 bits of EA */ | ||
870 | if ((regs->msr & MSR_64BIT) == 0) | ||
871 | EA &= 0xFFFFFFFF; | ||
872 | |||
869 | switch ((instword & PPC_INST_STRING_MASK)) { | 873 | switch ((instword & PPC_INST_STRING_MASK)) { |
870 | case PPC_INST_LSWX: | 874 | case PPC_INST_LSWX: |
871 | case PPC_INST_LSWI: | 875 | case PPC_INST_LSWI: |
@@ -1125,7 +1129,17 @@ void __kprobes program_check_exception(struct pt_regs *regs) | |||
1125 | * ESR_DST (!?) or 0. In the process of chasing this with the | 1129 | * ESR_DST (!?) or 0. In the process of chasing this with the |
1126 | * hardware people - not sure if it can happen on any illegal | 1130 | * hardware people - not sure if it can happen on any illegal |
1127 | * instruction or only on FP instructions, whether there is a | 1131 | * instruction or only on FP instructions, whether there is a |
1128 | * pattern to occurrences etc. -dgibson 31/Mar/2003 */ | 1132 | * pattern to occurrences etc. -dgibson 31/Mar/2003 |
1133 | */ | ||
1134 | |||
1135 | /* | ||
1136 | * If we support a HW FPU, we need to ensure the FP state | ||
1137 | * if flushed into the thread_struct before attempting | ||
1138 | * emulation | ||
1139 | */ | ||
1140 | #ifdef CONFIG_PPC_FPU | ||
1141 | flush_fp_to_thread(current); | ||
1142 | #endif | ||
1129 | switch (do_mathemu(regs)) { | 1143 | switch (do_mathemu(regs)) { |
1130 | case 0: | 1144 | case 0: |
1131 | emulate_single_step(regs); | 1145 | emulate_single_step(regs); |
@@ -1165,6 +1179,16 @@ bail: | |||
1165 | exception_exit(prev_state); | 1179 | exception_exit(prev_state); |
1166 | } | 1180 | } |
1167 | 1181 | ||
1182 | /* | ||
1183 | * This occurs when running in hypervisor mode on POWER6 or later | ||
1184 | * and an illegal instruction is encountered. | ||
1185 | */ | ||
1186 | void __kprobes emulation_assist_interrupt(struct pt_regs *regs) | ||
1187 | { | ||
1188 | regs->msr |= REASON_ILLEGAL; | ||
1189 | program_check_exception(regs); | ||
1190 | } | ||
1191 | |||
1168 | void alignment_exception(struct pt_regs *regs) | 1192 | void alignment_exception(struct pt_regs *regs) |
1169 | { | 1193 | { |
1170 | enum ctx_state prev_state = exception_enter(); | 1194 | enum ctx_state prev_state = exception_enter(); |
@@ -1272,25 +1296,50 @@ void vsx_unavailable_exception(struct pt_regs *regs) | |||
1272 | die("Unrecoverable VSX Unavailable Exception", regs, SIGABRT); | 1296 | die("Unrecoverable VSX Unavailable Exception", regs, SIGABRT); |
1273 | } | 1297 | } |
1274 | 1298 | ||
1275 | void tm_unavailable_exception(struct pt_regs *regs) | 1299 | void facility_unavailable_exception(struct pt_regs *regs) |
1276 | { | 1300 | { |
1301 | static char *facility_strings[] = { | ||
1302 | "FPU", | ||
1303 | "VMX/VSX", | ||
1304 | "DSCR", | ||
1305 | "PMU SPRs", | ||
1306 | "BHRB", | ||
1307 | "TM", | ||
1308 | "AT", | ||
1309 | "EBB", | ||
1310 | "TAR", | ||
1311 | }; | ||
1312 | char *facility, *prefix; | ||
1313 | u64 value; | ||
1314 | |||
1315 | if (regs->trap == 0xf60) { | ||
1316 | value = mfspr(SPRN_FSCR); | ||
1317 | prefix = ""; | ||
1318 | } else { | ||
1319 | value = mfspr(SPRN_HFSCR); | ||
1320 | prefix = "Hypervisor "; | ||
1321 | } | ||
1322 | |||
1323 | value = value >> 56; | ||
1324 | |||
1277 | /* We restore the interrupt state now */ | 1325 | /* We restore the interrupt state now */ |
1278 | if (!arch_irq_disabled_regs(regs)) | 1326 | if (!arch_irq_disabled_regs(regs)) |
1279 | local_irq_enable(); | 1327 | local_irq_enable(); |
1280 | 1328 | ||
1281 | /* Currently we never expect a TMU exception. Catch | 1329 | if (value < ARRAY_SIZE(facility_strings)) |
1282 | * this and kill the process! | 1330 | facility = facility_strings[value]; |
1283 | */ | 1331 | else |
1284 | printk(KERN_EMERG "Unexpected TM unavailable exception at %lx " | 1332 | facility = "unknown"; |
1285 | "(msr %lx)\n", | 1333 | |
1286 | regs->nip, regs->msr); | 1334 | pr_err("%sFacility '%s' unavailable, exception at 0x%lx, MSR=%lx\n", |
1335 | prefix, facility, regs->nip, regs->msr); | ||
1287 | 1336 | ||
1288 | if (user_mode(regs)) { | 1337 | if (user_mode(regs)) { |
1289 | _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); | 1338 | _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); |
1290 | return; | 1339 | return; |
1291 | } | 1340 | } |
1292 | 1341 | ||
1293 | die("Unexpected TM unavailable exception", regs, SIGABRT); | 1342 | die("Unexpected facility unavailable exception", regs, SIGABRT); |
1294 | } | 1343 | } |
1295 | 1344 | ||
1296 | #ifdef CONFIG_PPC_TRANSACTIONAL_MEM | 1345 | #ifdef CONFIG_PPC_TRANSACTIONAL_MEM |
@@ -1386,8 +1435,7 @@ void performance_monitor_exception(struct pt_regs *regs) | |||
1386 | void SoftwareEmulation(struct pt_regs *regs) | 1435 | void SoftwareEmulation(struct pt_regs *regs) |
1387 | { | 1436 | { |
1388 | extern int do_mathemu(struct pt_regs *); | 1437 | extern int do_mathemu(struct pt_regs *); |
1389 | extern int Soft_emulate_8xx(struct pt_regs *); | 1438 | #if defined(CONFIG_MATH_EMULATION) |
1390 | #if defined(CONFIG_MATH_EMULATION) || defined(CONFIG_8XX_MINIMAL_FPEMU) | ||
1391 | int errcode; | 1439 | int errcode; |
1392 | #endif | 1440 | #endif |
1393 | 1441 | ||
@@ -1420,23 +1468,6 @@ void SoftwareEmulation(struct pt_regs *regs) | |||
1420 | _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); | 1468 | _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); |
1421 | return; | 1469 | return; |
1422 | } | 1470 | } |
1423 | |||
1424 | #elif defined(CONFIG_8XX_MINIMAL_FPEMU) | ||
1425 | errcode = Soft_emulate_8xx(regs); | ||
1426 | if (errcode >= 0) | ||
1427 | PPC_WARN_EMULATED(8xx, regs); | ||
1428 | |||
1429 | switch (errcode) { | ||
1430 | case 0: | ||
1431 | emulate_single_step(regs); | ||
1432 | return; | ||
1433 | case 1: | ||
1434 | _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); | ||
1435 | return; | ||
1436 | case -EFAULT: | ||
1437 | _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip); | ||
1438 | return; | ||
1439 | } | ||
1440 | #else | 1471 | #else |
1441 | _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); | 1472 | _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); |
1442 | #endif | 1473 | #endif |
@@ -1786,8 +1817,6 @@ struct ppc_emulated ppc_emulated = { | |||
1786 | WARN_EMULATED_SETUP(unaligned), | 1817 | WARN_EMULATED_SETUP(unaligned), |
1787 | #ifdef CONFIG_MATH_EMULATION | 1818 | #ifdef CONFIG_MATH_EMULATION |
1788 | WARN_EMULATED_SETUP(math), | 1819 | WARN_EMULATED_SETUP(math), |
1789 | #elif defined(CONFIG_8XX_MINIMAL_FPEMU) | ||
1790 | WARN_EMULATED_SETUP(8xx), | ||
1791 | #endif | 1820 | #endif |
1792 | #ifdef CONFIG_VSX | 1821 | #ifdef CONFIG_VSX |
1793 | WARN_EMULATED_SETUP(vsx), | 1822 | WARN_EMULATED_SETUP(vsx), |