diff options
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/kernel/kprobes-decode.c | 1529 |
2 files changed, 1530 insertions, 0 deletions
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 593b56509f4f..9e0eebacd3d9 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-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/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 | */ | ||