diff options
author | Paul Mackerras <paulus@samba.org> | 2014-09-02 00:35:08 -0400 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2014-09-25 09:14:51 -0400 |
commit | cf87c3f6b64791ce5d4c7e591c915065d31a162d (patch) | |
tree | 3ca06fa36c998b21a839690cf1ac73ece11d9f03 /arch/powerpc/lib | |
parent | be96f63375a14ee8e690856ac77e579c75bd0bae (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.c | 60 |
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 | ||
603 | static 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; |