diff options
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/kernel/dma-isa.c | 2 | ||||
-rw-r--r-- | arch/arm/kernel/entry-armv.S | 63 | ||||
-rw-r--r-- | arch/arm/kernel/entry-common.S | 2 | ||||
-rw-r--r-- | arch/arm/kernel/kprobes-decode.c | 1529 | ||||
-rw-r--r-- | arch/arm/kernel/kprobes.c | 447 | ||||
-rw-r--r-- | arch/arm/kernel/time.c | 2 | ||||
-rw-r--r-- | arch/arm/kernel/traps.c | 21 | ||||
-rw-r--r-- | arch/arm/kernel/vmlinux.lds.S | 1 |
9 files changed, 2051 insertions, 17 deletions
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 593b56509f4f..faa761921153 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile | |||
@@ -19,6 +19,7 @@ obj-$(CONFIG_ISA_DMA) += dma-isa.o | |||
19 | obj-$(CONFIG_PCI) += bios32.o isa.o | 19 | obj-$(CONFIG_PCI) += bios32.o isa.o |
20 | obj-$(CONFIG_SMP) += smp.o | 20 | obj-$(CONFIG_SMP) += smp.o |
21 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o | 21 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o |
22 | obj-$(CONFIG_KPROBES) += kprobes.o kprobes-decode.o | ||
22 | obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o | 23 | obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o |
23 | 24 | ||
24 | obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o | 25 | obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o |
diff --git a/arch/arm/kernel/dma-isa.c b/arch/arm/kernel/dma-isa.c index 0a3e9ad297d8..2f080a35a2d9 100644 --- a/arch/arm/kernel/dma-isa.c +++ b/arch/arm/kernel/dma-isa.c | |||
@@ -216,7 +216,7 @@ void __init isa_init_dma(dma_t *dma) | |||
216 | 216 | ||
217 | request_dma(DMA_ISA_CASCADE, "cascade"); | 217 | request_dma(DMA_ISA_CASCADE, "cascade"); |
218 | 218 | ||
219 | for (i = 0; i < sizeof(dma_resources) / sizeof(dma_resources[0]); i++) | 219 | for (i = 0; i < ARRAY_SIZE(dma_resources); i++) |
220 | request_resource(&ioport_resource, dma_resources + i); | 220 | request_resource(&ioport_resource, dma_resources + i); |
221 | } | 221 | } |
222 | } | 222 | } |
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 29dec080a604..a46d5b456765 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S | |||
@@ -11,8 +11,8 @@ | |||
11 | * | 11 | * |
12 | * Low-level vector interface routines | 12 | * Low-level vector interface routines |
13 | * | 13 | * |
14 | * Note: there is a StrongARM bug in the STMIA rn, {regs}^ instruction that causes | 14 | * Note: there is a StrongARM bug in the STMIA rn, {regs}^ instruction |
15 | * it to save wrong values... Be aware! | 15 | * that causes it to save wrong values... Be aware! |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <asm/memory.h> | 18 | #include <asm/memory.h> |
@@ -58,6 +58,12 @@ | |||
58 | 58 | ||
59 | .endm | 59 | .endm |
60 | 60 | ||
61 | #ifdef CONFIG_KPROBES | ||
62 | .section .kprobes.text,"ax",%progbits | ||
63 | #else | ||
64 | .text | ||
65 | #endif | ||
66 | |||
61 | /* | 67 | /* |
62 | * Invalid mode handlers | 68 | * Invalid mode handlers |
63 | */ | 69 | */ |
@@ -112,8 +118,8 @@ common_invalid: | |||
112 | #define SPFIX(code...) | 118 | #define SPFIX(code...) |
113 | #endif | 119 | #endif |
114 | 120 | ||
115 | .macro svc_entry | 121 | .macro svc_entry, stack_hole=0 |
116 | sub sp, sp, #S_FRAME_SIZE | 122 | sub sp, sp, #(S_FRAME_SIZE + \stack_hole) |
117 | SPFIX( tst sp, #4 ) | 123 | SPFIX( tst sp, #4 ) |
118 | SPFIX( bicne sp, sp, #4 ) | 124 | SPFIX( bicne sp, sp, #4 ) |
119 | stmib sp, {r1 - r12} | 125 | stmib sp, {r1 - r12} |
@@ -121,7 +127,7 @@ common_invalid: | |||
121 | ldmia r0, {r1 - r3} | 127 | ldmia r0, {r1 - r3} |
122 | add r5, sp, #S_SP @ here for interlock avoidance | 128 | add r5, sp, #S_SP @ here for interlock avoidance |
123 | mov r4, #-1 @ "" "" "" "" | 129 | mov r4, #-1 @ "" "" "" "" |
124 | add r0, sp, #S_FRAME_SIZE @ "" "" "" "" | 130 | add r0, sp, #(S_FRAME_SIZE + \stack_hole) |
125 | SPFIX( addne r0, r0, #4 ) | 131 | SPFIX( addne r0, r0, #4 ) |
126 | str r1, [sp] @ save the "real" r0 copied | 132 | str r1, [sp] @ save the "real" r0 copied |
127 | @ from the exception stack | 133 | @ from the exception stack |
@@ -242,7 +248,14 @@ svc_preempt: | |||
242 | 248 | ||
243 | .align 5 | 249 | .align 5 |
244 | __und_svc: | 250 | __und_svc: |
251 | #ifdef CONFIG_KPROBES | ||
252 | @ If a kprobe is about to simulate a "stmdb sp..." instruction, | ||
253 | @ it obviously needs free stack space which then will belong to | ||
254 | @ the saved context. | ||
255 | svc_entry 64 | ||
256 | #else | ||
245 | svc_entry | 257 | svc_entry |
258 | #endif | ||
246 | 259 | ||
247 | @ | 260 | @ |
248 | @ call emulation code, which returns using r9 if it has emulated | 261 | @ call emulation code, which returns using r9 if it has emulated |
@@ -480,6 +493,13 @@ __und_usr: | |||
480 | * co-processor instructions. However, we have to watch out | 493 | * co-processor instructions. However, we have to watch out |
481 | * for the ARM6/ARM7 SWI bug. | 494 | * for the ARM6/ARM7 SWI bug. |
482 | * | 495 | * |
496 | * NEON is a special case that has to be handled here. Not all | ||
497 | * NEON instructions are co-processor instructions, so we have | ||
498 | * to make a special case of checking for them. Plus, there's | ||
499 | * five groups of them, so we have a table of mask/opcode pairs | ||
500 | * to check against, and if any match then we branch off into the | ||
501 | * NEON handler code. | ||
502 | * | ||
483 | * Emulators may wish to make use of the following registers: | 503 | * Emulators may wish to make use of the following registers: |
484 | * r0 = instruction opcode. | 504 | * r0 = instruction opcode. |
485 | * r2 = PC+4 | 505 | * r2 = PC+4 |
@@ -488,6 +508,23 @@ __und_usr: | |||
488 | * lr = unrecognised instruction return address | 508 | * lr = unrecognised instruction return address |
489 | */ | 509 | */ |
490 | call_fpe: | 510 | call_fpe: |
511 | #ifdef CONFIG_NEON | ||
512 | adr r6, .LCneon_opcodes | ||
513 | 2: | ||
514 | ldr r7, [r6], #4 @ mask value | ||
515 | cmp r7, #0 @ end mask? | ||
516 | beq 1f | ||
517 | and r8, r0, r7 | ||
518 | ldr r7, [r6], #4 @ opcode bits matching in mask | ||
519 | cmp r8, r7 @ NEON instruction? | ||
520 | bne 2b | ||
521 | get_thread_info r10 | ||
522 | mov r7, #1 | ||
523 | strb r7, [r10, #TI_USED_CP + 10] @ mark CP#10 as used | ||
524 | strb r7, [r10, #TI_USED_CP + 11] @ mark CP#11 as used | ||
525 | b do_vfp @ let VFP handler handle this | ||
526 | 1: | ||
527 | #endif | ||
491 | tst r0, #0x08000000 @ only CDP/CPRT/LDC/STC have bit 27 | 528 | tst r0, #0x08000000 @ only CDP/CPRT/LDC/STC have bit 27 |
492 | #if defined(CONFIG_CPU_ARM610) || defined(CONFIG_CPU_ARM710) | 529 | #if defined(CONFIG_CPU_ARM610) || defined(CONFIG_CPU_ARM710) |
493 | and r8, r0, #0x0f000000 @ mask out op-code bits | 530 | and r8, r0, #0x0f000000 @ mask out op-code bits |
@@ -537,6 +574,20 @@ call_fpe: | |||
537 | mov pc, lr @ CP#14 (Debug) | 574 | mov pc, lr @ CP#14 (Debug) |
538 | mov pc, lr @ CP#15 (Control) | 575 | mov pc, lr @ CP#15 (Control) |
539 | 576 | ||
577 | #ifdef CONFIG_NEON | ||
578 | .align 6 | ||
579 | |||
580 | .LCneon_opcodes: | ||
581 | .word 0xfe000000 @ mask | ||
582 | .word 0xf2000000 @ opcode | ||
583 | |||
584 | .word 0xff100000 @ mask | ||
585 | .word 0xf4000000 @ opcode | ||
586 | |||
587 | .word 0x00000000 @ mask | ||
588 | .word 0x00000000 @ opcode | ||
589 | #endif | ||
590 | |||
540 | do_fpe: | 591 | do_fpe: |
541 | enable_irq | 592 | enable_irq |
542 | ldr r4, .LCfp | 593 | ldr r4, .LCfp |
@@ -555,7 +606,7 @@ do_fpe: | |||
555 | .data | 606 | .data |
556 | ENTRY(fp_enter) | 607 | ENTRY(fp_enter) |
557 | .word no_fp | 608 | .word no_fp |
558 | .text | 609 | .previous |
559 | 610 | ||
560 | no_fp: mov pc, lr | 611 | no_fp: mov pc, lr |
561 | 612 | ||
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 33e6cc2ffd3b..6c90c50a9ee3 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S | |||
@@ -72,7 +72,7 @@ no_work_pending: | |||
72 | ldr r1, [sp, #S_PSR] @ get calling cpsr | 72 | ldr r1, [sp, #S_PSR] @ get calling cpsr |
73 | ldr lr, [sp, #S_PC]! @ get pc | 73 | ldr lr, [sp, #S_PC]! @ get pc |
74 | msr spsr_cxsf, r1 @ save in spsr_svc | 74 | msr spsr_cxsf, r1 @ save in spsr_svc |
75 | ldmdb sp, {r0 - lr}^ @ get calling r1 - lr | 75 | ldmdb sp, {r0 - lr}^ @ get calling r0 - lr |
76 | mov r0, r0 | 76 | mov r0, r0 |
77 | add sp, sp, #S_FRAME_SIZE - S_PC | 77 | add sp, sp, #S_FRAME_SIZE - S_PC |
78 | movs pc, lr @ return & move spsr_svc into cpsr | 78 | movs pc, lr @ return & move spsr_svc into cpsr |
diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c new file mode 100644 index 000000000000..d51bc8b60557 --- /dev/null +++ b/arch/arm/kernel/kprobes-decode.c | |||
@@ -0,0 +1,1529 @@ | |||
1 | /* | ||
2 | * arch/arm/kernel/kprobes-decode.c | ||
3 | * | ||
4 | * Copyright (C) 2006, 2007 Motorola Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | /* | ||
17 | * We do not have hardware single-stepping on ARM, This | ||
18 | * effort is further complicated by the ARM not having a | ||
19 | * "next PC" register. Instructions that change the PC | ||
20 | * can't be safely single-stepped in a MP environment, so | ||
21 | * we have a lot of work to do: | ||
22 | * | ||
23 | * In the prepare phase: | ||
24 | * *) If it is an instruction that does anything | ||
25 | * with the CPU mode, we reject it for a kprobe. | ||
26 | * (This is out of laziness rather than need. The | ||
27 | * instructions could be simulated.) | ||
28 | * | ||
29 | * *) Otherwise, decode the instruction rewriting its | ||
30 | * registers to take fixed, ordered registers and | ||
31 | * setting a handler for it to run the instruction. | ||
32 | * | ||
33 | * In the execution phase by an instruction's handler: | ||
34 | * | ||
35 | * *) If the PC is written to by the instruction, the | ||
36 | * instruction must be fully simulated in software. | ||
37 | * If it is a conditional instruction, the handler | ||
38 | * will use insn[0] to copy its condition code to | ||
39 | * set r0 to 1 and insn[1] to "mov pc, lr" to return. | ||
40 | * | ||
41 | * *) Otherwise, a modified form of the instruction is | ||
42 | * directly executed. Its handler calls the | ||
43 | * instruction in insn[0]. In insn[1] is a | ||
44 | * "mov pc, lr" to return. | ||
45 | * | ||
46 | * Before calling, load up the reordered registers | ||
47 | * from the original instruction's registers. If one | ||
48 | * of the original input registers is the PC, compute | ||
49 | * and adjust the appropriate input register. | ||
50 | * | ||
51 | * After call completes, copy the output registers to | ||
52 | * the original instruction's original registers. | ||
53 | * | ||
54 | * We don't use a real breakpoint instruction since that | ||
55 | * would have us in the kernel go from SVC mode to SVC | ||
56 | * mode losing the link register. Instead we use an | ||
57 | * undefined instruction. To simplify processing, the | ||
58 | * undefined instruction used for kprobes must be reserved | ||
59 | * exclusively for kprobes use. | ||
60 | * | ||
61 | * TODO: ifdef out some instruction decoding based on architecture. | ||
62 | */ | ||
63 | |||
64 | #include <linux/kernel.h> | ||
65 | #include <linux/kprobes.h> | ||
66 | |||
67 | #define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit))))) | ||
68 | |||
69 | #define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25) | ||
70 | |||
71 | #define PSR_fs (PSR_f|PSR_s) | ||
72 | |||
73 | #define KPROBE_RETURN_INSTRUCTION 0xe1a0f00e /* mov pc, lr */ | ||
74 | #define SET_R0_TRUE_INSTRUCTION 0xe3a00001 /* mov r0, #1 */ | ||
75 | |||
76 | #define truecc_insn(insn) (((insn) & 0xf0000000) | \ | ||
77 | (SET_R0_TRUE_INSTRUCTION & 0x0fffffff)) | ||
78 | |||
79 | typedef long (insn_0arg_fn_t)(void); | ||
80 | typedef long (insn_1arg_fn_t)(long); | ||
81 | typedef long (insn_2arg_fn_t)(long, long); | ||
82 | typedef long (insn_3arg_fn_t)(long, long, long); | ||
83 | typedef long (insn_4arg_fn_t)(long, long, long, long); | ||
84 | typedef long long (insn_llret_0arg_fn_t)(void); | ||
85 | typedef long long (insn_llret_3arg_fn_t)(long, long, long); | ||
86 | typedef long long (insn_llret_4arg_fn_t)(long, long, long, long); | ||
87 | |||
88 | union reg_pair { | ||
89 | long long dr; | ||
90 | #ifdef __LITTLE_ENDIAN | ||
91 | struct { long r0, r1; }; | ||
92 | #else | ||
93 | struct { long r1, r0; }; | ||
94 | #endif | ||
95 | }; | ||
96 | |||
97 | /* | ||
98 | * For STR and STM instructions, an ARM core may choose to use either | ||
99 | * a +8 or a +12 displacement from the current instruction's address. | ||
100 | * Whichever value is chosen for a given core, it must be the same for | ||
101 | * both instructions and may not change. This function measures it. | ||
102 | */ | ||
103 | |||
104 | static int str_pc_offset; | ||
105 | |||
106 | static void __init find_str_pc_offset(void) | ||
107 | { | ||
108 | int addr, scratch, ret; | ||
109 | |||
110 | __asm__ ( | ||
111 | "sub %[ret], pc, #4 \n\t" | ||
112 | "str pc, %[addr] \n\t" | ||
113 | "ldr %[scr], %[addr] \n\t" | ||
114 | "sub %[ret], %[scr], %[ret] \n\t" | ||
115 | : [ret] "=r" (ret), [scr] "=r" (scratch), [addr] "+m" (addr)); | ||
116 | |||
117 | str_pc_offset = ret; | ||
118 | } | ||
119 | |||
120 | /* | ||
121 | * The insnslot_?arg_r[w]flags() functions below are to keep the | ||
122 | * msr -> *fn -> mrs instruction sequences indivisible so that | ||
123 | * the state of the CPSR flags aren't inadvertently modified | ||
124 | * just before or just after the call. | ||
125 | */ | ||
126 | |||
127 | static inline long __kprobes | ||
128 | insnslot_0arg_rflags(long cpsr, insn_0arg_fn_t *fn) | ||
129 | { | ||
130 | register long ret asm("r0"); | ||
131 | |||
132 | __asm__ __volatile__ ( | ||
133 | "msr cpsr_fs, %[cpsr] \n\t" | ||
134 | "mov lr, pc \n\t" | ||
135 | "mov pc, %[fn] \n\t" | ||
136 | : "=r" (ret) | ||
137 | : [cpsr] "r" (cpsr), [fn] "r" (fn) | ||
138 | : "lr", "cc" | ||
139 | ); | ||
140 | return ret; | ||
141 | } | ||
142 | |||
143 | static inline long long __kprobes | ||
144 | insnslot_llret_0arg_rflags(long cpsr, insn_llret_0arg_fn_t *fn) | ||
145 | { | ||
146 | register long ret0 asm("r0"); | ||
147 | register long ret1 asm("r1"); | ||
148 | union reg_pair fnr; | ||
149 | |||
150 | __asm__ __volatile__ ( | ||
151 | "msr cpsr_fs, %[cpsr] \n\t" | ||
152 | "mov lr, pc \n\t" | ||
153 | "mov pc, %[fn] \n\t" | ||
154 | : "=r" (ret0), "=r" (ret1) | ||
155 | : [cpsr] "r" (cpsr), [fn] "r" (fn) | ||
156 | : "lr", "cc" | ||
157 | ); | ||
158 | fnr.r0 = ret0; | ||
159 | fnr.r1 = ret1; | ||
160 | return fnr.dr; | ||
161 | } | ||
162 | |||
163 | static inline long __kprobes | ||
164 | insnslot_1arg_rflags(long r0, long cpsr, insn_1arg_fn_t *fn) | ||
165 | { | ||
166 | register long rr0 asm("r0") = r0; | ||
167 | register long ret asm("r0"); | ||
168 | |||
169 | __asm__ __volatile__ ( | ||
170 | "msr cpsr_fs, %[cpsr] \n\t" | ||
171 | "mov lr, pc \n\t" | ||
172 | "mov pc, %[fn] \n\t" | ||
173 | : "=r" (ret) | ||
174 | : "0" (rr0), [cpsr] "r" (cpsr), [fn] "r" (fn) | ||
175 | : "lr", "cc" | ||
176 | ); | ||
177 | return ret; | ||
178 | } | ||
179 | |||
180 | static inline long __kprobes | ||
181 | insnslot_2arg_rflags(long r0, long r1, long cpsr, insn_2arg_fn_t *fn) | ||
182 | { | ||
183 | register long rr0 asm("r0") = r0; | ||
184 | register long rr1 asm("r1") = r1; | ||
185 | register long ret asm("r0"); | ||
186 | |||
187 | __asm__ __volatile__ ( | ||
188 | "msr cpsr_fs, %[cpsr] \n\t" | ||
189 | "mov lr, pc \n\t" | ||
190 | "mov pc, %[fn] \n\t" | ||
191 | : "=r" (ret) | ||
192 | : "0" (rr0), "r" (rr1), | ||
193 | [cpsr] "r" (cpsr), [fn] "r" (fn) | ||
194 | : "lr", "cc" | ||
195 | ); | ||
196 | return ret; | ||
197 | } | ||
198 | |||
199 | static inline long __kprobes | ||
200 | insnslot_3arg_rflags(long r0, long r1, long r2, long cpsr, insn_3arg_fn_t *fn) | ||
201 | { | ||
202 | register long rr0 asm("r0") = r0; | ||
203 | register long rr1 asm("r1") = r1; | ||
204 | register long rr2 asm("r2") = r2; | ||
205 | register long ret asm("r0"); | ||
206 | |||
207 | __asm__ __volatile__ ( | ||
208 | "msr cpsr_fs, %[cpsr] \n\t" | ||
209 | "mov lr, pc \n\t" | ||
210 | "mov pc, %[fn] \n\t" | ||
211 | : "=r" (ret) | ||
212 | : "0" (rr0), "r" (rr1), "r" (rr2), | ||
213 | [cpsr] "r" (cpsr), [fn] "r" (fn) | ||
214 | : "lr", "cc" | ||
215 | ); | ||
216 | return ret; | ||
217 | } | ||
218 | |||
219 | static inline long long __kprobes | ||
220 | insnslot_llret_3arg_rflags(long r0, long r1, long r2, long cpsr, | ||
221 | insn_llret_3arg_fn_t *fn) | ||
222 | { | ||
223 | register long rr0 asm("r0") = r0; | ||
224 | register long rr1 asm("r1") = r1; | ||
225 | register long rr2 asm("r2") = r2; | ||
226 | register long ret0 asm("r0"); | ||
227 | register long ret1 asm("r1"); | ||
228 | union reg_pair fnr; | ||
229 | |||
230 | __asm__ __volatile__ ( | ||
231 | "msr cpsr_fs, %[cpsr] \n\t" | ||
232 | "mov lr, pc \n\t" | ||
233 | "mov pc, %[fn] \n\t" | ||
234 | : "=r" (ret0), "=r" (ret1) | ||
235 | : "0" (rr0), "r" (rr1), "r" (rr2), | ||
236 | [cpsr] "r" (cpsr), [fn] "r" (fn) | ||
237 | : "lr", "cc" | ||
238 | ); | ||
239 | fnr.r0 = ret0; | ||
240 | fnr.r1 = ret1; | ||
241 | return fnr.dr; | ||
242 | } | ||
243 | |||
244 | static inline long __kprobes | ||
245 | insnslot_4arg_rflags(long r0, long r1, long r2, long r3, long cpsr, | ||
246 | insn_4arg_fn_t *fn) | ||
247 | { | ||
248 | register long rr0 asm("r0") = r0; | ||
249 | register long rr1 asm("r1") = r1; | ||
250 | register long rr2 asm("r2") = r2; | ||
251 | register long rr3 asm("r3") = r3; | ||
252 | register long ret asm("r0"); | ||
253 | |||
254 | __asm__ __volatile__ ( | ||
255 | "msr cpsr_fs, %[cpsr] \n\t" | ||
256 | "mov lr, pc \n\t" | ||
257 | "mov pc, %[fn] \n\t" | ||
258 | : "=r" (ret) | ||
259 | : "0" (rr0), "r" (rr1), "r" (rr2), "r" (rr3), | ||
260 | [cpsr] "r" (cpsr), [fn] "r" (fn) | ||
261 | : "lr", "cc" | ||
262 | ); | ||
263 | return ret; | ||
264 | } | ||
265 | |||
266 | static inline long __kprobes | ||
267 | insnslot_1arg_rwflags(long r0, long *cpsr, insn_1arg_fn_t *fn) | ||
268 | { | ||
269 | register long rr0 asm("r0") = r0; | ||
270 | register long ret asm("r0"); | ||
271 | long oldcpsr = *cpsr; | ||
272 | long newcpsr; | ||
273 | |||
274 | __asm__ __volatile__ ( | ||
275 | "msr cpsr_fs, %[oldcpsr] \n\t" | ||
276 | "mov lr, pc \n\t" | ||
277 | "mov pc, %[fn] \n\t" | ||
278 | "mrs %[newcpsr], cpsr \n\t" | ||
279 | : "=r" (ret), [newcpsr] "=r" (newcpsr) | ||
280 | : "0" (rr0), [oldcpsr] "r" (oldcpsr), [fn] "r" (fn) | ||
281 | : "lr", "cc" | ||
282 | ); | ||
283 | *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs); | ||
284 | return ret; | ||
285 | } | ||
286 | |||
287 | static inline long __kprobes | ||
288 | insnslot_2arg_rwflags(long r0, long r1, long *cpsr, insn_2arg_fn_t *fn) | ||
289 | { | ||
290 | register long rr0 asm("r0") = r0; | ||
291 | register long rr1 asm("r1") = r1; | ||
292 | register long ret asm("r0"); | ||
293 | long oldcpsr = *cpsr; | ||
294 | long newcpsr; | ||
295 | |||
296 | __asm__ __volatile__ ( | ||
297 | "msr cpsr_fs, %[oldcpsr] \n\t" | ||
298 | "mov lr, pc \n\t" | ||
299 | "mov pc, %[fn] \n\t" | ||
300 | "mrs %[newcpsr], cpsr \n\t" | ||
301 | : "=r" (ret), [newcpsr] "=r" (newcpsr) | ||
302 | : "0" (rr0), "r" (rr1), [oldcpsr] "r" (oldcpsr), [fn] "r" (fn) | ||
303 | : "lr", "cc" | ||
304 | ); | ||
305 | *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs); | ||
306 | return ret; | ||
307 | } | ||
308 | |||
309 | static inline long __kprobes | ||
310 | insnslot_3arg_rwflags(long r0, long r1, long r2, long *cpsr, | ||
311 | insn_3arg_fn_t *fn) | ||
312 | { | ||
313 | register long rr0 asm("r0") = r0; | ||
314 | register long rr1 asm("r1") = r1; | ||
315 | register long rr2 asm("r2") = r2; | ||
316 | register long ret asm("r0"); | ||
317 | long oldcpsr = *cpsr; | ||
318 | long newcpsr; | ||
319 | |||
320 | __asm__ __volatile__ ( | ||
321 | "msr cpsr_fs, %[oldcpsr] \n\t" | ||
322 | "mov lr, pc \n\t" | ||
323 | "mov pc, %[fn] \n\t" | ||
324 | "mrs %[newcpsr], cpsr \n\t" | ||
325 | : "=r" (ret), [newcpsr] "=r" (newcpsr) | ||
326 | : "0" (rr0), "r" (rr1), "r" (rr2), | ||
327 | [oldcpsr] "r" (oldcpsr), [fn] "r" (fn) | ||
328 | : "lr", "cc" | ||
329 | ); | ||
330 | *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs); | ||
331 | return ret; | ||
332 | } | ||
333 | |||
334 | static inline long __kprobes | ||
335 | insnslot_4arg_rwflags(long r0, long r1, long r2, long r3, long *cpsr, | ||
336 | insn_4arg_fn_t *fn) | ||
337 | { | ||
338 | register long rr0 asm("r0") = r0; | ||
339 | register long rr1 asm("r1") = r1; | ||
340 | register long rr2 asm("r2") = r2; | ||
341 | register long rr3 asm("r3") = r3; | ||
342 | register long ret asm("r0"); | ||
343 | long oldcpsr = *cpsr; | ||
344 | long newcpsr; | ||
345 | |||
346 | __asm__ __volatile__ ( | ||
347 | "msr cpsr_fs, %[oldcpsr] \n\t" | ||
348 | "mov lr, pc \n\t" | ||
349 | "mov pc, %[fn] \n\t" | ||
350 | "mrs %[newcpsr], cpsr \n\t" | ||
351 | : "=r" (ret), [newcpsr] "=r" (newcpsr) | ||
352 | : "0" (rr0), "r" (rr1), "r" (rr2), "r" (rr3), | ||
353 | [oldcpsr] "r" (oldcpsr), [fn] "r" (fn) | ||
354 | : "lr", "cc" | ||
355 | ); | ||
356 | *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs); | ||
357 | return ret; | ||
358 | } | ||
359 | |||
360 | static inline long long __kprobes | ||
361 | insnslot_llret_4arg_rwflags(long r0, long r1, long r2, long r3, long *cpsr, | ||
362 | insn_llret_4arg_fn_t *fn) | ||
363 | { | ||
364 | register long rr0 asm("r0") = r0; | ||
365 | register long rr1 asm("r1") = r1; | ||
366 | register long rr2 asm("r2") = r2; | ||
367 | register long rr3 asm("r3") = r3; | ||
368 | register long ret0 asm("r0"); | ||
369 | register long ret1 asm("r1"); | ||
370 | long oldcpsr = *cpsr; | ||
371 | long newcpsr; | ||
372 | union reg_pair fnr; | ||
373 | |||
374 | __asm__ __volatile__ ( | ||
375 | "msr cpsr_fs, %[oldcpsr] \n\t" | ||
376 | "mov lr, pc \n\t" | ||
377 | "mov pc, %[fn] \n\t" | ||
378 | "mrs %[newcpsr], cpsr \n\t" | ||
379 | : "=r" (ret0), "=r" (ret1), [newcpsr] "=r" (newcpsr) | ||
380 | : "0" (rr0), "r" (rr1), "r" (rr2), "r" (rr3), | ||
381 | [oldcpsr] "r" (oldcpsr), [fn] "r" (fn) | ||
382 | : "lr", "cc" | ||
383 | ); | ||
384 | *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs); | ||
385 | fnr.r0 = ret0; | ||
386 | fnr.r1 = ret1; | ||
387 | return fnr.dr; | ||
388 | } | ||
389 | |||
390 | /* | ||
391 | * To avoid the complications of mimicing single-stepping on a | ||
392 | * processor without a Next-PC or a single-step mode, and to | ||
393 | * avoid having to deal with the side-effects of boosting, we | ||
394 | * simulate or emulate (almost) all ARM instructions. | ||
395 | * | ||
396 | * "Simulation" is where the instruction's behavior is duplicated in | ||
397 | * C code. "Emulation" is where the original instruction is rewritten | ||
398 | * and executed, often by altering its registers. | ||
399 | * | ||
400 | * By having all behavior of the kprobe'd instruction completed before | ||
401 | * returning from the kprobe_handler(), all locks (scheduler and | ||
402 | * interrupt) can safely be released. There is no need for secondary | ||
403 | * breakpoints, no race with MP or preemptable kernels, nor having to | ||
404 | * clean up resources counts at a later time impacting overall system | ||
405 | * performance. By rewriting the instruction, only the minimum registers | ||
406 | * need to be loaded and saved back optimizing performance. | ||
407 | * | ||
408 | * Calling the insnslot_*_rwflags version of a function doesn't hurt | ||
409 | * anything even when the CPSR flags aren't updated by the | ||
410 | * instruction. It's just a little slower in return for saving | ||
411 | * a little space by not having a duplicate function that doesn't | ||
412 | * update the flags. (The same optimization can be said for | ||
413 | * instructions that do or don't perform register writeback) | ||
414 | * Also, instructions can either read the flags, only write the | ||
415 | * flags, or read and write the flags. To save combinations | ||
416 | * rather than for sheer performance, flag functions just assume | ||
417 | * read and write of flags. | ||
418 | */ | ||
419 | |||
420 | static void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs) | ||
421 | { | ||
422 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
423 | kprobe_opcode_t insn = p->opcode; | ||
424 | long iaddr = (long)p->addr; | ||
425 | int disp = branch_displacement(insn); | ||
426 | |||
427 | if (!insnslot_1arg_rflags(0, regs->ARM_cpsr, i_fn)) | ||
428 | return; | ||
429 | |||
430 | if (insn & (1 << 24)) | ||
431 | regs->ARM_lr = iaddr + 4; | ||
432 | |||
433 | regs->ARM_pc = iaddr + 8 + disp; | ||
434 | } | ||
435 | |||
436 | static void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs) | ||
437 | { | ||
438 | kprobe_opcode_t insn = p->opcode; | ||
439 | long iaddr = (long)p->addr; | ||
440 | int disp = branch_displacement(insn); | ||
441 | |||
442 | regs->ARM_lr = iaddr + 4; | ||
443 | regs->ARM_pc = iaddr + 8 + disp + ((insn >> 23) & 0x2); | ||
444 | regs->ARM_cpsr |= PSR_T_BIT; | ||
445 | } | ||
446 | |||
447 | static void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs) | ||
448 | { | ||
449 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
450 | kprobe_opcode_t insn = p->opcode; | ||
451 | int rm = insn & 0xf; | ||
452 | long rmv = regs->uregs[rm]; | ||
453 | |||
454 | if (!insnslot_1arg_rflags(0, regs->ARM_cpsr, i_fn)) | ||
455 | return; | ||
456 | |||
457 | if (insn & (1 << 5)) | ||
458 | regs->ARM_lr = (long)p->addr + 4; | ||
459 | |||
460 | regs->ARM_pc = rmv & ~0x1; | ||
461 | regs->ARM_cpsr &= ~PSR_T_BIT; | ||
462 | if (rmv & 0x1) | ||
463 | regs->ARM_cpsr |= PSR_T_BIT; | ||
464 | } | ||
465 | |||
466 | static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs) | ||
467 | { | ||
468 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
469 | kprobe_opcode_t insn = p->opcode; | ||
470 | int rn = (insn >> 16) & 0xf; | ||
471 | int lbit = insn & (1 << 20); | ||
472 | int wbit = insn & (1 << 21); | ||
473 | int ubit = insn & (1 << 23); | ||
474 | int pbit = insn & (1 << 24); | ||
475 | long *addr = (long *)regs->uregs[rn]; | ||
476 | int reg_bit_vector; | ||
477 | int reg_count; | ||
478 | |||
479 | if (!insnslot_1arg_rflags(0, regs->ARM_cpsr, i_fn)) | ||
480 | return; | ||
481 | |||
482 | reg_count = 0; | ||
483 | reg_bit_vector = insn & 0xffff; | ||
484 | while (reg_bit_vector) { | ||
485 | reg_bit_vector &= (reg_bit_vector - 1); | ||
486 | ++reg_count; | ||
487 | } | ||
488 | |||
489 | if (!ubit) | ||
490 | addr -= reg_count; | ||
491 | addr += (!pbit ^ !ubit); | ||
492 | |||
493 | reg_bit_vector = insn & 0xffff; | ||
494 | while (reg_bit_vector) { | ||
495 | int reg = __ffs(reg_bit_vector); | ||
496 | reg_bit_vector &= (reg_bit_vector - 1); | ||
497 | if (lbit) | ||
498 | regs->uregs[reg] = *addr++; | ||
499 | else | ||
500 | *addr++ = regs->uregs[reg]; | ||
501 | } | ||
502 | |||
503 | if (wbit) { | ||
504 | if (!ubit) | ||
505 | addr -= reg_count; | ||
506 | addr -= (!pbit ^ !ubit); | ||
507 | regs->uregs[rn] = (long)addr; | ||
508 | } | ||
509 | } | ||
510 | |||
511 | static void __kprobes simulate_stm1_pc(struct kprobe *p, struct pt_regs *regs) | ||
512 | { | ||
513 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
514 | |||
515 | if (!insnslot_1arg_rflags(0, regs->ARM_cpsr, i_fn)) | ||
516 | return; | ||
517 | |||
518 | regs->ARM_pc = (long)p->addr + str_pc_offset; | ||
519 | simulate_ldm1stm1(p, regs); | ||
520 | regs->ARM_pc = (long)p->addr + 4; | ||
521 | } | ||
522 | |||
523 | static void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs) | ||
524 | { | ||
525 | regs->uregs[12] = regs->uregs[13]; | ||
526 | } | ||
527 | |||
528 | static void __kprobes emulate_ldcstc(struct kprobe *p, struct pt_regs *regs) | ||
529 | { | ||
530 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
531 | kprobe_opcode_t insn = p->opcode; | ||
532 | int rn = (insn >> 16) & 0xf; | ||
533 | long rnv = regs->uregs[rn]; | ||
534 | |||
535 | /* Save Rn in case of writeback. */ | ||
536 | regs->uregs[rn] = insnslot_1arg_rflags(rnv, regs->ARM_cpsr, i_fn); | ||
537 | } | ||
538 | |||
539 | static void __kprobes emulate_ldrd(struct kprobe *p, struct pt_regs *regs) | ||
540 | { | ||
541 | insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; | ||
542 | kprobe_opcode_t insn = p->opcode; | ||
543 | int rd = (insn >> 12) & 0xf; | ||
544 | int rn = (insn >> 16) & 0xf; | ||
545 | int rm = insn & 0xf; /* rm may be invalid, don't care. */ | ||
546 | |||
547 | /* Not following the C calling convention here, so need asm(). */ | ||
548 | __asm__ __volatile__ ( | ||
549 | "ldr r0, %[rn] \n\t" | ||
550 | "ldr r1, %[rm] \n\t" | ||
551 | "msr cpsr_fs, %[cpsr]\n\t" | ||
552 | "mov lr, pc \n\t" | ||
553 | "mov pc, %[i_fn] \n\t" | ||
554 | "str r0, %[rn] \n\t" /* in case of writeback */ | ||
555 | "str r2, %[rd0] \n\t" | ||
556 | "str r3, %[rd1] \n\t" | ||
557 | : [rn] "+m" (regs->uregs[rn]), | ||
558 | [rd0] "=m" (regs->uregs[rd]), | ||
559 | [rd1] "=m" (regs->uregs[rd+1]) | ||
560 | : [rm] "m" (regs->uregs[rm]), | ||
561 | [cpsr] "r" (regs->ARM_cpsr), | ||
562 | [i_fn] "r" (i_fn) | ||
563 | : "r0", "r1", "r2", "r3", "lr", "cc" | ||
564 | ); | ||
565 | } | ||
566 | |||
567 | static void __kprobes emulate_strd(struct kprobe *p, struct pt_regs *regs) | ||
568 | { | ||
569 | insn_4arg_fn_t *i_fn = (insn_4arg_fn_t *)&p->ainsn.insn[0]; | ||
570 | kprobe_opcode_t insn = p->opcode; | ||
571 | int rd = (insn >> 12) & 0xf; | ||
572 | int rn = (insn >> 16) & 0xf; | ||
573 | int rm = insn & 0xf; | ||
574 | long rnv = regs->uregs[rn]; | ||
575 | long rmv = regs->uregs[rm]; /* rm/rmv may be invalid, don't care. */ | ||
576 | |||
577 | regs->uregs[rn] = insnslot_4arg_rflags(rnv, rmv, regs->uregs[rd], | ||
578 | regs->uregs[rd+1], | ||
579 | regs->ARM_cpsr, i_fn); | ||
580 | } | ||
581 | |||
582 | static void __kprobes emulate_ldr(struct kprobe *p, struct pt_regs *regs) | ||
583 | { | ||
584 | insn_llret_3arg_fn_t *i_fn = (insn_llret_3arg_fn_t *)&p->ainsn.insn[0]; | ||
585 | kprobe_opcode_t insn = p->opcode; | ||
586 | union reg_pair fnr; | ||
587 | int rd = (insn >> 12) & 0xf; | ||
588 | int rn = (insn >> 16) & 0xf; | ||
589 | int rm = insn & 0xf; | ||
590 | long rdv; | ||
591 | long rnv = regs->uregs[rn]; | ||
592 | long rmv = regs->uregs[rm]; /* rm/rmv may be invalid, don't care. */ | ||
593 | long cpsr = regs->ARM_cpsr; | ||
594 | |||
595 | fnr.dr = insnslot_llret_3arg_rflags(rnv, 0, rmv, cpsr, i_fn); | ||
596 | regs->uregs[rn] = fnr.r0; /* Save Rn in case of writeback. */ | ||
597 | rdv = fnr.r1; | ||
598 | |||
599 | if (rd == 15) { | ||
600 | #if __LINUX_ARM_ARCH__ >= 5 | ||
601 | cpsr &= ~PSR_T_BIT; | ||
602 | if (rdv & 0x1) | ||
603 | cpsr |= PSR_T_BIT; | ||
604 | regs->ARM_cpsr = cpsr; | ||
605 | rdv &= ~0x1; | ||
606 | #else | ||
607 | rdv &= ~0x2; | ||
608 | #endif | ||
609 | } | ||
610 | regs->uregs[rd] = rdv; | ||
611 | } | ||
612 | |||
613 | static void __kprobes emulate_str(struct kprobe *p, struct pt_regs *regs) | ||
614 | { | ||
615 | insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; | ||
616 | kprobe_opcode_t insn = p->opcode; | ||
617 | long iaddr = (long)p->addr; | ||
618 | int rd = (insn >> 12) & 0xf; | ||
619 | int rn = (insn >> 16) & 0xf; | ||
620 | int rm = insn & 0xf; | ||
621 | long rdv = (rd == 15) ? iaddr + str_pc_offset : regs->uregs[rd]; | ||
622 | long rnv = (rn == 15) ? iaddr + 8 : regs->uregs[rn]; | ||
623 | long rmv = regs->uregs[rm]; /* rm/rmv may be invalid, don't care. */ | ||
624 | |||
625 | /* Save Rn in case of writeback. */ | ||
626 | regs->uregs[rn] = | ||
627 | insnslot_3arg_rflags(rnv, rdv, rmv, regs->ARM_cpsr, i_fn); | ||
628 | } | ||
629 | |||
630 | static void __kprobes emulate_mrrc(struct kprobe *p, struct pt_regs *regs) | ||
631 | { | ||
632 | insn_llret_0arg_fn_t *i_fn = (insn_llret_0arg_fn_t *)&p->ainsn.insn[0]; | ||
633 | kprobe_opcode_t insn = p->opcode; | ||
634 | union reg_pair fnr; | ||
635 | int rd = (insn >> 12) & 0xf; | ||
636 | int rn = (insn >> 16) & 0xf; | ||
637 | |||
638 | fnr.dr = insnslot_llret_0arg_rflags(regs->ARM_cpsr, i_fn); | ||
639 | regs->uregs[rn] = fnr.r0; | ||
640 | regs->uregs[rd] = fnr.r1; | ||
641 | } | ||
642 | |||
643 | static void __kprobes emulate_mcrr(struct kprobe *p, struct pt_regs *regs) | ||
644 | { | ||
645 | insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; | ||
646 | kprobe_opcode_t insn = p->opcode; | ||
647 | int rd = (insn >> 12) & 0xf; | ||
648 | int rn = (insn >> 16) & 0xf; | ||
649 | long rnv = regs->uregs[rn]; | ||
650 | long rdv = regs->uregs[rd]; | ||
651 | |||
652 | insnslot_2arg_rflags(rnv, rdv, regs->ARM_cpsr, i_fn); | ||
653 | } | ||
654 | |||
655 | static void __kprobes emulate_sat(struct kprobe *p, struct pt_regs *regs) | ||
656 | { | ||
657 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
658 | kprobe_opcode_t insn = p->opcode; | ||
659 | int rd = (insn >> 12) & 0xf; | ||
660 | int rm = insn & 0xf; | ||
661 | long rmv = regs->uregs[rm]; | ||
662 | |||
663 | /* Writes Q flag */ | ||
664 | regs->uregs[rd] = insnslot_1arg_rwflags(rmv, ®s->ARM_cpsr, i_fn); | ||
665 | } | ||
666 | |||
667 | static void __kprobes emulate_sel(struct kprobe *p, struct pt_regs *regs) | ||
668 | { | ||
669 | insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; | ||
670 | kprobe_opcode_t insn = p->opcode; | ||
671 | int rd = (insn >> 12) & 0xf; | ||
672 | int rn = (insn >> 16) & 0xf; | ||
673 | int rm = insn & 0xf; | ||
674 | long rnv = regs->uregs[rn]; | ||
675 | long rmv = regs->uregs[rm]; | ||
676 | |||
677 | /* Reads GE bits */ | ||
678 | regs->uregs[rd] = insnslot_2arg_rflags(rnv, rmv, regs->ARM_cpsr, i_fn); | ||
679 | } | ||
680 | |||
681 | static void __kprobes emulate_none(struct kprobe *p, struct pt_regs *regs) | ||
682 | { | ||
683 | insn_0arg_fn_t *i_fn = (insn_0arg_fn_t *)&p->ainsn.insn[0]; | ||
684 | |||
685 | insnslot_0arg_rflags(regs->ARM_cpsr, i_fn); | ||
686 | } | ||
687 | |||
688 | static void __kprobes emulate_rd12(struct kprobe *p, struct pt_regs *regs) | ||
689 | { | ||
690 | insn_0arg_fn_t *i_fn = (insn_0arg_fn_t *)&p->ainsn.insn[0]; | ||
691 | kprobe_opcode_t insn = p->opcode; | ||
692 | int rd = (insn >> 12) & 0xf; | ||
693 | |||
694 | regs->uregs[rd] = insnslot_0arg_rflags(regs->ARM_cpsr, i_fn); | ||
695 | } | ||
696 | |||
697 | static void __kprobes emulate_ird12(struct kprobe *p, struct pt_regs *regs) | ||
698 | { | ||
699 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
700 | kprobe_opcode_t insn = p->opcode; | ||
701 | int ird = (insn >> 12) & 0xf; | ||
702 | |||
703 | insnslot_1arg_rflags(regs->uregs[ird], regs->ARM_cpsr, i_fn); | ||
704 | } | ||
705 | |||
706 | static void __kprobes emulate_rn16(struct kprobe *p, struct pt_regs *regs) | ||
707 | { | ||
708 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
709 | kprobe_opcode_t insn = p->opcode; | ||
710 | int rn = (insn >> 16) & 0xf; | ||
711 | long rnv = regs->uregs[rn]; | ||
712 | |||
713 | insnslot_1arg_rflags(rnv, regs->ARM_cpsr, i_fn); | ||
714 | } | ||
715 | |||
716 | static void __kprobes emulate_rd12rm0(struct kprobe *p, struct pt_regs *regs) | ||
717 | { | ||
718 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
719 | kprobe_opcode_t insn = p->opcode; | ||
720 | int rd = (insn >> 12) & 0xf; | ||
721 | int rm = insn & 0xf; | ||
722 | long rmv = regs->uregs[rm]; | ||
723 | |||
724 | regs->uregs[rd] = insnslot_1arg_rflags(rmv, regs->ARM_cpsr, i_fn); | ||
725 | } | ||
726 | |||
727 | static void __kprobes | ||
728 | emulate_rd12rn16rm0_rwflags(struct kprobe *p, struct pt_regs *regs) | ||
729 | { | ||
730 | insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; | ||
731 | kprobe_opcode_t insn = p->opcode; | ||
732 | int rd = (insn >> 12) & 0xf; | ||
733 | int rn = (insn >> 16) & 0xf; | ||
734 | int rm = insn & 0xf; | ||
735 | long rnv = regs->uregs[rn]; | ||
736 | long rmv = regs->uregs[rm]; | ||
737 | |||
738 | regs->uregs[rd] = | ||
739 | insnslot_2arg_rwflags(rnv, rmv, ®s->ARM_cpsr, i_fn); | ||
740 | } | ||
741 | |||
742 | static void __kprobes | ||
743 | emulate_rd16rn12rs8rm0_rwflags(struct kprobe *p, struct pt_regs *regs) | ||
744 | { | ||
745 | insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; | ||
746 | kprobe_opcode_t insn = p->opcode; | ||
747 | int rd = (insn >> 16) & 0xf; | ||
748 | int rn = (insn >> 12) & 0xf; | ||
749 | int rs = (insn >> 8) & 0xf; | ||
750 | int rm = insn & 0xf; | ||
751 | long rnv = regs->uregs[rn]; | ||
752 | long rsv = regs->uregs[rs]; | ||
753 | long rmv = regs->uregs[rm]; | ||
754 | |||
755 | regs->uregs[rd] = | ||
756 | insnslot_3arg_rwflags(rnv, rsv, rmv, ®s->ARM_cpsr, i_fn); | ||
757 | } | ||
758 | |||
759 | static void __kprobes | ||
760 | emulate_rd16rs8rm0_rwflags(struct kprobe *p, struct pt_regs *regs) | ||
761 | { | ||
762 | insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; | ||
763 | kprobe_opcode_t insn = p->opcode; | ||
764 | int rd = (insn >> 16) & 0xf; | ||
765 | int rs = (insn >> 8) & 0xf; | ||
766 | int rm = insn & 0xf; | ||
767 | long rsv = regs->uregs[rs]; | ||
768 | long rmv = regs->uregs[rm]; | ||
769 | |||
770 | regs->uregs[rd] = | ||
771 | insnslot_2arg_rwflags(rsv, rmv, ®s->ARM_cpsr, i_fn); | ||
772 | } | ||
773 | |||
774 | static void __kprobes | ||
775 | emulate_rdhi16rdlo12rs8rm0_rwflags(struct kprobe *p, struct pt_regs *regs) | ||
776 | { | ||
777 | insn_llret_4arg_fn_t *i_fn = (insn_llret_4arg_fn_t *)&p->ainsn.insn[0]; | ||
778 | kprobe_opcode_t insn = p->opcode; | ||
779 | union reg_pair fnr; | ||
780 | int rdhi = (insn >> 16) & 0xf; | ||
781 | int rdlo = (insn >> 12) & 0xf; | ||
782 | int rs = (insn >> 8) & 0xf; | ||
783 | int rm = insn & 0xf; | ||
784 | long rsv = regs->uregs[rs]; | ||
785 | long rmv = regs->uregs[rm]; | ||
786 | |||
787 | fnr.dr = insnslot_llret_4arg_rwflags(regs->uregs[rdhi], | ||
788 | regs->uregs[rdlo], rsv, rmv, | ||
789 | ®s->ARM_cpsr, i_fn); | ||
790 | regs->uregs[rdhi] = fnr.r0; | ||
791 | regs->uregs[rdlo] = fnr.r1; | ||
792 | } | ||
793 | |||
794 | static void __kprobes | ||
795 | emulate_alu_imm_rflags(struct kprobe *p, struct pt_regs *regs) | ||
796 | { | ||
797 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
798 | kprobe_opcode_t insn = p->opcode; | ||
799 | int rd = (insn >> 12) & 0xf; | ||
800 | int rn = (insn >> 16) & 0xf; | ||
801 | long rnv = (rn == 15) ? (long)p->addr + 8 : regs->uregs[rn]; | ||
802 | |||
803 | regs->uregs[rd] = insnslot_1arg_rflags(rnv, regs->ARM_cpsr, i_fn); | ||
804 | } | ||
805 | |||
806 | static void __kprobes | ||
807 | emulate_alu_imm_rwflags(struct kprobe *p, struct pt_regs *regs) | ||
808 | { | ||
809 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
810 | kprobe_opcode_t insn = p->opcode; | ||
811 | int rd = (insn >> 12) & 0xf; | ||
812 | int rn = (insn >> 16) & 0xf; | ||
813 | long rnv = (rn == 15) ? (long)p->addr + 8 : regs->uregs[rn]; | ||
814 | |||
815 | regs->uregs[rd] = insnslot_1arg_rwflags(rnv, ®s->ARM_cpsr, i_fn); | ||
816 | } | ||
817 | |||
818 | static void __kprobes | ||
819 | emulate_alu_rflags(struct kprobe *p, struct pt_regs *regs) | ||
820 | { | ||
821 | insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; | ||
822 | kprobe_opcode_t insn = p->opcode; | ||
823 | long ppc = (long)p->addr + 8; | ||
824 | int rd = (insn >> 12) & 0xf; | ||
825 | int rn = (insn >> 16) & 0xf; /* rn/rnv/rs/rsv may be */ | ||
826 | int rs = (insn >> 8) & 0xf; /* invalid, don't care. */ | ||
827 | int rm = insn & 0xf; | ||
828 | long rnv = (rn == 15) ? ppc : regs->uregs[rn]; | ||
829 | long rmv = (rm == 15) ? ppc : regs->uregs[rm]; | ||
830 | long rsv = regs->uregs[rs]; | ||
831 | |||
832 | regs->uregs[rd] = | ||
833 | insnslot_3arg_rflags(rnv, rmv, rsv, regs->ARM_cpsr, i_fn); | ||
834 | } | ||
835 | |||
836 | static void __kprobes | ||
837 | emulate_alu_rwflags(struct kprobe *p, struct pt_regs *regs) | ||
838 | { | ||
839 | insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; | ||
840 | kprobe_opcode_t insn = p->opcode; | ||
841 | long ppc = (long)p->addr + 8; | ||
842 | int rd = (insn >> 12) & 0xf; | ||
843 | int rn = (insn >> 16) & 0xf; /* rn/rnv/rs/rsv may be */ | ||
844 | int rs = (insn >> 8) & 0xf; /* invalid, don't care. */ | ||
845 | int rm = insn & 0xf; | ||
846 | long rnv = (rn == 15) ? ppc : regs->uregs[rn]; | ||
847 | long rmv = (rm == 15) ? ppc : regs->uregs[rm]; | ||
848 | long rsv = regs->uregs[rs]; | ||
849 | |||
850 | regs->uregs[rd] = | ||
851 | insnslot_3arg_rwflags(rnv, rmv, rsv, ®s->ARM_cpsr, i_fn); | ||
852 | } | ||
853 | |||
854 | static enum kprobe_insn __kprobes | ||
855 | prep_emulate_ldr_str(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
856 | { | ||
857 | int ibit = (insn & (1 << 26)) ? 25 : 22; | ||
858 | |||
859 | insn &= 0xfff00fff; | ||
860 | insn |= 0x00001000; /* Rn = r0, Rd = r1 */ | ||
861 | if (insn & (1 << ibit)) { | ||
862 | insn &= ~0xf; | ||
863 | insn |= 2; /* Rm = r2 */ | ||
864 | } | ||
865 | asi->insn[0] = insn; | ||
866 | asi->insn_handler = (insn & (1 << 20)) ? emulate_ldr : emulate_str; | ||
867 | return INSN_GOOD; | ||
868 | } | ||
869 | |||
870 | static enum kprobe_insn __kprobes | ||
871 | prep_emulate_rd12rm0(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
872 | { | ||
873 | insn &= 0xffff0ff0; /* Rd = r0, Rm = r0 */ | ||
874 | asi->insn[0] = insn; | ||
875 | asi->insn_handler = emulate_rd12rm0; | ||
876 | return INSN_GOOD; | ||
877 | } | ||
878 | |||
879 | static enum kprobe_insn __kprobes | ||
880 | prep_emulate_rd12(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
881 | { | ||
882 | insn &= 0xffff0fff; /* Rd = r0 */ | ||
883 | asi->insn[0] = insn; | ||
884 | asi->insn_handler = emulate_rd12; | ||
885 | return INSN_GOOD; | ||
886 | } | ||
887 | |||
888 | static enum kprobe_insn __kprobes | ||
889 | prep_emulate_rd12rn16rm0_wflags(kprobe_opcode_t insn, | ||
890 | struct arch_specific_insn *asi) | ||
891 | { | ||
892 | insn &= 0xfff00ff0; /* Rd = r0, Rn = r0 */ | ||
893 | insn |= 0x00000001; /* Rm = r1 */ | ||
894 | asi->insn[0] = insn; | ||
895 | asi->insn_handler = emulate_rd12rn16rm0_rwflags; | ||
896 | return INSN_GOOD; | ||
897 | } | ||
898 | |||
899 | static enum kprobe_insn __kprobes | ||
900 | prep_emulate_rd16rs8rm0_wflags(kprobe_opcode_t insn, | ||
901 | struct arch_specific_insn *asi) | ||
902 | { | ||
903 | insn &= 0xfff0f0f0; /* Rd = r0, Rs = r0 */ | ||
904 | insn |= 0x00000001; /* Rm = r1 */ | ||
905 | asi->insn[0] = insn; | ||
906 | asi->insn_handler = emulate_rd16rs8rm0_rwflags; | ||
907 | return INSN_GOOD; | ||
908 | } | ||
909 | |||
910 | static enum kprobe_insn __kprobes | ||
911 | prep_emulate_rd16rn12rs8rm0_wflags(kprobe_opcode_t insn, | ||
912 | struct arch_specific_insn *asi) | ||
913 | { | ||
914 | insn &= 0xfff000f0; /* Rd = r0, Rn = r0 */ | ||
915 | insn |= 0x00000102; /* Rs = r1, Rm = r2 */ | ||
916 | asi->insn[0] = insn; | ||
917 | asi->insn_handler = emulate_rd16rn12rs8rm0_rwflags; | ||
918 | return INSN_GOOD; | ||
919 | } | ||
920 | |||
921 | static enum kprobe_insn __kprobes | ||
922 | prep_emulate_rdhi16rdlo12rs8rm0_wflags(kprobe_opcode_t insn, | ||
923 | struct arch_specific_insn *asi) | ||
924 | { | ||
925 | insn &= 0xfff000f0; /* RdHi = r0, RdLo = r1 */ | ||
926 | insn |= 0x00001203; /* Rs = r2, Rm = r3 */ | ||
927 | asi->insn[0] = insn; | ||
928 | asi->insn_handler = emulate_rdhi16rdlo12rs8rm0_rwflags; | ||
929 | return INSN_GOOD; | ||
930 | } | ||
931 | |||
932 | /* | ||
933 | * For the instruction masking and comparisons in all the "space_*" | ||
934 | * functions below, Do _not_ rearrange the order of tests unless | ||
935 | * you're very, very sure of what you are doing. For the sake of | ||
936 | * efficiency, the masks for some tests sometimes assume other test | ||
937 | * have been done prior to them so the number of patterns to test | ||
938 | * for an instruction set can be as broad as possible to reduce the | ||
939 | * number of tests needed. | ||
940 | */ | ||
941 | |||
942 | static enum kprobe_insn __kprobes | ||
943 | space_1111(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
944 | { | ||
945 | /* CPS mmod == 1 : 1111 0001 0000 xx10 xxxx xxxx xx0x xxxx */ | ||
946 | /* RFE : 1111 100x x0x1 xxxx xxxx 1010 xxxx xxxx */ | ||
947 | /* SRS : 1111 100x x1x0 1101 xxxx 0101 xxxx xxxx */ | ||
948 | if ((insn & 0xfff30020) == 0xf1020000 || | ||
949 | (insn & 0xfe500f00) == 0xf8100a00 || | ||
950 | (insn & 0xfe5f0f00) == 0xf84d0500) | ||
951 | return INSN_REJECTED; | ||
952 | |||
953 | /* PLD : 1111 01x1 x101 xxxx xxxx xxxx xxxx xxxx : */ | ||
954 | if ((insn & 0xfd700000) == 0xf4500000) { | ||
955 | insn &= 0xfff0ffff; /* Rn = r0 */ | ||
956 | asi->insn[0] = insn; | ||
957 | asi->insn_handler = emulate_rn16; | ||
958 | return INSN_GOOD; | ||
959 | } | ||
960 | |||
961 | /* BLX(1) : 1111 101x xxxx xxxx xxxx xxxx xxxx xxxx : */ | ||
962 | if ((insn & 0xfe000000) == 0xfa000000) { | ||
963 | asi->insn_handler = simulate_blx1; | ||
964 | return INSN_GOOD_NO_SLOT; | ||
965 | } | ||
966 | |||
967 | /* SETEND : 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */ | ||
968 | /* CDP2 : 1111 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ | ||
969 | if ((insn & 0xffff00f0) == 0xf1010000 || | ||
970 | (insn & 0xff000010) == 0xfe000000) { | ||
971 | asi->insn[0] = insn; | ||
972 | asi->insn_handler = emulate_none; | ||
973 | return INSN_GOOD; | ||
974 | } | ||
975 | |||
976 | /* MCRR2 : 1111 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */ | ||
977 | /* MRRC2 : 1111 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */ | ||
978 | if ((insn & 0xffe00000) == 0xfc400000) { | ||
979 | insn &= 0xfff00fff; /* Rn = r0 */ | ||
980 | insn |= 0x00001000; /* Rd = r1 */ | ||
981 | asi->insn[0] = insn; | ||
982 | asi->insn_handler = | ||
983 | (insn & (1 << 20)) ? emulate_mrrc : emulate_mcrr; | ||
984 | return INSN_GOOD; | ||
985 | } | ||
986 | |||
987 | /* LDC2 : 1111 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ | ||
988 | /* STC2 : 1111 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ | ||
989 | if ((insn & 0xfe000000) == 0xfc000000) { | ||
990 | insn &= 0xfff0ffff; /* Rn = r0 */ | ||
991 | asi->insn[0] = insn; | ||
992 | asi->insn_handler = emulate_ldcstc; | ||
993 | return INSN_GOOD; | ||
994 | } | ||
995 | |||
996 | /* MCR2 : 1111 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ | ||
997 | /* MRC2 : 1111 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ | ||
998 | insn &= 0xffff0fff; /* Rd = r0 */ | ||
999 | asi->insn[0] = insn; | ||
1000 | asi->insn_handler = (insn & (1 << 20)) ? emulate_rd12 : emulate_ird12; | ||
1001 | return INSN_GOOD; | ||
1002 | } | ||
1003 | |||
1004 | static enum kprobe_insn __kprobes | ||
1005 | space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1006 | { | ||
1007 | /* cccc 0001 0xx0 xxxx xxxx xxxx xxxx xxx0 xxxx */ | ||
1008 | if ((insn & 0x0f900010) == 0x01000000) { | ||
1009 | |||
1010 | /* BXJ : cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */ | ||
1011 | /* MSR : cccc 0001 0x10 xxxx xxxx xxxx 0000 xxxx */ | ||
1012 | if ((insn & 0x0ff000f0) == 0x01200020 || | ||
1013 | (insn & 0x0fb000f0) == 0x01200000) | ||
1014 | return INSN_REJECTED; | ||
1015 | |||
1016 | /* MRS : cccc 0001 0x00 xxxx xxxx xxxx 0000 xxxx */ | ||
1017 | if ((insn & 0x0fb00010) == 0x01000000) | ||
1018 | return prep_emulate_rd12(insn, asi); | ||
1019 | |||
1020 | /* SMLALxy : cccc 0001 0100 xxxx xxxx xxxx 1xx0 xxxx */ | ||
1021 | if ((insn & 0x0ff00090) == 0x01400080) | ||
1022 | return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, asi); | ||
1023 | |||
1024 | /* SMULWy : cccc 0001 0010 xxxx xxxx xxxx 1x10 xxxx */ | ||
1025 | /* SMULxy : cccc 0001 0110 xxxx xxxx xxxx 1xx0 xxxx */ | ||
1026 | if ((insn & 0x0ff000b0) == 0x012000a0 || | ||
1027 | (insn & 0x0ff00090) == 0x01600080) | ||
1028 | return prep_emulate_rd16rs8rm0_wflags(insn, asi); | ||
1029 | |||
1030 | /* SMLAxy : cccc 0001 0000 xxxx xxxx xxxx 1xx0 xxxx : Q */ | ||
1031 | /* SMLAWy : cccc 0001 0010 xxxx xxxx xxxx 0x00 xxxx : Q */ | ||
1032 | return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); | ||
1033 | |||
1034 | } | ||
1035 | |||
1036 | /* cccc 0001 0xx0 xxxx xxxx xxxx xxxx 0xx1 xxxx */ | ||
1037 | else if ((insn & 0x0f900090) == 0x01000010) { | ||
1038 | |||
1039 | /* BKPT : 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */ | ||
1040 | if ((insn & 0xfff000f0) == 0xe1200070) | ||
1041 | return INSN_REJECTED; | ||
1042 | |||
1043 | /* BLX(2) : cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */ | ||
1044 | /* BX : cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */ | ||
1045 | if ((insn & 0x0ff000d0) == 0x01200010) { | ||
1046 | asi->insn[0] = truecc_insn(insn); | ||
1047 | asi->insn_handler = simulate_blx2bx; | ||
1048 | return INSN_GOOD; | ||
1049 | } | ||
1050 | |||
1051 | /* CLZ : cccc 0001 0110 xxxx xxxx xxxx 0001 xxxx */ | ||
1052 | if ((insn & 0x0ff000f0) == 0x01600010) | ||
1053 | return prep_emulate_rd12rm0(insn, asi); | ||
1054 | |||
1055 | /* QADD : cccc 0001 0000 xxxx xxxx xxxx 0101 xxxx :Q */ | ||
1056 | /* QSUB : cccc 0001 0010 xxxx xxxx xxxx 0101 xxxx :Q */ | ||
1057 | /* QDADD : cccc 0001 0100 xxxx xxxx xxxx 0101 xxxx :Q */ | ||
1058 | /* QDSUB : cccc 0001 0110 xxxx xxxx xxxx 0101 xxxx :Q */ | ||
1059 | return prep_emulate_rd12rn16rm0_wflags(insn, asi); | ||
1060 | } | ||
1061 | |||
1062 | /* cccc 0000 xxxx xxxx xxxx xxxx xxxx 1001 xxxx */ | ||
1063 | else if ((insn & 0x0f000090) == 0x00000090) { | ||
1064 | |||
1065 | /* MUL : cccc 0000 0000 xxxx xxxx xxxx 1001 xxxx : */ | ||
1066 | /* MULS : cccc 0000 0001 xxxx xxxx xxxx 1001 xxxx :cc */ | ||
1067 | /* MLA : cccc 0000 0010 xxxx xxxx xxxx 1001 xxxx : */ | ||
1068 | /* MLAS : cccc 0000 0011 xxxx xxxx xxxx 1001 xxxx :cc */ | ||
1069 | /* UMAAL : cccc 0000 0100 xxxx xxxx xxxx 1001 xxxx : */ | ||
1070 | /* UMULL : cccc 0000 1000 xxxx xxxx xxxx 1001 xxxx : */ | ||
1071 | /* UMULLS : cccc 0000 1001 xxxx xxxx xxxx 1001 xxxx :cc */ | ||
1072 | /* UMLAL : cccc 0000 1010 xxxx xxxx xxxx 1001 xxxx : */ | ||
1073 | /* UMLALS : cccc 0000 1011 xxxx xxxx xxxx 1001 xxxx :cc */ | ||
1074 | /* SMULL : cccc 0000 1100 xxxx xxxx xxxx 1001 xxxx : */ | ||
1075 | /* SMULLS : cccc 0000 1101 xxxx xxxx xxxx 1001 xxxx :cc */ | ||
1076 | /* SMLAL : cccc 0000 1110 xxxx xxxx xxxx 1001 xxxx : */ | ||
1077 | /* SMLALS : cccc 0000 1111 xxxx xxxx xxxx 1001 xxxx :cc */ | ||
1078 | if ((insn & 0x0fe000f0) == 0x00000090) { | ||
1079 | return prep_emulate_rd16rs8rm0_wflags(insn, asi); | ||
1080 | } else if ((insn & 0x0fe000f0) == 0x00200090) { | ||
1081 | return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); | ||
1082 | } else { | ||
1083 | return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, asi); | ||
1084 | } | ||
1085 | } | ||
1086 | |||
1087 | /* cccc 000x xxxx xxxx xxxx xxxx xxxx 1xx1 xxxx */ | ||
1088 | else if ((insn & 0x0e000090) == 0x00000090) { | ||
1089 | |||
1090 | /* SWP : cccc 0001 0000 xxxx xxxx xxxx 1001 xxxx */ | ||
1091 | /* SWPB : cccc 0001 0100 xxxx xxxx xxxx 1001 xxxx */ | ||
1092 | /* LDRD : cccc 000x xxx0 xxxx xxxx xxxx 1101 xxxx */ | ||
1093 | /* STRD : cccc 000x xxx0 xxxx xxxx xxxx 1111 xxxx */ | ||
1094 | /* STREX : cccc 0001 1000 xxxx xxxx xxxx 1001 xxxx */ | ||
1095 | /* LDREX : cccc 0001 1001 xxxx xxxx xxxx 1001 xxxx */ | ||
1096 | /* LDRH : cccc 000x xxx1 xxxx xxxx xxxx 1011 xxxx */ | ||
1097 | /* STRH : cccc 000x xxx0 xxxx xxxx xxxx 1011 xxxx */ | ||
1098 | /* LDRSB : cccc 000x xxx1 xxxx xxxx xxxx 1101 xxxx */ | ||
1099 | /* LDRSH : cccc 000x xxx1 xxxx xxxx xxxx 1111 xxxx */ | ||
1100 | if ((insn & 0x0fb000f0) == 0x01000090) { | ||
1101 | /* SWP/SWPB */ | ||
1102 | return prep_emulate_rd12rn16rm0_wflags(insn, asi); | ||
1103 | } else if ((insn & 0x0e1000d0) == 0x00000d0) { | ||
1104 | /* STRD/LDRD */ | ||
1105 | insn &= 0xfff00fff; | ||
1106 | insn |= 0x00002000; /* Rn = r0, Rd = r2 */ | ||
1107 | if (insn & (1 << 22)) { | ||
1108 | /* I bit */ | ||
1109 | insn &= ~0xf; | ||
1110 | insn |= 1; /* Rm = r1 */ | ||
1111 | } | ||
1112 | asi->insn[0] = insn; | ||
1113 | asi->insn_handler = | ||
1114 | (insn & (1 << 5)) ? emulate_strd : emulate_ldrd; | ||
1115 | return INSN_GOOD; | ||
1116 | } | ||
1117 | |||
1118 | return prep_emulate_ldr_str(insn, asi); | ||
1119 | } | ||
1120 | |||
1121 | /* cccc 000x xxxx xxxx xxxx xxxx xxxx xxxx xxxx */ | ||
1122 | |||
1123 | /* | ||
1124 | * ALU op with S bit and Rd == 15 : | ||
1125 | * cccc 000x xxx1 xxxx 1111 xxxx xxxx xxxx | ||
1126 | */ | ||
1127 | if ((insn & 0x0e10f000) == 0x0010f000) | ||
1128 | return INSN_REJECTED; | ||
1129 | |||
1130 | /* | ||
1131 | * "mov ip, sp" is the most common kprobe'd instruction by far. | ||
1132 | * Check and optimize for it explicitly. | ||
1133 | */ | ||
1134 | if (insn == 0xe1a0c00d) { | ||
1135 | asi->insn_handler = simulate_mov_ipsp; | ||
1136 | return INSN_GOOD_NO_SLOT; | ||
1137 | } | ||
1138 | |||
1139 | /* | ||
1140 | * Data processing: Immediate-shift / Register-shift | ||
1141 | * ALU op : cccc 000x xxxx xxxx xxxx xxxx xxxx xxxx | ||
1142 | * CPY : cccc 0001 1010 xxxx xxxx 0000 0000 xxxx | ||
1143 | * MOV : cccc 0001 101x xxxx xxxx xxxx xxxx xxxx | ||
1144 | * *S (bit 20) updates condition codes | ||
1145 | * ADC/SBC/RSC reads the C flag | ||
1146 | */ | ||
1147 | insn &= 0xfff00ff0; /* Rn = r0, Rd = r0 */ | ||
1148 | insn |= 0x00000001; /* Rm = r1 */ | ||
1149 | if (insn & 0x010) { | ||
1150 | insn &= 0xfffff0ff; /* register shift */ | ||
1151 | insn |= 0x00000200; /* Rs = r2 */ | ||
1152 | } | ||
1153 | asi->insn[0] = insn; | ||
1154 | asi->insn_handler = (insn & (1 << 20)) ? /* S-bit */ | ||
1155 | emulate_alu_rwflags : emulate_alu_rflags; | ||
1156 | return INSN_GOOD; | ||
1157 | } | ||
1158 | |||
1159 | static enum kprobe_insn __kprobes | ||
1160 | space_cccc_001x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1161 | { | ||
1162 | /* | ||
1163 | * MSR : cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx | ||
1164 | * Undef : cccc 0011 0x00 xxxx xxxx xxxx xxxx xxxx | ||
1165 | * ALU op with S bit and Rd == 15 : | ||
1166 | * cccc 001x xxx1 xxxx 1111 xxxx xxxx xxxx | ||
1167 | */ | ||
1168 | if ((insn & 0x0f900000) == 0x03200000 || /* MSR & Undef */ | ||
1169 | (insn & 0x0e10f000) == 0x0210f000) /* ALU s-bit, R15 */ | ||
1170 | return INSN_REJECTED; | ||
1171 | |||
1172 | /* | ||
1173 | * Data processing: 32-bit Immediate | ||
1174 | * ALU op : cccc 001x xxxx xxxx xxxx xxxx xxxx xxxx | ||
1175 | * MOV : cccc 0011 101x xxxx xxxx xxxx xxxx xxxx | ||
1176 | * *S (bit 20) updates condition codes | ||
1177 | * ADC/SBC/RSC reads the C flag | ||
1178 | */ | ||
1179 | insn &= 0xfff00ff0; /* Rn = r0, Rd = r0 */ | ||
1180 | asi->insn[0] = insn; | ||
1181 | asi->insn_handler = (insn & (1 << 20)) ? /* S-bit */ | ||
1182 | emulate_alu_imm_rwflags : emulate_alu_imm_rflags; | ||
1183 | return INSN_GOOD; | ||
1184 | } | ||
1185 | |||
1186 | static enum kprobe_insn __kprobes | ||
1187 | space_cccc_0110__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1188 | { | ||
1189 | /* SEL : cccc 0110 1000 xxxx xxxx xxxx 1011 xxxx GE: !!! */ | ||
1190 | if ((insn & 0x0ff000f0) == 0x068000b0) { | ||
1191 | insn &= 0xfff00ff0; /* Rd = r0, Rn = r0 */ | ||
1192 | insn |= 0x00000001; /* Rm = r1 */ | ||
1193 | asi->insn[0] = insn; | ||
1194 | asi->insn_handler = emulate_sel; | ||
1195 | return INSN_GOOD; | ||
1196 | } | ||
1197 | |||
1198 | /* SSAT : cccc 0110 101x xxxx xxxx xxxx xx01 xxxx :Q */ | ||
1199 | /* USAT : cccc 0110 111x xxxx xxxx xxxx xx01 xxxx :Q */ | ||
1200 | /* SSAT16 : cccc 0110 1010 xxxx xxxx xxxx 0011 xxxx :Q */ | ||
1201 | /* USAT16 : cccc 0110 1110 xxxx xxxx xxxx 0011 xxxx :Q */ | ||
1202 | if ((insn & 0x0fa00030) == 0x06a00010 || | ||
1203 | (insn & 0x0fb000f0) == 0x06a00030) { | ||
1204 | insn &= 0xffff0ff0; /* Rd = r0, Rm = r0 */ | ||
1205 | asi->insn[0] = insn; | ||
1206 | asi->insn_handler = emulate_sat; | ||
1207 | return INSN_GOOD; | ||
1208 | } | ||
1209 | |||
1210 | /* REV : cccc 0110 1011 xxxx xxxx xxxx 0011 xxxx */ | ||
1211 | /* REV16 : cccc 0110 1011 xxxx xxxx xxxx 1011 xxxx */ | ||
1212 | /* REVSH : cccc 0110 1111 xxxx xxxx xxxx 1011 xxxx */ | ||
1213 | if ((insn & 0x0ff00070) == 0x06b00030 || | ||
1214 | (insn & 0x0ff000f0) == 0x06f000b0) | ||
1215 | return prep_emulate_rd12rm0(insn, asi); | ||
1216 | |||
1217 | /* SADD16 : cccc 0110 0001 xxxx xxxx xxxx 0001 xxxx :GE */ | ||
1218 | /* SADDSUBX : cccc 0110 0001 xxxx xxxx xxxx 0011 xxxx :GE */ | ||
1219 | /* SSUBADDX : cccc 0110 0001 xxxx xxxx xxxx 0101 xxxx :GE */ | ||
1220 | /* SSUB16 : cccc 0110 0001 xxxx xxxx xxxx 0111 xxxx :GE */ | ||
1221 | /* SADD8 : cccc 0110 0001 xxxx xxxx xxxx 1001 xxxx :GE */ | ||
1222 | /* SSUB8 : cccc 0110 0001 xxxx xxxx xxxx 1111 xxxx :GE */ | ||
1223 | /* QADD16 : cccc 0110 0010 xxxx xxxx xxxx 0001 xxxx : */ | ||
1224 | /* QADDSUBX : cccc 0110 0010 xxxx xxxx xxxx 0011 xxxx : */ | ||
1225 | /* QSUBADDX : cccc 0110 0010 xxxx xxxx xxxx 0101 xxxx : */ | ||
1226 | /* QSUB16 : cccc 0110 0010 xxxx xxxx xxxx 0111 xxxx : */ | ||
1227 | /* QADD8 : cccc 0110 0010 xxxx xxxx xxxx 1001 xxxx : */ | ||
1228 | /* QSUB8 : cccc 0110 0010 xxxx xxxx xxxx 1111 xxxx : */ | ||
1229 | /* SHADD16 : cccc 0110 0011 xxxx xxxx xxxx 0001 xxxx : */ | ||
1230 | /* SHADDSUBX : cccc 0110 0011 xxxx xxxx xxxx 0011 xxxx : */ | ||
1231 | /* SHSUBADDX : cccc 0110 0011 xxxx xxxx xxxx 0101 xxxx : */ | ||
1232 | /* SHSUB16 : cccc 0110 0011 xxxx xxxx xxxx 0111 xxxx : */ | ||
1233 | /* SHADD8 : cccc 0110 0011 xxxx xxxx xxxx 1001 xxxx : */ | ||
1234 | /* SHSUB8 : cccc 0110 0011 xxxx xxxx xxxx 1111 xxxx : */ | ||
1235 | /* UADD16 : cccc 0110 0101 xxxx xxxx xxxx 0001 xxxx :GE */ | ||
1236 | /* UADDSUBX : cccc 0110 0101 xxxx xxxx xxxx 0011 xxxx :GE */ | ||
1237 | /* USUBADDX : cccc 0110 0101 xxxx xxxx xxxx 0101 xxxx :GE */ | ||
1238 | /* USUB16 : cccc 0110 0101 xxxx xxxx xxxx 0111 xxxx :GE */ | ||
1239 | /* UADD8 : cccc 0110 0101 xxxx xxxx xxxx 1001 xxxx :GE */ | ||
1240 | /* USUB8 : cccc 0110 0101 xxxx xxxx xxxx 1111 xxxx :GE */ | ||
1241 | /* UQADD16 : cccc 0110 0110 xxxx xxxx xxxx 0001 xxxx : */ | ||
1242 | /* UQADDSUBX : cccc 0110 0110 xxxx xxxx xxxx 0011 xxxx : */ | ||
1243 | /* UQSUBADDX : cccc 0110 0110 xxxx xxxx xxxx 0101 xxxx : */ | ||
1244 | /* UQSUB16 : cccc 0110 0110 xxxx xxxx xxxx 0111 xxxx : */ | ||
1245 | /* UQADD8 : cccc 0110 0110 xxxx xxxx xxxx 1001 xxxx : */ | ||
1246 | /* UQSUB8 : cccc 0110 0110 xxxx xxxx xxxx 1111 xxxx : */ | ||
1247 | /* UHADD16 : cccc 0110 0111 xxxx xxxx xxxx 0001 xxxx : */ | ||
1248 | /* UHADDSUBX : cccc 0110 0111 xxxx xxxx xxxx 0011 xxxx : */ | ||
1249 | /* UHSUBADDX : cccc 0110 0111 xxxx xxxx xxxx 0101 xxxx : */ | ||
1250 | /* UHSUB16 : cccc 0110 0111 xxxx xxxx xxxx 0111 xxxx : */ | ||
1251 | /* UHADD8 : cccc 0110 0111 xxxx xxxx xxxx 1001 xxxx : */ | ||
1252 | /* UHSUB8 : cccc 0110 0111 xxxx xxxx xxxx 1111 xxxx : */ | ||
1253 | /* PKHBT : cccc 0110 1000 xxxx xxxx xxxx x001 xxxx : */ | ||
1254 | /* PKHTB : cccc 0110 1000 xxxx xxxx xxxx x101 xxxx : */ | ||
1255 | /* SXTAB16 : cccc 0110 1000 xxxx xxxx xxxx 0111 xxxx : */ | ||
1256 | /* SXTB : cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx : */ | ||
1257 | /* SXTAB : cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx : */ | ||
1258 | /* SXTAH : cccc 0110 1011 xxxx xxxx xxxx 0111 xxxx : */ | ||
1259 | /* UXTAB16 : cccc 0110 1100 xxxx xxxx xxxx 0111 xxxx : */ | ||
1260 | /* UXTAB : cccc 0110 1110 xxxx xxxx xxxx 0111 xxxx : */ | ||
1261 | /* UXTAH : cccc 0110 1111 xxxx xxxx xxxx 0111 xxxx : */ | ||
1262 | return prep_emulate_rd12rn16rm0_wflags(insn, asi); | ||
1263 | } | ||
1264 | |||
1265 | static enum kprobe_insn __kprobes | ||
1266 | space_cccc_0111__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1267 | { | ||
1268 | /* Undef : cccc 0111 1111 xxxx xxxx xxxx 1111 xxxx */ | ||
1269 | if ((insn & 0x0ff000f0) == 0x03f000f0) | ||
1270 | return INSN_REJECTED; | ||
1271 | |||
1272 | /* USADA8 : cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx */ | ||
1273 | /* USAD8 : cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx */ | ||
1274 | if ((insn & 0x0ff000f0) == 0x07800010) | ||
1275 | return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); | ||
1276 | |||
1277 | /* SMLALD : cccc 0111 0100 xxxx xxxx xxxx 00x1 xxxx */ | ||
1278 | /* SMLSLD : cccc 0111 0100 xxxx xxxx xxxx 01x1 xxxx */ | ||
1279 | if ((insn & 0x0ff00090) == 0x07400010) | ||
1280 | return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, asi); | ||
1281 | |||
1282 | /* SMLAD : cccc 0111 0000 xxxx xxxx xxxx 00x1 xxxx :Q */ | ||
1283 | /* SMLSD : cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx :Q */ | ||
1284 | /* SMMLA : cccc 0111 0101 xxxx xxxx xxxx 00x1 xxxx : */ | ||
1285 | /* SMMLS : cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx : */ | ||
1286 | if ((insn & 0x0ff00090) == 0x07000010 || | ||
1287 | (insn & 0x0ff000d0) == 0x07500010 || | ||
1288 | (insn & 0x0ff000d0) == 0x075000d0) | ||
1289 | return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); | ||
1290 | |||
1291 | /* SMUSD : cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx : */ | ||
1292 | /* SMUAD : cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx :Q */ | ||
1293 | /* SMMUL : cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx : */ | ||
1294 | return prep_emulate_rd16rs8rm0_wflags(insn, asi); | ||
1295 | } | ||
1296 | |||
1297 | static enum kprobe_insn __kprobes | ||
1298 | space_cccc_01xx(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1299 | { | ||
1300 | /* LDR : cccc 01xx x0x1 xxxx xxxx xxxx xxxx xxxx */ | ||
1301 | /* LDRB : cccc 01xx x1x1 xxxx xxxx xxxx xxxx xxxx */ | ||
1302 | /* LDRBT : cccc 01x0 x111 xxxx xxxx xxxx xxxx xxxx */ | ||
1303 | /* LDRT : cccc 01x0 x011 xxxx xxxx xxxx xxxx xxxx */ | ||
1304 | /* STR : cccc 01xx x0x0 xxxx xxxx xxxx xxxx xxxx */ | ||
1305 | /* STRB : cccc 01xx x1x0 xxxx xxxx xxxx xxxx xxxx */ | ||
1306 | /* STRBT : cccc 01x0 x110 xxxx xxxx xxxx xxxx xxxx */ | ||
1307 | /* STRT : cccc 01x0 x010 xxxx xxxx xxxx xxxx xxxx */ | ||
1308 | return prep_emulate_ldr_str(insn, asi); | ||
1309 | } | ||
1310 | |||
1311 | static enum kprobe_insn __kprobes | ||
1312 | space_cccc_100x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1313 | { | ||
1314 | /* LDM(2) : cccc 100x x101 xxxx 0xxx xxxx xxxx xxxx */ | ||
1315 | /* LDM(3) : cccc 100x x1x1 xxxx 1xxx xxxx xxxx xxxx */ | ||
1316 | if ((insn & 0x0e708000) == 0x85000000 || | ||
1317 | (insn & 0x0e508000) == 0x85010000) | ||
1318 | return INSN_REJECTED; | ||
1319 | |||
1320 | /* LDM(1) : cccc 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ | ||
1321 | /* STM(1) : cccc 100x x0x0 xxxx xxxx xxxx xxxx xxxx */ | ||
1322 | asi->insn[0] = truecc_insn(insn); | ||
1323 | asi->insn_handler = ((insn & 0x108000) == 0x008000) ? /* STM & R15 */ | ||
1324 | simulate_stm1_pc : simulate_ldm1stm1; | ||
1325 | return INSN_GOOD; | ||
1326 | } | ||
1327 | |||
1328 | static enum kprobe_insn __kprobes | ||
1329 | space_cccc_101x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1330 | { | ||
1331 | /* B : cccc 1010 xxxx xxxx xxxx xxxx xxxx xxxx */ | ||
1332 | /* BL : cccc 1011 xxxx xxxx xxxx xxxx xxxx xxxx */ | ||
1333 | asi->insn[0] = truecc_insn(insn); | ||
1334 | asi->insn_handler = simulate_bbl; | ||
1335 | return INSN_GOOD; | ||
1336 | } | ||
1337 | |||
1338 | static enum kprobe_insn __kprobes | ||
1339 | space_cccc_1100_010x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1340 | { | ||
1341 | /* MCRR : cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */ | ||
1342 | /* MRRC : cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */ | ||
1343 | insn &= 0xfff00fff; | ||
1344 | insn |= 0x00001000; /* Rn = r0, Rd = r1 */ | ||
1345 | asi->insn[0] = insn; | ||
1346 | asi->insn_handler = (insn & (1 << 20)) ? emulate_mrrc : emulate_mcrr; | ||
1347 | return INSN_GOOD; | ||
1348 | } | ||
1349 | |||
1350 | static enum kprobe_insn __kprobes | ||
1351 | space_cccc_110x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1352 | { | ||
1353 | /* LDC : cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ | ||
1354 | /* STC : cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ | ||
1355 | insn &= 0xfff0ffff; /* Rn = r0 */ | ||
1356 | asi->insn[0] = insn; | ||
1357 | asi->insn_handler = emulate_ldcstc; | ||
1358 | return INSN_GOOD; | ||
1359 | } | ||
1360 | |||
1361 | static enum kprobe_insn __kprobes | ||
1362 | space_cccc_111x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1363 | { | ||
1364 | /* BKPT : 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */ | ||
1365 | /* SWI : cccc 1111 xxxx xxxx xxxx xxxx xxxx xxxx */ | ||
1366 | if ((insn & 0xfff000f0) == 0xe1200070 || | ||
1367 | (insn & 0x0f000000) == 0x0f000000) | ||
1368 | return INSN_REJECTED; | ||
1369 | |||
1370 | /* CDP : cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ | ||
1371 | if ((insn & 0x0f000010) == 0x0e000000) { | ||
1372 | asi->insn[0] = insn; | ||
1373 | asi->insn_handler = emulate_none; | ||
1374 | return INSN_GOOD; | ||
1375 | } | ||
1376 | |||
1377 | /* MCR : cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ | ||
1378 | /* MRC : cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ | ||
1379 | insn &= 0xffff0fff; /* Rd = r0 */ | ||
1380 | asi->insn[0] = insn; | ||
1381 | asi->insn_handler = (insn & (1 << 20)) ? emulate_rd12 : emulate_ird12; | ||
1382 | return INSN_GOOD; | ||
1383 | } | ||
1384 | |||
1385 | /* Return: | ||
1386 | * INSN_REJECTED If instruction is one not allowed to kprobe, | ||
1387 | * INSN_GOOD If instruction is supported and uses instruction slot, | ||
1388 | * INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot. | ||
1389 | * | ||
1390 | * For instructions we don't want to kprobe (INSN_REJECTED return result): | ||
1391 | * These are generally ones that modify the processor state making | ||
1392 | * them "hard" to simulate such as switches processor modes or | ||
1393 | * make accesses in alternate modes. Any of these could be simulated | ||
1394 | * if the work was put into it, but low return considering they | ||
1395 | * should also be very rare. | ||
1396 | */ | ||
1397 | enum kprobe_insn __kprobes | ||
1398 | arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1399 | { | ||
1400 | asi->insn[1] = KPROBE_RETURN_INSTRUCTION; | ||
1401 | |||
1402 | if ((insn & 0xf0000000) == 0xf0000000) { | ||
1403 | |||
1404 | return space_1111(insn, asi); | ||
1405 | |||
1406 | } else if ((insn & 0x0e000000) == 0x00000000) { | ||
1407 | |||
1408 | return space_cccc_000x(insn, asi); | ||
1409 | |||
1410 | } else if ((insn & 0x0e000000) == 0x02000000) { | ||
1411 | |||
1412 | return space_cccc_001x(insn, asi); | ||
1413 | |||
1414 | } else if ((insn & 0x0f000010) == 0x06000010) { | ||
1415 | |||
1416 | return space_cccc_0110__1(insn, asi); | ||
1417 | |||
1418 | } else if ((insn & 0x0f000010) == 0x07000010) { | ||
1419 | |||
1420 | return space_cccc_0111__1(insn, asi); | ||
1421 | |||
1422 | } else if ((insn & 0x0c000000) == 0x04000000) { | ||
1423 | |||
1424 | return space_cccc_01xx(insn, asi); | ||
1425 | |||
1426 | } else if ((insn & 0x0e000000) == 0x08000000) { | ||
1427 | |||
1428 | return space_cccc_100x(insn, asi); | ||
1429 | |||
1430 | } else if ((insn & 0x0e000000) == 0x0a000000) { | ||
1431 | |||
1432 | return space_cccc_101x(insn, asi); | ||
1433 | |||
1434 | } else if ((insn & 0x0fe00000) == 0x0c400000) { | ||
1435 | |||
1436 | return space_cccc_1100_010x(insn, asi); | ||
1437 | |||
1438 | } else if ((insn & 0x0e000000) == 0x0c400000) { | ||
1439 | |||
1440 | return space_cccc_110x(insn, asi); | ||
1441 | |||
1442 | } | ||
1443 | |||
1444 | return space_cccc_111x(insn, asi); | ||
1445 | } | ||
1446 | |||
1447 | void __init arm_kprobe_decode_init(void) | ||
1448 | { | ||
1449 | find_str_pc_offset(); | ||
1450 | } | ||
1451 | |||
1452 | |||
1453 | /* | ||
1454 | * All ARM instructions listed below. | ||
1455 | * | ||
1456 | * Instructions and their general purpose registers are given. | ||
1457 | * If a particular register may not use R15, it is prefixed with a "!". | ||
1458 | * If marked with a "*" means the value returned by reading R15 | ||
1459 | * is implementation defined. | ||
1460 | * | ||
1461 | * ADC/ADD/AND/BIC/CMN/CMP/EOR/MOV/MVN/ORR/RSB/RSC/SBC/SUB/TEQ | ||
1462 | * TST: Rd, Rn, Rm, !Rs | ||
1463 | * BX: Rm | ||
1464 | * BLX(2): !Rm | ||
1465 | * BX: Rm (R15 legal, but discouraged) | ||
1466 | * BXJ: !Rm, | ||
1467 | * CLZ: !Rd, !Rm | ||
1468 | * CPY: Rd, Rm | ||
1469 | * LDC/2,STC/2 immediate offset & unindex: Rn | ||
1470 | * LDC/2,STC/2 immediate pre/post-indexed: !Rn | ||
1471 | * LDM(1/3): !Rn, register_list | ||
1472 | * LDM(2): !Rn, !register_list | ||
1473 | * LDR,STR,PLD immediate offset: Rd, Rn | ||
1474 | * LDR,STR,PLD register offset: Rd, Rn, !Rm | ||
1475 | * LDR,STR,PLD scaled register offset: Rd, !Rn, !Rm | ||
1476 | * LDR,STR immediate pre/post-indexed: Rd, !Rn | ||
1477 | * LDR,STR register pre/post-indexed: Rd, !Rn, !Rm | ||
1478 | * LDR,STR scaled register pre/post-indexed: Rd, !Rn, !Rm | ||
1479 | * LDRB,STRB immediate offset: !Rd, Rn | ||
1480 | * LDRB,STRB register offset: !Rd, Rn, !Rm | ||
1481 | * LDRB,STRB scaled register offset: !Rd, !Rn, !Rm | ||
1482 | * LDRB,STRB immediate pre/post-indexed: !Rd, !Rn | ||
1483 | * LDRB,STRB register pre/post-indexed: !Rd, !Rn, !Rm | ||
1484 | * LDRB,STRB scaled register pre/post-indexed: !Rd, !Rn, !Rm | ||
1485 | * LDRT,LDRBT,STRBT immediate pre/post-indexed: !Rd, !Rn | ||
1486 | * LDRT,LDRBT,STRBT register pre/post-indexed: !Rd, !Rn, !Rm | ||
1487 | * LDRT,LDRBT,STRBT scaled register pre/post-indexed: !Rd, !Rn, !Rm | ||
1488 | * LDRH/SH/SB/D,STRH/SH/SB/D immediate offset: !Rd, Rn | ||
1489 | * LDRH/SH/SB/D,STRH/SH/SB/D register offset: !Rd, Rn, !Rm | ||
1490 | * LDRH/SH/SB/D,STRH/SH/SB/D immediate pre/post-indexed: !Rd, !Rn | ||
1491 | * LDRH/SH/SB/D,STRH/SH/SB/D register pre/post-indexed: !Rd, !Rn, !Rm | ||
1492 | * LDREX: !Rd, !Rn | ||
1493 | * MCR/2: !Rd | ||
1494 | * MCRR/2,MRRC/2: !Rd, !Rn | ||
1495 | * MLA: !Rd, !Rn, !Rm, !Rs | ||
1496 | * MOV: Rd | ||
1497 | * MRC/2: !Rd (if Rd==15, only changes cond codes, not the register) | ||
1498 | * MRS,MSR: !Rd | ||
1499 | * MUL: !Rd, !Rm, !Rs | ||
1500 | * PKH{BT,TB}: !Rd, !Rn, !Rm | ||
1501 | * QDADD,[U]QADD/16/8/SUBX: !Rd, !Rm, !Rn | ||
1502 | * QDSUB,[U]QSUB/16/8/ADDX: !Rd, !Rm, !Rn | ||
1503 | * REV/16/SH: !Rd, !Rm | ||
1504 | * RFE: !Rn | ||
1505 | * {S,U}[H]ADD{16,8,SUBX},{S,U}[H]SUB{16,8,ADDX}: !Rd, !Rn, !Rm | ||
1506 | * SEL: !Rd, !Rn, !Rm | ||
1507 | * SMLA<x><y>,SMLA{D,W<y>},SMLSD,SMML{A,S}: !Rd, !Rn, !Rm, !Rs | ||
1508 | * SMLAL<x><y>,SMLA{D,LD},SMLSLD,SMMULL,SMULW<y>: !RdHi, !RdLo, !Rm, !Rs | ||
1509 | * SMMUL,SMUAD,SMUL<x><y>,SMUSD: !Rd, !Rm, !Rs | ||
1510 | * SSAT/16: !Rd, !Rm | ||
1511 | * STM(1/2): !Rn, register_list* (R15 in reg list not recommended) | ||
1512 | * STRT immediate pre/post-indexed: Rd*, !Rn | ||
1513 | * STRT register pre/post-indexed: Rd*, !Rn, !Rm | ||
1514 | * STRT scaled register pre/post-indexed: Rd*, !Rn, !Rm | ||
1515 | * STREX: !Rd, !Rn, !Rm | ||
1516 | * SWP/B: !Rd, !Rn, !Rm | ||
1517 | * {S,U}XTA{B,B16,H}: !Rd, !Rn, !Rm | ||
1518 | * {S,U}XT{B,B16,H}: !Rd, !Rm | ||
1519 | * UM{AA,LA,UL}L: !RdHi, !RdLo, !Rm, !Rs | ||
1520 | * USA{D8,A8,T,T16}: !Rd, !Rm, !Rs | ||
1521 | * | ||
1522 | * May transfer control by writing R15 (possible mode changes or alternate | ||
1523 | * mode accesses marked by "*"): | ||
1524 | * ALU op (* with s-bit), B, BL, BKPT, BLX(1/2), BX, BXJ, CPS*, CPY, | ||
1525 | * LDM(1), LDM(2/3)*, LDR, MOV, RFE*, SWI* | ||
1526 | * | ||
1527 | * Instructions that do not take general registers, nor transfer control: | ||
1528 | * CDP/2, SETEND, SRS* | ||
1529 | */ | ||
diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c new file mode 100644 index 000000000000..a22a98c43ca5 --- /dev/null +++ b/arch/arm/kernel/kprobes.c | |||
@@ -0,0 +1,447 @@ | |||
1 | /* | ||
2 | * arch/arm/kernel/kprobes.c | ||
3 | * | ||
4 | * Kprobes on ARM | ||
5 | * | ||
6 | * Abhishek Sagar <sagar.abhishek@gmail.com> | ||
7 | * Copyright (C) 2006, 2007 Motorola Inc. | ||
8 | * | ||
9 | * Nicolas Pitre <nico@marvell.com> | ||
10 | * Copyright (C) 2007 Marvell Ltd. | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License version 2 as | ||
14 | * published by the Free Software Foundation. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
19 | * General Public License for more details. | ||
20 | */ | ||
21 | |||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/kprobes.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/stringify.h> | ||
26 | #include <asm/traps.h> | ||
27 | #include <asm/cacheflush.h> | ||
28 | |||
29 | #define MIN_STACK_SIZE(addr) \ | ||
30 | min((unsigned long)MAX_STACK_SIZE, \ | ||
31 | (unsigned long)current_thread_info() + THREAD_START_SP - (addr)) | ||
32 | |||
33 | #define flush_insns(addr, cnt) \ | ||
34 | flush_icache_range((unsigned long)(addr), \ | ||
35 | (unsigned long)(addr) + \ | ||
36 | sizeof(kprobe_opcode_t) * (cnt)) | ||
37 | |||
38 | /* Used as a marker in ARM_pc to note when we're in a jprobe. */ | ||
39 | #define JPROBE_MAGIC_ADDR 0xffffffff | ||
40 | |||
41 | DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; | ||
42 | DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); | ||
43 | |||
44 | |||
45 | int __kprobes arch_prepare_kprobe(struct kprobe *p) | ||
46 | { | ||
47 | kprobe_opcode_t insn; | ||
48 | kprobe_opcode_t tmp_insn[MAX_INSN_SIZE]; | ||
49 | unsigned long addr = (unsigned long)p->addr; | ||
50 | int is; | ||
51 | |||
52 | if (addr & 0x3 || in_exception_text(addr)) | ||
53 | return -EINVAL; | ||
54 | |||
55 | insn = *p->addr; | ||
56 | p->opcode = insn; | ||
57 | p->ainsn.insn = tmp_insn; | ||
58 | |||
59 | switch (arm_kprobe_decode_insn(insn, &p->ainsn)) { | ||
60 | case INSN_REJECTED: /* not supported */ | ||
61 | return -EINVAL; | ||
62 | |||
63 | case INSN_GOOD: /* instruction uses slot */ | ||
64 | p->ainsn.insn = get_insn_slot(); | ||
65 | if (!p->ainsn.insn) | ||
66 | return -ENOMEM; | ||
67 | for (is = 0; is < MAX_INSN_SIZE; ++is) | ||
68 | p->ainsn.insn[is] = tmp_insn[is]; | ||
69 | flush_insns(&p->ainsn.insn, MAX_INSN_SIZE); | ||
70 | break; | ||
71 | |||
72 | case INSN_GOOD_NO_SLOT: /* instruction doesn't need insn slot */ | ||
73 | p->ainsn.insn = NULL; | ||
74 | break; | ||
75 | } | ||
76 | |||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | void __kprobes arch_arm_kprobe(struct kprobe *p) | ||
81 | { | ||
82 | *p->addr = KPROBE_BREAKPOINT_INSTRUCTION; | ||
83 | flush_insns(p->addr, 1); | ||
84 | } | ||
85 | |||
86 | void __kprobes arch_disarm_kprobe(struct kprobe *p) | ||
87 | { | ||
88 | *p->addr = p->opcode; | ||
89 | flush_insns(p->addr, 1); | ||
90 | } | ||
91 | |||
92 | void __kprobes arch_remove_kprobe(struct kprobe *p) | ||
93 | { | ||
94 | if (p->ainsn.insn) { | ||
95 | mutex_lock(&kprobe_mutex); | ||
96 | free_insn_slot(p->ainsn.insn, 0); | ||
97 | mutex_unlock(&kprobe_mutex); | ||
98 | p->ainsn.insn = NULL; | ||
99 | } | ||
100 | } | ||
101 | |||
102 | static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb) | ||
103 | { | ||
104 | kcb->prev_kprobe.kp = kprobe_running(); | ||
105 | kcb->prev_kprobe.status = kcb->kprobe_status; | ||
106 | } | ||
107 | |||
108 | static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb) | ||
109 | { | ||
110 | __get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp; | ||
111 | kcb->kprobe_status = kcb->prev_kprobe.status; | ||
112 | } | ||
113 | |||
114 | static void __kprobes set_current_kprobe(struct kprobe *p) | ||
115 | { | ||
116 | __get_cpu_var(current_kprobe) = p; | ||
117 | } | ||
118 | |||
119 | static void __kprobes singlestep(struct kprobe *p, struct pt_regs *regs, | ||
120 | struct kprobe_ctlblk *kcb) | ||
121 | { | ||
122 | regs->ARM_pc += 4; | ||
123 | p->ainsn.insn_handler(p, regs); | ||
124 | } | ||
125 | |||
126 | /* | ||
127 | * Called with IRQs disabled. IRQs must remain disabled from that point | ||
128 | * all the way until processing this kprobe is complete. The current | ||
129 | * kprobes implementation cannot process more than one nested level of | ||
130 | * kprobe, and that level is reserved for user kprobe handlers, so we can't | ||
131 | * risk encountering a new kprobe in an interrupt handler. | ||
132 | */ | ||
133 | void __kprobes kprobe_handler(struct pt_regs *regs) | ||
134 | { | ||
135 | struct kprobe *p, *cur; | ||
136 | struct kprobe_ctlblk *kcb; | ||
137 | kprobe_opcode_t *addr = (kprobe_opcode_t *)regs->ARM_pc; | ||
138 | |||
139 | kcb = get_kprobe_ctlblk(); | ||
140 | cur = kprobe_running(); | ||
141 | p = get_kprobe(addr); | ||
142 | |||
143 | if (p) { | ||
144 | if (cur) { | ||
145 | /* Kprobe is pending, so we're recursing. */ | ||
146 | switch (kcb->kprobe_status) { | ||
147 | case KPROBE_HIT_ACTIVE: | ||
148 | case KPROBE_HIT_SSDONE: | ||
149 | /* A pre- or post-handler probe got us here. */ | ||
150 | kprobes_inc_nmissed_count(p); | ||
151 | save_previous_kprobe(kcb); | ||
152 | set_current_kprobe(p); | ||
153 | kcb->kprobe_status = KPROBE_REENTER; | ||
154 | singlestep(p, regs, kcb); | ||
155 | restore_previous_kprobe(kcb); | ||
156 | break; | ||
157 | default: | ||
158 | /* impossible cases */ | ||
159 | BUG(); | ||
160 | } | ||
161 | } else { | ||
162 | set_current_kprobe(p); | ||
163 | kcb->kprobe_status = KPROBE_HIT_ACTIVE; | ||
164 | |||
165 | /* | ||
166 | * If we have no pre-handler or it returned 0, we | ||
167 | * continue with normal processing. If we have a | ||
168 | * pre-handler and it returned non-zero, it prepped | ||
169 | * for calling the break_handler below on re-entry, | ||
170 | * so get out doing nothing more here. | ||
171 | */ | ||
172 | if (!p->pre_handler || !p->pre_handler(p, regs)) { | ||
173 | kcb->kprobe_status = KPROBE_HIT_SS; | ||
174 | singlestep(p, regs, kcb); | ||
175 | if (p->post_handler) { | ||
176 | kcb->kprobe_status = KPROBE_HIT_SSDONE; | ||
177 | p->post_handler(p, regs, 0); | ||
178 | } | ||
179 | reset_current_kprobe(); | ||
180 | } | ||
181 | } | ||
182 | } else if (cur) { | ||
183 | /* We probably hit a jprobe. Call its break handler. */ | ||
184 | if (cur->break_handler && cur->break_handler(cur, regs)) { | ||
185 | kcb->kprobe_status = KPROBE_HIT_SS; | ||
186 | singlestep(cur, regs, kcb); | ||
187 | if (cur->post_handler) { | ||
188 | kcb->kprobe_status = KPROBE_HIT_SSDONE; | ||
189 | cur->post_handler(cur, regs, 0); | ||
190 | } | ||
191 | } | ||
192 | reset_current_kprobe(); | ||
193 | } else { | ||
194 | /* | ||
195 | * The probe was removed and a race is in progress. | ||
196 | * There is nothing we can do about it. Let's restart | ||
197 | * the instruction. By the time we can restart, the | ||
198 | * real instruction will be there. | ||
199 | */ | ||
200 | } | ||
201 | } | ||
202 | |||
203 | int kprobe_trap_handler(struct pt_regs *regs, unsigned int instr) | ||
204 | { | ||
205 | kprobe_handler(regs); | ||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr) | ||
210 | { | ||
211 | struct kprobe *cur = kprobe_running(); | ||
212 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | ||
213 | |||
214 | switch (kcb->kprobe_status) { | ||
215 | case KPROBE_HIT_SS: | ||
216 | case KPROBE_REENTER: | ||
217 | /* | ||
218 | * We are here because the instruction being single | ||
219 | * stepped caused a page fault. We reset the current | ||
220 | * kprobe and the PC to point back to the probe address | ||
221 | * and allow the page fault handler to continue as a | ||
222 | * normal page fault. | ||
223 | */ | ||
224 | regs->ARM_pc = (long)cur->addr; | ||
225 | if (kcb->kprobe_status == KPROBE_REENTER) { | ||
226 | restore_previous_kprobe(kcb); | ||
227 | } else { | ||
228 | reset_current_kprobe(); | ||
229 | } | ||
230 | break; | ||
231 | |||
232 | case KPROBE_HIT_ACTIVE: | ||
233 | case KPROBE_HIT_SSDONE: | ||
234 | /* | ||
235 | * We increment the nmissed count for accounting, | ||
236 | * we can also use npre/npostfault count for accounting | ||
237 | * these specific fault cases. | ||
238 | */ | ||
239 | kprobes_inc_nmissed_count(cur); | ||
240 | |||
241 | /* | ||
242 | * We come here because instructions in the pre/post | ||
243 | * handler caused the page_fault, this could happen | ||
244 | * if handler tries to access user space by | ||
245 | * copy_from_user(), get_user() etc. Let the | ||
246 | * user-specified handler try to fix it. | ||
247 | */ | ||
248 | if (cur->fault_handler && cur->fault_handler(cur, regs, fsr)) | ||
249 | return 1; | ||
250 | break; | ||
251 | |||
252 | default: | ||
253 | break; | ||
254 | } | ||
255 | |||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | int __kprobes kprobe_exceptions_notify(struct notifier_block *self, | ||
260 | unsigned long val, void *data) | ||
261 | { | ||
262 | /* | ||
263 | * notify_die() is currently never called on ARM, | ||
264 | * so this callback is currently empty. | ||
265 | */ | ||
266 | return NOTIFY_DONE; | ||
267 | } | ||
268 | |||
269 | /* | ||
270 | * When a retprobed function returns, trampoline_handler() is called, | ||
271 | * calling the kretprobe's handler. We construct a struct pt_regs to | ||
272 | * give a view of registers r0-r11 to the user return-handler. This is | ||
273 | * not a complete pt_regs structure, but that should be plenty sufficient | ||
274 | * for kretprobe handlers which should normally be interested in r0 only | ||
275 | * anyway. | ||
276 | */ | ||
277 | static void __attribute__((naked)) __kprobes kretprobe_trampoline(void) | ||
278 | { | ||
279 | __asm__ __volatile__ ( | ||
280 | "stmdb sp!, {r0 - r11} \n\t" | ||
281 | "mov r0, sp \n\t" | ||
282 | "bl trampoline_handler \n\t" | ||
283 | "mov lr, r0 \n\t" | ||
284 | "ldmia sp!, {r0 - r11} \n\t" | ||
285 | "mov pc, lr \n\t" | ||
286 | : : : "memory"); | ||
287 | } | ||
288 | |||
289 | /* Called from kretprobe_trampoline */ | ||
290 | static __used __kprobes void *trampoline_handler(struct pt_regs *regs) | ||
291 | { | ||
292 | struct kretprobe_instance *ri = NULL; | ||
293 | struct hlist_head *head, empty_rp; | ||
294 | struct hlist_node *node, *tmp; | ||
295 | unsigned long flags, orig_ret_address = 0; | ||
296 | unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline; | ||
297 | |||
298 | INIT_HLIST_HEAD(&empty_rp); | ||
299 | spin_lock_irqsave(&kretprobe_lock, flags); | ||
300 | head = kretprobe_inst_table_head(current); | ||
301 | |||
302 | /* | ||
303 | * It is possible to have multiple instances associated with a given | ||
304 | * task either because multiple functions in the call path have | ||
305 | * a return probe installed on them, and/or more than one return | ||
306 | * probe was registered for a target function. | ||
307 | * | ||
308 | * We can handle this because: | ||
309 | * - instances are always inserted at the head of the list | ||
310 | * - when multiple return probes are registered for the same | ||
311 | * function, the first instance's ret_addr will point to the | ||
312 | * real return address, and all the rest will point to | ||
313 | * kretprobe_trampoline | ||
314 | */ | ||
315 | hlist_for_each_entry_safe(ri, node, tmp, head, hlist) { | ||
316 | if (ri->task != current) | ||
317 | /* another task is sharing our hash bucket */ | ||
318 | continue; | ||
319 | |||
320 | if (ri->rp && ri->rp->handler) { | ||
321 | __get_cpu_var(current_kprobe) = &ri->rp->kp; | ||
322 | get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE; | ||
323 | ri->rp->handler(ri, regs); | ||
324 | __get_cpu_var(current_kprobe) = NULL; | ||
325 | } | ||
326 | |||
327 | orig_ret_address = (unsigned long)ri->ret_addr; | ||
328 | recycle_rp_inst(ri, &empty_rp); | ||
329 | |||
330 | if (orig_ret_address != trampoline_address) | ||
331 | /* | ||
332 | * This is the real return address. Any other | ||
333 | * instances associated with this task are for | ||
334 | * other calls deeper on the call stack | ||
335 | */ | ||
336 | break; | ||
337 | } | ||
338 | |||
339 | kretprobe_assert(ri, orig_ret_address, trampoline_address); | ||
340 | spin_unlock_irqrestore(&kretprobe_lock, flags); | ||
341 | |||
342 | hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) { | ||
343 | hlist_del(&ri->hlist); | ||
344 | kfree(ri); | ||
345 | } | ||
346 | |||
347 | return (void *)orig_ret_address; | ||
348 | } | ||
349 | |||
350 | /* Called with kretprobe_lock held. */ | ||
351 | void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, | ||
352 | struct pt_regs *regs) | ||
353 | { | ||
354 | ri->ret_addr = (kprobe_opcode_t *)regs->ARM_lr; | ||
355 | |||
356 | /* Replace the return addr with trampoline addr. */ | ||
357 | regs->ARM_lr = (unsigned long)&kretprobe_trampoline; | ||
358 | } | ||
359 | |||
360 | int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) | ||
361 | { | ||
362 | struct jprobe *jp = container_of(p, struct jprobe, kp); | ||
363 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | ||
364 | long sp_addr = regs->ARM_sp; | ||
365 | |||
366 | kcb->jprobe_saved_regs = *regs; | ||
367 | memcpy(kcb->jprobes_stack, (void *)sp_addr, MIN_STACK_SIZE(sp_addr)); | ||
368 | regs->ARM_pc = (long)jp->entry; | ||
369 | regs->ARM_cpsr |= PSR_I_BIT; | ||
370 | preempt_disable(); | ||
371 | return 1; | ||
372 | } | ||
373 | |||
374 | void __kprobes jprobe_return(void) | ||
375 | { | ||
376 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | ||
377 | |||
378 | __asm__ __volatile__ ( | ||
379 | /* | ||
380 | * Setup an empty pt_regs. Fill SP and PC fields as | ||
381 | * they're needed by longjmp_break_handler. | ||
382 | */ | ||
383 | "sub sp, %0, %1 \n\t" | ||
384 | "ldr r0, ="__stringify(JPROBE_MAGIC_ADDR)"\n\t" | ||
385 | "str %0, [sp, %2] \n\t" | ||
386 | "str r0, [sp, %3] \n\t" | ||
387 | "mov r0, sp \n\t" | ||
388 | "bl kprobe_handler \n\t" | ||
389 | |||
390 | /* | ||
391 | * Return to the context saved by setjmp_pre_handler | ||
392 | * and restored by longjmp_break_handler. | ||
393 | */ | ||
394 | "ldr r0, [sp, %4] \n\t" | ||
395 | "msr cpsr_cxsf, r0 \n\t" | ||
396 | "ldmia sp, {r0 - pc} \n\t" | ||
397 | : | ||
398 | : "r" (kcb->jprobe_saved_regs.ARM_sp), | ||
399 | "I" (sizeof(struct pt_regs)), | ||
400 | "J" (offsetof(struct pt_regs, ARM_sp)), | ||
401 | "J" (offsetof(struct pt_regs, ARM_pc)), | ||
402 | "J" (offsetof(struct pt_regs, ARM_cpsr)) | ||
403 | : "memory", "cc"); | ||
404 | } | ||
405 | |||
406 | int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) | ||
407 | { | ||
408 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | ||
409 | long stack_addr = kcb->jprobe_saved_regs.ARM_sp; | ||
410 | long orig_sp = regs->ARM_sp; | ||
411 | struct jprobe *jp = container_of(p, struct jprobe, kp); | ||
412 | |||
413 | if (regs->ARM_pc == JPROBE_MAGIC_ADDR) { | ||
414 | if (orig_sp != stack_addr) { | ||
415 | struct pt_regs *saved_regs = | ||
416 | (struct pt_regs *)kcb->jprobe_saved_regs.ARM_sp; | ||
417 | printk("current sp %lx does not match saved sp %lx\n", | ||
418 | orig_sp, stack_addr); | ||
419 | printk("Saved registers for jprobe %p\n", jp); | ||
420 | show_regs(saved_regs); | ||
421 | printk("Current registers\n"); | ||
422 | show_regs(regs); | ||
423 | BUG(); | ||
424 | } | ||
425 | *regs = kcb->jprobe_saved_regs; | ||
426 | memcpy((void *)stack_addr, kcb->jprobes_stack, | ||
427 | MIN_STACK_SIZE(stack_addr)); | ||
428 | preempt_enable_no_resched(); | ||
429 | return 1; | ||
430 | } | ||
431 | return 0; | ||
432 | } | ||
433 | |||
434 | static struct undef_hook kprobes_break_hook = { | ||
435 | .instr_mask = 0xffffffff, | ||
436 | .instr_val = KPROBE_BREAKPOINT_INSTRUCTION, | ||
437 | .cpsr_mask = MODE_MASK, | ||
438 | .cpsr_val = SVC_MODE, | ||
439 | .fn = kprobe_trap_handler, | ||
440 | }; | ||
441 | |||
442 | int __init arch_init_kprobes() | ||
443 | { | ||
444 | arm_kprobe_decode_init(); | ||
445 | register_undef_hook(&kprobes_break_hook); | ||
446 | return 0; | ||
447 | } | ||
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index e59b5b84168d..b5867eca1d0b 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c | |||
@@ -325,7 +325,9 @@ void timer_tick(void) | |||
325 | profile_tick(CPU_PROFILING); | 325 | profile_tick(CPU_PROFILING); |
326 | do_leds(); | 326 | do_leds(); |
327 | do_set_rtc(); | 327 | do_set_rtc(); |
328 | write_seqlock(&xtime_lock); | ||
328 | do_timer(1); | 329 | do_timer(1); |
330 | write_sequnlock(&xtime_lock); | ||
329 | #ifndef CONFIG_SMP | 331 | #ifndef CONFIG_SMP |
330 | update_process_times(user_mode(get_irq_regs())); | 332 | update_process_times(user_mode(get_irq_regs())); |
331 | #endif | 333 | #endif |
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index c34db4e868fa..5595fdd75e82 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/kallsyms.h> | 19 | #include <linux/kallsyms.h> |
20 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/kprobes.h> | ||
22 | 23 | ||
23 | #include <asm/atomic.h> | 24 | #include <asm/atomic.h> |
24 | #include <asm/cacheflush.h> | 25 | #include <asm/cacheflush.h> |
@@ -46,15 +47,6 @@ __setup("user_debug=", user_debug_setup); | |||
46 | 47 | ||
47 | static void dump_mem(const char *str, unsigned long bottom, unsigned long top); | 48 | static void dump_mem(const char *str, unsigned long bottom, unsigned long top); |
48 | 49 | ||
49 | static inline int in_exception_text(unsigned long ptr) | ||
50 | { | ||
51 | extern char __exception_text_start[]; | ||
52 | extern char __exception_text_end[]; | ||
53 | |||
54 | return ptr >= (unsigned long)&__exception_text_start && | ||
55 | ptr < (unsigned long)&__exception_text_end; | ||
56 | } | ||
57 | |||
58 | void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame) | 50 | void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame) |
59 | { | 51 | { |
60 | #ifdef CONFIG_KALLSYMS | 52 | #ifdef CONFIG_KALLSYMS |
@@ -322,6 +314,17 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs) | |||
322 | get_user(instr, (u32 __user *)pc); | 314 | get_user(instr, (u32 __user *)pc); |
323 | } | 315 | } |
324 | 316 | ||
317 | #ifdef CONFIG_KPROBES | ||
318 | /* | ||
319 | * It is possible to have recursive kprobes, so we can't call | ||
320 | * the kprobe trap handler with the undef_lock held. | ||
321 | */ | ||
322 | if (instr == KPROBE_BREAKPOINT_INSTRUCTION && !user_mode(regs)) { | ||
323 | kprobe_trap_handler(regs, instr); | ||
324 | return; | ||
325 | } | ||
326 | #endif | ||
327 | |||
325 | spin_lock_irqsave(&undef_lock, flags); | 328 | spin_lock_irqsave(&undef_lock, flags); |
326 | list_for_each_entry(hook, &undef_hook, node) { | 329 | list_for_each_entry(hook, &undef_hook, node) { |
327 | if ((instr & hook->instr_mask) == hook->instr_val && | 330 | if ((instr & hook->instr_mask) == hook->instr_val && |
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index 5ff5406666b4..30f732c7fdb5 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S | |||
@@ -94,6 +94,7 @@ SECTIONS | |||
94 | TEXT_TEXT | 94 | TEXT_TEXT |
95 | SCHED_TEXT | 95 | SCHED_TEXT |
96 | LOCK_TEXT | 96 | LOCK_TEXT |
97 | KPROBES_TEXT | ||
97 | #ifdef CONFIG_MMU | 98 | #ifdef CONFIG_MMU |
98 | *(.fixup) | 99 | *(.fixup) |
99 | #endif | 100 | #endif |