aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/traps.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/traps.c')
-rw-r--r--arch/powerpc/kernel/traps.c96
1 files changed, 94 insertions, 2 deletions
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 678fbff0d206..6a5b2b731f43 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -33,7 +33,9 @@
33#include <linux/backlight.h> 33#include <linux/backlight.h>
34#include <linux/bug.h> 34#include <linux/bug.h>
35#include <linux/kdebug.h> 35#include <linux/kdebug.h>
36#include <linux/debugfs.h>
36 37
38#include <asm/emulated_ops.h>
37#include <asm/pgtable.h> 39#include <asm/pgtable.h>
38#include <asm/uaccess.h> 40#include <asm/uaccess.h>
39#include <asm/system.h> 41#include <asm/system.h>
@@ -757,36 +759,44 @@ static int emulate_instruction(struct pt_regs *regs)
757 759
758 /* Emulate the mfspr rD, PVR. */ 760 /* Emulate the mfspr rD, PVR. */
759 if ((instword & PPC_INST_MFSPR_PVR_MASK) == PPC_INST_MFSPR_PVR) { 761 if ((instword & PPC_INST_MFSPR_PVR_MASK) == PPC_INST_MFSPR_PVR) {
762 PPC_WARN_EMULATED(mfpvr);
760 rd = (instword >> 21) & 0x1f; 763 rd = (instword >> 21) & 0x1f;
761 regs->gpr[rd] = mfspr(SPRN_PVR); 764 regs->gpr[rd] = mfspr(SPRN_PVR);
762 return 0; 765 return 0;
763 } 766 }
764 767
765 /* Emulating the dcba insn is just a no-op. */ 768 /* Emulating the dcba insn is just a no-op. */
766 if ((instword & PPC_INST_DCBA_MASK) == PPC_INST_DCBA) 769 if ((instword & PPC_INST_DCBA_MASK) == PPC_INST_DCBA) {
770 PPC_WARN_EMULATED(dcba);
767 return 0; 771 return 0;
772 }
768 773
769 /* Emulate the mcrxr insn. */ 774 /* Emulate the mcrxr insn. */
770 if ((instword & PPC_INST_MCRXR_MASK) == PPC_INST_MCRXR) { 775 if ((instword & PPC_INST_MCRXR_MASK) == PPC_INST_MCRXR) {
771 int shift = (instword >> 21) & 0x1c; 776 int shift = (instword >> 21) & 0x1c;
772 unsigned long msk = 0xf0000000UL >> shift; 777 unsigned long msk = 0xf0000000UL >> shift;
773 778
779 PPC_WARN_EMULATED(mcrxr);
774 regs->ccr = (regs->ccr & ~msk) | ((regs->xer >> shift) & msk); 780 regs->ccr = (regs->ccr & ~msk) | ((regs->xer >> shift) & msk);
775 regs->xer &= ~0xf0000000UL; 781 regs->xer &= ~0xf0000000UL;
776 return 0; 782 return 0;
777 } 783 }
778 784
779 /* Emulate load/store string insn. */ 785 /* Emulate load/store string insn. */
780 if ((instword & PPC_INST_STRING_GEN_MASK) == PPC_INST_STRING) 786 if ((instword & PPC_INST_STRING_GEN_MASK) == PPC_INST_STRING) {
787 PPC_WARN_EMULATED(string);
781 return emulate_string_inst(regs, instword); 788 return emulate_string_inst(regs, instword);
789 }
782 790
783 /* Emulate the popcntb (Population Count Bytes) instruction. */ 791 /* Emulate the popcntb (Population Count Bytes) instruction. */
784 if ((instword & PPC_INST_POPCNTB_MASK) == PPC_INST_POPCNTB) { 792 if ((instword & PPC_INST_POPCNTB_MASK) == PPC_INST_POPCNTB) {
793 PPC_WARN_EMULATED(popcntb);
785 return emulate_popcntb_inst(regs, instword); 794 return emulate_popcntb_inst(regs, instword);
786 } 795 }
787 796
788 /* Emulate isel (Integer Select) instruction */ 797 /* Emulate isel (Integer Select) instruction */
789 if ((instword & PPC_INST_ISEL_MASK) == PPC_INST_ISEL) { 798 if ((instword & PPC_INST_ISEL_MASK) == PPC_INST_ISEL) {
799 PPC_WARN_EMULATED(isel);
790 return emulate_isel(regs, instword); 800 return emulate_isel(regs, instword);
791 } 801 }
792 802
@@ -984,6 +994,8 @@ void SoftwareEmulation(struct pt_regs *regs)
984 994
985#ifdef CONFIG_MATH_EMULATION 995#ifdef CONFIG_MATH_EMULATION
986 errcode = do_mathemu(regs); 996 errcode = do_mathemu(regs);
997 if (errcode >= 0)
998 PPC_WARN_EMULATED(math);
987 999
988 switch (errcode) { 1000 switch (errcode) {
989 case 0: 1001 case 0:
@@ -1005,6 +1017,9 @@ void SoftwareEmulation(struct pt_regs *regs)
1005 1017
1006#elif defined(CONFIG_8XX_MINIMAL_FPEMU) 1018#elif defined(CONFIG_8XX_MINIMAL_FPEMU)
1007 errcode = Soft_emulate_8xx(regs); 1019 errcode = Soft_emulate_8xx(regs);
1020 if (errcode >= 0)
1021 PPC_WARN_EMULATED(8xx);
1022
1008 switch (errcode) { 1023 switch (errcode) {
1009 case 0: 1024 case 0:
1010 emulate_single_step(regs); 1025 emulate_single_step(regs);
@@ -1088,6 +1103,7 @@ void altivec_assist_exception(struct pt_regs *regs)
1088 1103
1089 flush_altivec_to_thread(current); 1104 flush_altivec_to_thread(current);
1090 1105
1106 PPC_WARN_EMULATED(altivec);
1091 err = emulate_altivec(regs); 1107 err = emulate_altivec(regs);
1092 if (err == 0) { 1108 if (err == 0) {
1093 regs->nip += 4; /* skip emulated instruction */ 1109 regs->nip += 4; /* skip emulated instruction */
@@ -1286,3 +1302,79 @@ void kernel_bad_stack(struct pt_regs *regs)
1286void __init trap_init(void) 1302void __init trap_init(void)
1287{ 1303{
1288} 1304}
1305
1306
1307#ifdef CONFIG_PPC_EMULATED_STATS
1308
1309#define WARN_EMULATED_SETUP(type) .type = { .name = #type }
1310
1311struct ppc_emulated ppc_emulated = {
1312#ifdef CONFIG_ALTIVEC
1313 WARN_EMULATED_SETUP(altivec),
1314#endif
1315 WARN_EMULATED_SETUP(dcba),
1316 WARN_EMULATED_SETUP(dcbz),
1317 WARN_EMULATED_SETUP(fp_pair),
1318 WARN_EMULATED_SETUP(isel),
1319 WARN_EMULATED_SETUP(mcrxr),
1320 WARN_EMULATED_SETUP(mfpvr),
1321 WARN_EMULATED_SETUP(multiple),
1322 WARN_EMULATED_SETUP(popcntb),
1323 WARN_EMULATED_SETUP(spe),
1324 WARN_EMULATED_SETUP(string),
1325 WARN_EMULATED_SETUP(unaligned),
1326#ifdef CONFIG_MATH_EMULATION
1327 WARN_EMULATED_SETUP(math),
1328#elif defined(CONFIG_8XX_MINIMAL_FPEMU)
1329 WARN_EMULATED_SETUP(8xx),
1330#endif
1331#ifdef CONFIG_VSX
1332 WARN_EMULATED_SETUP(vsx),
1333#endif
1334};
1335
1336u32 ppc_warn_emulated;
1337
1338void ppc_warn_emulated_print(const char *type)
1339{
1340 if (printk_ratelimit())
1341 pr_warning("%s used emulated %s instruction\n", current->comm,
1342 type);
1343}
1344
1345static int __init ppc_warn_emulated_init(void)
1346{
1347 struct dentry *dir, *d;
1348 unsigned int i;
1349 struct ppc_emulated_entry *entries = (void *)&ppc_emulated;
1350
1351 if (!powerpc_debugfs_root)
1352 return -ENODEV;
1353
1354 dir = debugfs_create_dir("emulated_instructions",
1355 powerpc_debugfs_root);
1356 if (!dir)
1357 return -ENOMEM;
1358
1359 d = debugfs_create_u32("do_warn", S_IRUGO | S_IWUSR, dir,
1360 &ppc_warn_emulated);
1361 if (!d)
1362 goto fail;
1363
1364 for (i = 0; i < sizeof(ppc_emulated)/sizeof(*entries); i++) {
1365 d = debugfs_create_u32(entries[i].name, S_IRUGO | S_IWUSR, dir,
1366 (u32 *)&entries[i].val.counter);
1367 if (!d)
1368 goto fail;
1369 }
1370
1371 return 0;
1372
1373fail:
1374 debugfs_remove_recursive(dir);
1375 return -ENOMEM;
1376}
1377
1378device_initcall(ppc_warn_emulated_init);
1379
1380#endif /* CONFIG_PPC_EMULATED_STATS */