aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/lib
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2014-09-02 00:35:08 -0400
committerMichael Ellerman <mpe@ellerman.id.au>2014-09-25 09:14:51 -0400
commitcf87c3f6b64791ce5d4c7e591c915065d31a162d (patch)
tree3ca06fa36c998b21a839690cf1ac73ece11d9f03 /arch/powerpc/lib
parentbe96f63375a14ee8e690856ac77e579c75bd0bae (diff)
powerpc: Emulate icbi, mcrf and conditional-trap instructions
This extends the instruction emulation done by analyse_instr() and emulate_step() to handle a few more instructions that are found in the kernel. Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'arch/powerpc/lib')
-rw-r--r--arch/powerpc/lib/sstep.c60
1 files changed, 60 insertions, 0 deletions
diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c
index 3726a03179ab..209a506f8517 100644
--- a/arch/powerpc/lib/sstep.c
+++ b/arch/powerpc/lib/sstep.c
@@ -600,6 +600,23 @@ static void __kprobes do_cmp_unsigned(struct pt_regs *regs, unsigned long v1,
600 regs->ccr = (regs->ccr & ~(0xf << shift)) | (crval << shift); 600 regs->ccr = (regs->ccr & ~(0xf << shift)) | (crval << shift);
601} 601}
602 602
603static int __kprobes trap_compare(long v1, long v2)
604{
605 int ret = 0;
606
607 if (v1 < v2)
608 ret |= 0x10;
609 else if (v1 > v2)
610 ret |= 0x08;
611 else
612 ret |= 0x04;
613 if ((unsigned long)v1 < (unsigned long)v2)
614 ret |= 0x02;
615 else if ((unsigned long)v1 > (unsigned long)v2)
616 ret |= 0x01;
617 return ret;
618}
619
603/* 620/*
604 * Elements of 32-bit rotate and mask instructions. 621 * Elements of 32-bit rotate and mask instructions.
605 */ 622 */
@@ -669,6 +686,13 @@ int __kprobes analyse_instr(struct instruction_op *op, struct pt_regs *regs,
669 return 1; 686 return 1;
670 case 19: 687 case 19:
671 switch ((instr >> 1) & 0x3ff) { 688 switch ((instr >> 1) & 0x3ff) {
689 case 0: /* mcrf */
690 rd = (instr >> 21) & 0x1c;
691 ra = (instr >> 16) & 0x1c;
692 val = (regs->ccr >> ra) & 0xf;
693 regs->ccr = (regs->ccr & ~(0xfUL << rd)) | (val << rd);
694 goto instr_done;
695
672 case 16: /* bclr */ 696 case 16: /* bclr */
673 case 528: /* bcctr */ 697 case 528: /* bcctr */
674 op->type = BRANCH; 698 op->type = BRANCH;
@@ -745,6 +769,17 @@ int __kprobes analyse_instr(struct instruction_op *op, struct pt_regs *regs,
745 rb = (instr >> 11) & 0x1f; 769 rb = (instr >> 11) & 0x1f;
746 770
747 switch (opcode) { 771 switch (opcode) {
772#ifdef __powerpc64__
773 case 2: /* tdi */
774 if (rd & trap_compare(regs->gpr[ra], (short) instr))
775 goto trap;
776 goto instr_done;
777#endif
778 case 3: /* twi */
779 if (rd & trap_compare((int)regs->gpr[ra], (short) instr))
780 goto trap;
781 goto instr_done;
782
748 case 7: /* mulli */ 783 case 7: /* mulli */
749 regs->gpr[rd] = regs->gpr[ra] * (short) instr; 784 regs->gpr[rd] = regs->gpr[ra] * (short) instr;
750 goto instr_done; 785 goto instr_done;
@@ -893,6 +928,18 @@ int __kprobes analyse_instr(struct instruction_op *op, struct pt_regs *regs,
893 928
894 case 31: 929 case 31:
895 switch ((instr >> 1) & 0x3ff) { 930 switch ((instr >> 1) & 0x3ff) {
931 case 4: /* tw */
932 if (rd == 0x1f ||
933 (rd & trap_compare((int)regs->gpr[ra],
934 (int)regs->gpr[rb])))
935 goto trap;
936 goto instr_done;
937#ifdef __powerpc64__
938 case 68: /* td */
939 if (rd & trap_compare(regs->gpr[ra], regs->gpr[rb]))
940 goto trap;
941 goto instr_done;
942#endif
896 case 83: /* mfmsr */ 943 case 83: /* mfmsr */
897 if (regs->msr & MSR_PR) 944 if (regs->msr & MSR_PR)
898 goto priv; 945 goto priv;
@@ -1269,6 +1316,11 @@ int __kprobes analyse_instr(struct instruction_op *op, struct pt_regs *regs,
1269 op->ea = xform_ea(instr, regs); 1316 op->ea = xform_ea(instr, regs);
1270 op->reg = rd; 1317 op->reg = rd;
1271 return 0; 1318 return 0;
1319
1320 case 982: /* icbi */
1321 op->type = MKOP(CACHEOP, ICBI, 0);
1322 op->ea = xform_ea(instr, regs);
1323 return 0;
1272 } 1324 }
1273 break; 1325 break;
1274 } 1326 }
@@ -1597,6 +1649,11 @@ int __kprobes analyse_instr(struct instruction_op *op, struct pt_regs *regs,
1597 op->val = SRR1_PROGPRIV; 1649 op->val = SRR1_PROGPRIV;
1598 return 0; 1650 return 0;
1599 1651
1652 trap:
1653 op->type = INTERRUPT | 0x700;
1654 op->val = SRR1_PROGTRAP;
1655 return 0;
1656
1600#ifdef CONFIG_PPC_FPU 1657#ifdef CONFIG_PPC_FPU
1601 fpunavail: 1658 fpunavail:
1602 op->type = INTERRUPT | 0x800; 1659 op->type = INTERRUPT | 0x800;
@@ -1714,6 +1771,9 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
1714 if (op.reg == 0) 1771 if (op.reg == 0)
1715 prefetch((void *) op.ea); 1772 prefetch((void *) op.ea);
1716 break; 1773 break;
1774 case ICBI:
1775 __cacheop_user_asmx(op.ea, err, "icbi");
1776 break;
1717 } 1777 }
1718 if (err) 1778 if (err)
1719 return 0; 1779 return 0;