diff options
author | Jon Medhurst <tixy@yxit.co.uk> | 2011-07-02 10:36:32 -0400 |
---|---|---|
committer | Tixy <tixy@medhuaa1.miniserver.com> | 2011-07-13 13:32:43 -0400 |
commit | 3f92dfed6a9a5f490128c8e7cc6a64dfe412994f (patch) | |
tree | 1d503b19d01075dfd1db1023b8d0e787f9d58bb6 | |
parent | 0d1a095aa1e6e2a233bfb1729e15233e77f69d54 (diff) |
ARM: kprobes: Decode 16-bit Thumb hint instructions
For hints which may have observable effects, like SEV (send event), we
use kprobe_emulate_none which emulates the hint by executing the
original instruction.
For NOP we simulate the instruction using kprobe_simulate_nop, which
does nothing. As probes execute with interrupts disabled this is also
used for hints which may block for an indefinite time, like WFE (wait
for event).
Signed-off-by: Jon Medhurst <tixy@yxit.co.uk>
Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org>
-rw-r--r-- | arch/arm/kernel/kprobes-common.c | 9 | ||||
-rw-r--r-- | arch/arm/kernel/kprobes-thumb.c | 35 | ||||
-rw-r--r-- | arch/arm/kernel/kprobes.h | 3 |
3 files changed, 46 insertions, 1 deletions
diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/kernel/kprobes-common.c index 1cb6a82a5e24..3a3e765d2090 100644 --- a/arch/arm/kernel/kprobes-common.c +++ b/arch/arm/kernel/kprobes-common.c | |||
@@ -142,6 +142,15 @@ kprobe_check_cc * const kprobe_condition_checks[16] = { | |||
142 | }; | 142 | }; |
143 | 143 | ||
144 | 144 | ||
145 | void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs) | ||
146 | { | ||
147 | } | ||
148 | |||
149 | void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs) | ||
150 | { | ||
151 | p->ainsn.insn_fn(); | ||
152 | } | ||
153 | |||
145 | /* | 154 | /* |
146 | * Prepare an instruction slot to receive an instruction for emulating. | 155 | * Prepare an instruction slot to receive an instruction for emulating. |
147 | * This is done by placing a subroutine return after the location where the | 156 | * This is done by placing a subroutine return after the location where the |
diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/kernel/kprobes-thumb.c index 973c3eb1243a..7dcf6df4a85c 100644 --- a/arch/arm/kernel/kprobes-thumb.c +++ b/arch/arm/kernel/kprobes-thumb.c | |||
@@ -26,6 +26,39 @@ | |||
26 | */ | 26 | */ |
27 | #define current_cond(cpsr) ((cpsr >> 12) & 0xf) | 27 | #define current_cond(cpsr) ((cpsr >> 12) & 0xf) |
28 | 28 | ||
29 | static const union decode_item t16_table_1011[] = { | ||
30 | /* Miscellaneous 16-bit instructions */ | ||
31 | |||
32 | /* | ||
33 | * If-Then, and hints | ||
34 | * 1011 1111 xxxx xxxx | ||
35 | */ | ||
36 | |||
37 | /* YIELD 1011 1111 0001 0000 */ | ||
38 | DECODE_OR (0xffff, 0xbf10), | ||
39 | /* SEV 1011 1111 0100 0000 */ | ||
40 | DECODE_EMULATE (0xffff, 0xbf40, kprobe_emulate_none), | ||
41 | /* NOP 1011 1111 0000 0000 */ | ||
42 | /* WFE 1011 1111 0010 0000 */ | ||
43 | /* WFI 1011 1111 0011 0000 */ | ||
44 | DECODE_SIMULATE (0xffcf, 0xbf00, kprobe_simulate_nop), | ||
45 | /* Unassigned hints 1011 1111 xxxx 0000 */ | ||
46 | DECODE_REJECT (0xff0f, 0xbf00), | ||
47 | |||
48 | DECODE_END | ||
49 | }; | ||
50 | |||
51 | const union decode_item kprobe_decode_thumb16_table[] = { | ||
52 | |||
53 | /* | ||
54 | * Miscellaneous 16-bit instructions | ||
55 | * 1011 xxxx xxxx xxxx | ||
56 | */ | ||
57 | DECODE_TABLE (0xf000, 0xb000, t16_table_1011), | ||
58 | |||
59 | DECODE_END | ||
60 | }; | ||
61 | |||
29 | static unsigned long __kprobes thumb_check_cc(unsigned long cpsr) | 62 | static unsigned long __kprobes thumb_check_cc(unsigned long cpsr) |
30 | { | 63 | { |
31 | if (unlikely(in_it_block(cpsr))) | 64 | if (unlikely(in_it_block(cpsr))) |
@@ -52,7 +85,7 @@ thumb16_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
52 | { | 85 | { |
53 | asi->insn_singlestep = thumb16_singlestep; | 86 | asi->insn_singlestep = thumb16_singlestep; |
54 | asi->insn_check_cc = thumb_check_cc; | 87 | asi->insn_check_cc = thumb_check_cc; |
55 | return INSN_REJECTED; | 88 | return kprobe_decode_insn(insn, asi, kprobe_decode_thumb16_table, true); |
56 | } | 89 | } |
57 | 90 | ||
58 | enum kprobe_insn __kprobes | 91 | enum kprobe_insn __kprobes |
diff --git a/arch/arm/kernel/kprobes.h b/arch/arm/kernel/kprobes.h index c00681ce5cce..36e07684fe08 100644 --- a/arch/arm/kernel/kprobes.h +++ b/arch/arm/kernel/kprobes.h | |||
@@ -95,6 +95,9 @@ static inline unsigned long it_advance(unsigned long cpsr) | |||
95 | return cpsr; | 95 | return cpsr; |
96 | } | 96 | } |
97 | 97 | ||
98 | void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs); | ||
99 | void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs); | ||
100 | |||
98 | /* | 101 | /* |
99 | * Test if load/store instructions writeback the address register. | 102 | * Test if load/store instructions writeback the address register. |
100 | * if P (bit 24) == 0 or W (bit 21) == 1 | 103 | * if P (bit 24) == 0 or W (bit 21) == 1 |