diff options
author | Jon Medhurst <tixy@yxit.co.uk> | 2011-04-19 05:52:18 -0400 |
---|---|---|
committer | Nicolas Pitre <nicolas.pitre@linaro.org> | 2011-04-28 23:41:00 -0400 |
commit | 20e8155e24ba5c04558780d0a8da13c39f98c002 (patch) | |
tree | 27d7bcb62bb4964442a92eb05c2e679c2ea477af /arch | |
parent | c9836777d5f22e64eefc759d682511560b6d6d78 (diff) |
ARM: kprobes: Add emulation of SBFX, UBFX, BFI and BFC instructions
These bit field manipulation instructions occur several thousand
times in an ARMv7 kernel.
Signed-off-by: Jon Medhurst <tixy@yxit.co.uk>
Signed-off-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/kernel/kprobes-decode.c | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index a063f152d9b3..6bed8b089af0 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c | |||
@@ -672,6 +672,19 @@ emulate_rd12_modify(struct kprobe *p, struct pt_regs *regs) | |||
672 | regs->uregs[rd] = insnslot_1arg_rflags(rdv, regs->ARM_cpsr, i_fn); | 672 | regs->uregs[rd] = insnslot_1arg_rflags(rdv, regs->ARM_cpsr, i_fn); |
673 | } | 673 | } |
674 | 674 | ||
675 | static void __kprobes | ||
676 | emulate_rd12rn0_modify(struct kprobe *p, struct pt_regs *regs) | ||
677 | { | ||
678 | insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; | ||
679 | kprobe_opcode_t insn = p->opcode; | ||
680 | int rd = (insn >> 12) & 0xf; | ||
681 | int rn = insn & 0xf; | ||
682 | long rdv = regs->uregs[rd]; | ||
683 | long rnv = regs->uregs[rn]; | ||
684 | |||
685 | regs->uregs[rd] = insnslot_2arg_rflags(rdv, rnv, regs->ARM_cpsr, i_fn); | ||
686 | } | ||
687 | |||
675 | static void __kprobes emulate_rd12rm0(struct kprobe *p, struct pt_regs *regs) | 688 | static void __kprobes emulate_rd12rm0(struct kprobe *p, struct pt_regs *regs) |
676 | { | 689 | { |
677 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | 690 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; |
@@ -870,6 +883,20 @@ prep_emulate_rd12_modify(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
870 | } | 883 | } |
871 | 884 | ||
872 | static enum kprobe_insn __kprobes | 885 | static enum kprobe_insn __kprobes |
886 | prep_emulate_rd12rn0_modify(kprobe_opcode_t insn, | ||
887 | struct arch_specific_insn *asi) | ||
888 | { | ||
889 | if (is_r15(insn, 12)) | ||
890 | return INSN_REJECTED; /* Rd is PC */ | ||
891 | |||
892 | insn &= 0xffff0ff0; /* Rd = r0 */ | ||
893 | insn |= 0x00000001; /* Rn = r1 */ | ||
894 | asi->insn[0] = insn; | ||
895 | asi->insn_handler = emulate_rd12rn0_modify; | ||
896 | return INSN_GOOD; | ||
897 | } | ||
898 | |||
899 | static enum kprobe_insn __kprobes | ||
873 | prep_emulate_rd12rm0(kprobe_opcode_t insn, struct arch_specific_insn *asi) | 900 | prep_emulate_rd12rm0(kprobe_opcode_t insn, struct arch_specific_insn *asi) |
874 | { | 901 | { |
875 | if (is_r15(insn, 12)) | 902 | if (is_r15(insn, 12)) |
@@ -1396,6 +1423,21 @@ space_cccc_0111__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
1396 | if ((insn & 0x0ff000d0) == 0x075000d0) | 1423 | if ((insn & 0x0ff000d0) == 0x075000d0) |
1397 | return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); | 1424 | return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); |
1398 | 1425 | ||
1426 | /* SBFX : cccc 0111 101x xxxx xxxx xxxx x101 xxxx : */ | ||
1427 | /* UBFX : cccc 0111 111x xxxx xxxx xxxx x101 xxxx : */ | ||
1428 | if ((insn & 0x0fa00070) == 0x07a00050) | ||
1429 | return prep_emulate_rd12rm0(insn, asi); | ||
1430 | |||
1431 | /* BFI : cccc 0111 110x xxxx xxxx xxxx x001 xxxx : */ | ||
1432 | /* BFC : cccc 0111 110x xxxx xxxx xxxx x001 1111 : */ | ||
1433 | if ((insn & 0x0fe00070) == 0x07c00010) { | ||
1434 | |||
1435 | if ((insn & 0x0000000f) == 0x0000000f) | ||
1436 | return prep_emulate_rd12_modify(insn, asi); | ||
1437 | else | ||
1438 | return prep_emulate_rd12rn0_modify(insn, asi); | ||
1439 | } | ||
1440 | |||
1399 | return INSN_REJECTED; | 1441 | return INSN_REJECTED; |
1400 | } | 1442 | } |
1401 | 1443 | ||