diff options
author | Jon Medhurst <tixy@yxit.co.uk> | 2011-07-06 05:49:07 -0400 |
---|---|---|
committer | Tixy <tixy@medhuaa1.miniserver.com> | 2011-07-13 13:32:40 -0400 |
commit | 691b2ff294a4787f3e54f5bb541570ac74bcb6f4 (patch) | |
tree | 77f3452cbd7c20f6bf69ab9c8759720740933b5c /arch/arm/kernel/kprobes-arm.c | |
parent | 592201a9f154cdd5db59304d1369e94d8b551803 (diff) |
ARM: kprobes: Rename kprobes-decode.c to kprobes-arm.c
This file contains decoding and emulation functions for the ARM
instruction set. As we will later be adding a file for Thumb and a
file with common decoding functions, this renaming makes things clearer.
Signed-off-by: Jon Medhurst <tixy@yxit.co.uk>
Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Diffstat (limited to 'arch/arm/kernel/kprobes-arm.c')
-rw-r--r-- | arch/arm/kernel/kprobes-arm.c | 1670 |
1 files changed, 1670 insertions, 0 deletions
diff --git a/arch/arm/kernel/kprobes-arm.c b/arch/arm/kernel/kprobes-arm.c new file mode 100644 index 000000000000..15eeff6aea0e --- /dev/null +++ b/arch/arm/kernel/kprobes-arm.c | |||
@@ -0,0 +1,1670 @@ | |||
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 | * | ||
38 | * *) Otherwise, a modified form of the instruction is | ||
39 | * directly executed. Its handler calls the | ||
40 | * instruction in insn[0]. In insn[1] is a | ||
41 | * "mov pc, lr" to return. | ||
42 | * | ||
43 | * Before calling, load up the reordered registers | ||
44 | * from the original instruction's registers. If one | ||
45 | * of the original input registers is the PC, compute | ||
46 | * and adjust the appropriate input register. | ||
47 | * | ||
48 | * After call completes, copy the output registers to | ||
49 | * the original instruction's original registers. | ||
50 | * | ||
51 | * We don't use a real breakpoint instruction since that | ||
52 | * would have us in the kernel go from SVC mode to SVC | ||
53 | * mode losing the link register. Instead we use an | ||
54 | * undefined instruction. To simplify processing, the | ||
55 | * undefined instruction used for kprobes must be reserved | ||
56 | * exclusively for kprobes use. | ||
57 | * | ||
58 | * TODO: ifdef out some instruction decoding based on architecture. | ||
59 | */ | ||
60 | |||
61 | #include <linux/kernel.h> | ||
62 | #include <linux/kprobes.h> | ||
63 | |||
64 | #define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit))))) | ||
65 | |||
66 | #define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25) | ||
67 | |||
68 | #define is_r15(insn, bitpos) (((insn) & (0xf << bitpos)) == (0xf << bitpos)) | ||
69 | |||
70 | /* | ||
71 | * Test if load/store instructions writeback the address register. | ||
72 | * if P (bit 24) == 0 or W (bit 21) == 1 | ||
73 | */ | ||
74 | #define is_writeback(insn) ((insn ^ 0x01000000) & 0x01200000) | ||
75 | |||
76 | #define PSR_fs (PSR_f|PSR_s) | ||
77 | |||
78 | #define KPROBE_RETURN_INSTRUCTION 0xe1a0f00e /* mov pc, lr */ | ||
79 | |||
80 | typedef long (insn_0arg_fn_t)(void); | ||
81 | typedef long (insn_1arg_fn_t)(long); | ||
82 | typedef long (insn_2arg_fn_t)(long, long); | ||
83 | typedef long (insn_3arg_fn_t)(long, long, long); | ||
84 | typedef long (insn_4arg_fn_t)(long, long, long, long); | ||
85 | typedef long long (insn_llret_0arg_fn_t)(void); | ||
86 | typedef long long (insn_llret_3arg_fn_t)(long, long, long); | ||
87 | typedef long long (insn_llret_4arg_fn_t)(long, long, long, long); | ||
88 | |||
89 | union reg_pair { | ||
90 | long long dr; | ||
91 | #ifdef __LITTLE_ENDIAN | ||
92 | struct { long r0, r1; }; | ||
93 | #else | ||
94 | struct { long r1, r0; }; | ||
95 | #endif | ||
96 | }; | ||
97 | |||
98 | /* | ||
99 | * For STR and STM instructions, an ARM core may choose to use either | ||
100 | * a +8 or a +12 displacement from the current instruction's address. | ||
101 | * Whichever value is chosen for a given core, it must be the same for | ||
102 | * both instructions and may not change. This function measures it. | ||
103 | */ | ||
104 | |||
105 | static int str_pc_offset; | ||
106 | |||
107 | static void __init find_str_pc_offset(void) | ||
108 | { | ||
109 | int addr, scratch, ret; | ||
110 | |||
111 | __asm__ ( | ||
112 | "sub %[ret], pc, #4 \n\t" | ||
113 | "str pc, %[addr] \n\t" | ||
114 | "ldr %[scr], %[addr] \n\t" | ||
115 | "sub %[ret], %[scr], %[ret] \n\t" | ||
116 | : [ret] "=r" (ret), [scr] "=r" (scratch), [addr] "+m" (addr)); | ||
117 | |||
118 | str_pc_offset = ret; | ||
119 | } | ||
120 | |||
121 | /* | ||
122 | * The insnslot_?arg_r[w]flags() functions below are to keep the | ||
123 | * msr -> *fn -> mrs instruction sequences indivisible so that | ||
124 | * the state of the CPSR flags aren't inadvertently modified | ||
125 | * just before or just after the call. | ||
126 | */ | ||
127 | |||
128 | static inline long __kprobes | ||
129 | insnslot_0arg_rflags(long cpsr, insn_0arg_fn_t *fn) | ||
130 | { | ||
131 | register long ret asm("r0"); | ||
132 | |||
133 | __asm__ __volatile__ ( | ||
134 | "msr cpsr_fs, %[cpsr] \n\t" | ||
135 | "mov lr, pc \n\t" | ||
136 | "mov pc, %[fn] \n\t" | ||
137 | : "=r" (ret) | ||
138 | : [cpsr] "r" (cpsr), [fn] "r" (fn) | ||
139 | : "lr", "cc" | ||
140 | ); | ||
141 | return ret; | ||
142 | } | ||
143 | |||
144 | static inline long long __kprobes | ||
145 | insnslot_llret_0arg_rflags(long cpsr, insn_llret_0arg_fn_t *fn) | ||
146 | { | ||
147 | register long ret0 asm("r0"); | ||
148 | register long ret1 asm("r1"); | ||
149 | union reg_pair fnr; | ||
150 | |||
151 | __asm__ __volatile__ ( | ||
152 | "msr cpsr_fs, %[cpsr] \n\t" | ||
153 | "mov lr, pc \n\t" | ||
154 | "mov pc, %[fn] \n\t" | ||
155 | : "=r" (ret0), "=r" (ret1) | ||
156 | : [cpsr] "r" (cpsr), [fn] "r" (fn) | ||
157 | : "lr", "cc" | ||
158 | ); | ||
159 | fnr.r0 = ret0; | ||
160 | fnr.r1 = ret1; | ||
161 | return fnr.dr; | ||
162 | } | ||
163 | |||
164 | static inline long __kprobes | ||
165 | insnslot_1arg_rflags(long r0, long cpsr, insn_1arg_fn_t *fn) | ||
166 | { | ||
167 | register long rr0 asm("r0") = r0; | ||
168 | register long ret asm("r0"); | ||
169 | |||
170 | __asm__ __volatile__ ( | ||
171 | "msr cpsr_fs, %[cpsr] \n\t" | ||
172 | "mov lr, pc \n\t" | ||
173 | "mov pc, %[fn] \n\t" | ||
174 | : "=r" (ret) | ||
175 | : "0" (rr0), [cpsr] "r" (cpsr), [fn] "r" (fn) | ||
176 | : "lr", "cc" | ||
177 | ); | ||
178 | return ret; | ||
179 | } | ||
180 | |||
181 | static inline long __kprobes | ||
182 | insnslot_2arg_rflags(long r0, long r1, long cpsr, insn_2arg_fn_t *fn) | ||
183 | { | ||
184 | register long rr0 asm("r0") = r0; | ||
185 | register long rr1 asm("r1") = r1; | ||
186 | register long ret asm("r0"); | ||
187 | |||
188 | __asm__ __volatile__ ( | ||
189 | "msr cpsr_fs, %[cpsr] \n\t" | ||
190 | "mov lr, pc \n\t" | ||
191 | "mov pc, %[fn] \n\t" | ||
192 | : "=r" (ret) | ||
193 | : "0" (rr0), "r" (rr1), | ||
194 | [cpsr] "r" (cpsr), [fn] "r" (fn) | ||
195 | : "lr", "cc" | ||
196 | ); | ||
197 | return ret; | ||
198 | } | ||
199 | |||
200 | static inline long __kprobes | ||
201 | insnslot_3arg_rflags(long r0, long r1, long r2, long cpsr, insn_3arg_fn_t *fn) | ||
202 | { | ||
203 | register long rr0 asm("r0") = r0; | ||
204 | register long rr1 asm("r1") = r1; | ||
205 | register long rr2 asm("r2") = r2; | ||
206 | register long ret asm("r0"); | ||
207 | |||
208 | __asm__ __volatile__ ( | ||
209 | "msr cpsr_fs, %[cpsr] \n\t" | ||
210 | "mov lr, pc \n\t" | ||
211 | "mov pc, %[fn] \n\t" | ||
212 | : "=r" (ret) | ||
213 | : "0" (rr0), "r" (rr1), "r" (rr2), | ||
214 | [cpsr] "r" (cpsr), [fn] "r" (fn) | ||
215 | : "lr", "cc" | ||
216 | ); | ||
217 | return ret; | ||
218 | } | ||
219 | |||
220 | static inline long long __kprobes | ||
221 | insnslot_llret_3arg_rflags(long r0, long r1, long r2, long cpsr, | ||
222 | insn_llret_3arg_fn_t *fn) | ||
223 | { | ||
224 | register long rr0 asm("r0") = r0; | ||
225 | register long rr1 asm("r1") = r1; | ||
226 | register long rr2 asm("r2") = r2; | ||
227 | register long ret0 asm("r0"); | ||
228 | register long ret1 asm("r1"); | ||
229 | union reg_pair fnr; | ||
230 | |||
231 | __asm__ __volatile__ ( | ||
232 | "msr cpsr_fs, %[cpsr] \n\t" | ||
233 | "mov lr, pc \n\t" | ||
234 | "mov pc, %[fn] \n\t" | ||
235 | : "=r" (ret0), "=r" (ret1) | ||
236 | : "0" (rr0), "r" (rr1), "r" (rr2), | ||
237 | [cpsr] "r" (cpsr), [fn] "r" (fn) | ||
238 | : "lr", "cc" | ||
239 | ); | ||
240 | fnr.r0 = ret0; | ||
241 | fnr.r1 = ret1; | ||
242 | return fnr.dr; | ||
243 | } | ||
244 | |||
245 | static inline long __kprobes | ||
246 | insnslot_4arg_rflags(long r0, long r1, long r2, long r3, long cpsr, | ||
247 | insn_4arg_fn_t *fn) | ||
248 | { | ||
249 | register long rr0 asm("r0") = r0; | ||
250 | register long rr1 asm("r1") = r1; | ||
251 | register long rr2 asm("r2") = r2; | ||
252 | register long rr3 asm("r3") = r3; | ||
253 | register long ret asm("r0"); | ||
254 | |||
255 | __asm__ __volatile__ ( | ||
256 | "msr cpsr_fs, %[cpsr] \n\t" | ||
257 | "mov lr, pc \n\t" | ||
258 | "mov pc, %[fn] \n\t" | ||
259 | : "=r" (ret) | ||
260 | : "0" (rr0), "r" (rr1), "r" (rr2), "r" (rr3), | ||
261 | [cpsr] "r" (cpsr), [fn] "r" (fn) | ||
262 | : "lr", "cc" | ||
263 | ); | ||
264 | return ret; | ||
265 | } | ||
266 | |||
267 | static inline long __kprobes | ||
268 | insnslot_1arg_rwflags(long r0, long *cpsr, insn_1arg_fn_t *fn) | ||
269 | { | ||
270 | register long rr0 asm("r0") = r0; | ||
271 | register long ret asm("r0"); | ||
272 | long oldcpsr = *cpsr; | ||
273 | long newcpsr; | ||
274 | |||
275 | __asm__ __volatile__ ( | ||
276 | "msr cpsr_fs, %[oldcpsr] \n\t" | ||
277 | "mov lr, pc \n\t" | ||
278 | "mov pc, %[fn] \n\t" | ||
279 | "mrs %[newcpsr], cpsr \n\t" | ||
280 | : "=r" (ret), [newcpsr] "=r" (newcpsr) | ||
281 | : "0" (rr0), [oldcpsr] "r" (oldcpsr), [fn] "r" (fn) | ||
282 | : "lr", "cc" | ||
283 | ); | ||
284 | *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs); | ||
285 | return ret; | ||
286 | } | ||
287 | |||
288 | static inline long __kprobes | ||
289 | insnslot_2arg_rwflags(long r0, long r1, long *cpsr, insn_2arg_fn_t *fn) | ||
290 | { | ||
291 | register long rr0 asm("r0") = r0; | ||
292 | register long rr1 asm("r1") = r1; | ||
293 | register long ret asm("r0"); | ||
294 | long oldcpsr = *cpsr; | ||
295 | long newcpsr; | ||
296 | |||
297 | __asm__ __volatile__ ( | ||
298 | "msr cpsr_fs, %[oldcpsr] \n\t" | ||
299 | "mov lr, pc \n\t" | ||
300 | "mov pc, %[fn] \n\t" | ||
301 | "mrs %[newcpsr], cpsr \n\t" | ||
302 | : "=r" (ret), [newcpsr] "=r" (newcpsr) | ||
303 | : "0" (rr0), "r" (rr1), [oldcpsr] "r" (oldcpsr), [fn] "r" (fn) | ||
304 | : "lr", "cc" | ||
305 | ); | ||
306 | *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs); | ||
307 | return ret; | ||
308 | } | ||
309 | |||
310 | static inline long __kprobes | ||
311 | insnslot_3arg_rwflags(long r0, long r1, long r2, long *cpsr, | ||
312 | insn_3arg_fn_t *fn) | ||
313 | { | ||
314 | register long rr0 asm("r0") = r0; | ||
315 | register long rr1 asm("r1") = r1; | ||
316 | register long rr2 asm("r2") = r2; | ||
317 | register long ret asm("r0"); | ||
318 | long oldcpsr = *cpsr; | ||
319 | long newcpsr; | ||
320 | |||
321 | __asm__ __volatile__ ( | ||
322 | "msr cpsr_fs, %[oldcpsr] \n\t" | ||
323 | "mov lr, pc \n\t" | ||
324 | "mov pc, %[fn] \n\t" | ||
325 | "mrs %[newcpsr], cpsr \n\t" | ||
326 | : "=r" (ret), [newcpsr] "=r" (newcpsr) | ||
327 | : "0" (rr0), "r" (rr1), "r" (rr2), | ||
328 | [oldcpsr] "r" (oldcpsr), [fn] "r" (fn) | ||
329 | : "lr", "cc" | ||
330 | ); | ||
331 | *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs); | ||
332 | return ret; | ||
333 | } | ||
334 | |||
335 | static inline long __kprobes | ||
336 | insnslot_4arg_rwflags(long r0, long r1, long r2, long r3, long *cpsr, | ||
337 | insn_4arg_fn_t *fn) | ||
338 | { | ||
339 | register long rr0 asm("r0") = r0; | ||
340 | register long rr1 asm("r1") = r1; | ||
341 | register long rr2 asm("r2") = r2; | ||
342 | register long rr3 asm("r3") = r3; | ||
343 | register long ret asm("r0"); | ||
344 | long oldcpsr = *cpsr; | ||
345 | long newcpsr; | ||
346 | |||
347 | __asm__ __volatile__ ( | ||
348 | "msr cpsr_fs, %[oldcpsr] \n\t" | ||
349 | "mov lr, pc \n\t" | ||
350 | "mov pc, %[fn] \n\t" | ||
351 | "mrs %[newcpsr], cpsr \n\t" | ||
352 | : "=r" (ret), [newcpsr] "=r" (newcpsr) | ||
353 | : "0" (rr0), "r" (rr1), "r" (rr2), "r" (rr3), | ||
354 | [oldcpsr] "r" (oldcpsr), [fn] "r" (fn) | ||
355 | : "lr", "cc" | ||
356 | ); | ||
357 | *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs); | ||
358 | return ret; | ||
359 | } | ||
360 | |||
361 | static inline long long __kprobes | ||
362 | insnslot_llret_4arg_rwflags(long r0, long r1, long r2, long r3, long *cpsr, | ||
363 | insn_llret_4arg_fn_t *fn) | ||
364 | { | ||
365 | register long rr0 asm("r0") = r0; | ||
366 | register long rr1 asm("r1") = r1; | ||
367 | register long rr2 asm("r2") = r2; | ||
368 | register long rr3 asm("r3") = r3; | ||
369 | register long ret0 asm("r0"); | ||
370 | register long ret1 asm("r1"); | ||
371 | long oldcpsr = *cpsr; | ||
372 | long newcpsr; | ||
373 | union reg_pair fnr; | ||
374 | |||
375 | __asm__ __volatile__ ( | ||
376 | "msr cpsr_fs, %[oldcpsr] \n\t" | ||
377 | "mov lr, pc \n\t" | ||
378 | "mov pc, %[fn] \n\t" | ||
379 | "mrs %[newcpsr], cpsr \n\t" | ||
380 | : "=r" (ret0), "=r" (ret1), [newcpsr] "=r" (newcpsr) | ||
381 | : "0" (rr0), "r" (rr1), "r" (rr2), "r" (rr3), | ||
382 | [oldcpsr] "r" (oldcpsr), [fn] "r" (fn) | ||
383 | : "lr", "cc" | ||
384 | ); | ||
385 | *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs); | ||
386 | fnr.r0 = ret0; | ||
387 | fnr.r1 = ret1; | ||
388 | return fnr.dr; | ||
389 | } | ||
390 | |||
391 | /* | ||
392 | * To avoid the complications of mimicing single-stepping on a | ||
393 | * processor without a Next-PC or a single-step mode, and to | ||
394 | * avoid having to deal with the side-effects of boosting, we | ||
395 | * simulate or emulate (almost) all ARM instructions. | ||
396 | * | ||
397 | * "Simulation" is where the instruction's behavior is duplicated in | ||
398 | * C code. "Emulation" is where the original instruction is rewritten | ||
399 | * and executed, often by altering its registers. | ||
400 | * | ||
401 | * By having all behavior of the kprobe'd instruction completed before | ||
402 | * returning from the kprobe_handler(), all locks (scheduler and | ||
403 | * interrupt) can safely be released. There is no need for secondary | ||
404 | * breakpoints, no race with MP or preemptable kernels, nor having to | ||
405 | * clean up resources counts at a later time impacting overall system | ||
406 | * performance. By rewriting the instruction, only the minimum registers | ||
407 | * need to be loaded and saved back optimizing performance. | ||
408 | * | ||
409 | * Calling the insnslot_*_rwflags version of a function doesn't hurt | ||
410 | * anything even when the CPSR flags aren't updated by the | ||
411 | * instruction. It's just a little slower in return for saving | ||
412 | * a little space by not having a duplicate function that doesn't | ||
413 | * update the flags. (The same optimization can be said for | ||
414 | * instructions that do or don't perform register writeback) | ||
415 | * Also, instructions can either read the flags, only write the | ||
416 | * flags, or read and write the flags. To save combinations | ||
417 | * rather than for sheer performance, flag functions just assume | ||
418 | * read and write of flags. | ||
419 | */ | ||
420 | |||
421 | static void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs) | ||
422 | { | ||
423 | kprobe_opcode_t insn = p->opcode; | ||
424 | long iaddr = (long)p->addr; | ||
425 | int disp = branch_displacement(insn); | ||
426 | |||
427 | if (insn & (1 << 24)) | ||
428 | regs->ARM_lr = iaddr + 4; | ||
429 | |||
430 | regs->ARM_pc = iaddr + 8 + disp; | ||
431 | } | ||
432 | |||
433 | static void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs) | ||
434 | { | ||
435 | kprobe_opcode_t insn = p->opcode; | ||
436 | long iaddr = (long)p->addr; | ||
437 | int disp = branch_displacement(insn); | ||
438 | |||
439 | regs->ARM_lr = iaddr + 4; | ||
440 | regs->ARM_pc = iaddr + 8 + disp + ((insn >> 23) & 0x2); | ||
441 | regs->ARM_cpsr |= PSR_T_BIT; | ||
442 | } | ||
443 | |||
444 | static void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs) | ||
445 | { | ||
446 | kprobe_opcode_t insn = p->opcode; | ||
447 | int rm = insn & 0xf; | ||
448 | long rmv = regs->uregs[rm]; | ||
449 | |||
450 | if (insn & (1 << 5)) | ||
451 | regs->ARM_lr = (long)p->addr + 4; | ||
452 | |||
453 | regs->ARM_pc = rmv & ~0x1; | ||
454 | regs->ARM_cpsr &= ~PSR_T_BIT; | ||
455 | if (rmv & 0x1) | ||
456 | regs->ARM_cpsr |= PSR_T_BIT; | ||
457 | } | ||
458 | |||
459 | static void __kprobes simulate_mrs(struct kprobe *p, struct pt_regs *regs) | ||
460 | { | ||
461 | kprobe_opcode_t insn = p->opcode; | ||
462 | int rd = (insn >> 12) & 0xf; | ||
463 | unsigned long mask = 0xf8ff03df; /* Mask out execution state */ | ||
464 | regs->uregs[rd] = regs->ARM_cpsr & mask; | ||
465 | } | ||
466 | |||
467 | static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs) | ||
468 | { | ||
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 | reg_count = 0; | ||
480 | reg_bit_vector = insn & 0xffff; | ||
481 | while (reg_bit_vector) { | ||
482 | reg_bit_vector &= (reg_bit_vector - 1); | ||
483 | ++reg_count; | ||
484 | } | ||
485 | |||
486 | if (!ubit) | ||
487 | addr -= reg_count; | ||
488 | addr += (!pbit == !ubit); | ||
489 | |||
490 | reg_bit_vector = insn & 0xffff; | ||
491 | while (reg_bit_vector) { | ||
492 | int reg = __ffs(reg_bit_vector); | ||
493 | reg_bit_vector &= (reg_bit_vector - 1); | ||
494 | if (lbit) | ||
495 | regs->uregs[reg] = *addr++; | ||
496 | else | ||
497 | *addr++ = regs->uregs[reg]; | ||
498 | } | ||
499 | |||
500 | if (wbit) { | ||
501 | if (!ubit) | ||
502 | addr -= reg_count; | ||
503 | addr -= (!pbit == !ubit); | ||
504 | regs->uregs[rn] = (long)addr; | ||
505 | } | ||
506 | } | ||
507 | |||
508 | static void __kprobes simulate_stm1_pc(struct kprobe *p, struct pt_regs *regs) | ||
509 | { | ||
510 | regs->ARM_pc = (long)p->addr + str_pc_offset; | ||
511 | simulate_ldm1stm1(p, regs); | ||
512 | regs->ARM_pc = (long)p->addr + 4; | ||
513 | } | ||
514 | |||
515 | static void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs) | ||
516 | { | ||
517 | regs->uregs[12] = regs->uregs[13]; | ||
518 | } | ||
519 | |||
520 | static void __kprobes emulate_ldrd(struct kprobe *p, struct pt_regs *regs) | ||
521 | { | ||
522 | insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; | ||
523 | kprobe_opcode_t insn = p->opcode; | ||
524 | long ppc = (long)p->addr + 8; | ||
525 | int rd = (insn >> 12) & 0xf; | ||
526 | int rn = (insn >> 16) & 0xf; | ||
527 | int rm = insn & 0xf; /* rm may be invalid, don't care. */ | ||
528 | long rmv = (rm == 15) ? ppc : regs->uregs[rm]; | ||
529 | long rnv = (rn == 15) ? ppc : regs->uregs[rn]; | ||
530 | |||
531 | /* Not following the C calling convention here, so need asm(). */ | ||
532 | __asm__ __volatile__ ( | ||
533 | "ldr r0, %[rn] \n\t" | ||
534 | "ldr r1, %[rm] \n\t" | ||
535 | "msr cpsr_fs, %[cpsr]\n\t" | ||
536 | "mov lr, pc \n\t" | ||
537 | "mov pc, %[i_fn] \n\t" | ||
538 | "str r0, %[rn] \n\t" /* in case of writeback */ | ||
539 | "str r2, %[rd0] \n\t" | ||
540 | "str r3, %[rd1] \n\t" | ||
541 | : [rn] "+m" (rnv), | ||
542 | [rd0] "=m" (regs->uregs[rd]), | ||
543 | [rd1] "=m" (regs->uregs[rd+1]) | ||
544 | : [rm] "m" (rmv), | ||
545 | [cpsr] "r" (regs->ARM_cpsr), | ||
546 | [i_fn] "r" (i_fn) | ||
547 | : "r0", "r1", "r2", "r3", "lr", "cc" | ||
548 | ); | ||
549 | if (is_writeback(insn)) | ||
550 | regs->uregs[rn] = rnv; | ||
551 | } | ||
552 | |||
553 | static void __kprobes emulate_strd(struct kprobe *p, struct pt_regs *regs) | ||
554 | { | ||
555 | insn_4arg_fn_t *i_fn = (insn_4arg_fn_t *)&p->ainsn.insn[0]; | ||
556 | kprobe_opcode_t insn = p->opcode; | ||
557 | long ppc = (long)p->addr + 8; | ||
558 | int rd = (insn >> 12) & 0xf; | ||
559 | int rn = (insn >> 16) & 0xf; | ||
560 | int rm = insn & 0xf; | ||
561 | long rnv = (rn == 15) ? ppc : regs->uregs[rn]; | ||
562 | /* rm/rmv may be invalid, don't care. */ | ||
563 | long rmv = (rm == 15) ? ppc : regs->uregs[rm]; | ||
564 | long rnv_wb; | ||
565 | |||
566 | rnv_wb = insnslot_4arg_rflags(rnv, rmv, regs->uregs[rd], | ||
567 | regs->uregs[rd+1], | ||
568 | regs->ARM_cpsr, i_fn); | ||
569 | if (is_writeback(insn)) | ||
570 | regs->uregs[rn] = rnv_wb; | ||
571 | } | ||
572 | |||
573 | static void __kprobes emulate_ldr(struct kprobe *p, struct pt_regs *regs) | ||
574 | { | ||
575 | insn_llret_3arg_fn_t *i_fn = (insn_llret_3arg_fn_t *)&p->ainsn.insn[0]; | ||
576 | kprobe_opcode_t insn = p->opcode; | ||
577 | long ppc = (long)p->addr + 8; | ||
578 | union reg_pair fnr; | ||
579 | int rd = (insn >> 12) & 0xf; | ||
580 | int rn = (insn >> 16) & 0xf; | ||
581 | int rm = insn & 0xf; | ||
582 | long rdv; | ||
583 | long rnv = (rn == 15) ? ppc : regs->uregs[rn]; | ||
584 | long rmv = (rm == 15) ? ppc : regs->uregs[rm]; | ||
585 | long cpsr = regs->ARM_cpsr; | ||
586 | |||
587 | fnr.dr = insnslot_llret_3arg_rflags(rnv, 0, rmv, cpsr, i_fn); | ||
588 | if (rn != 15) | ||
589 | regs->uregs[rn] = fnr.r0; /* Save Rn in case of writeback. */ | ||
590 | rdv = fnr.r1; | ||
591 | |||
592 | if (rd == 15) { | ||
593 | #if __LINUX_ARM_ARCH__ >= 5 | ||
594 | cpsr &= ~PSR_T_BIT; | ||
595 | if (rdv & 0x1) | ||
596 | cpsr |= PSR_T_BIT; | ||
597 | regs->ARM_cpsr = cpsr; | ||
598 | rdv &= ~0x1; | ||
599 | #else | ||
600 | rdv &= ~0x2; | ||
601 | #endif | ||
602 | } | ||
603 | regs->uregs[rd] = rdv; | ||
604 | } | ||
605 | |||
606 | static void __kprobes emulate_str(struct kprobe *p, struct pt_regs *regs) | ||
607 | { | ||
608 | insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; | ||
609 | kprobe_opcode_t insn = p->opcode; | ||
610 | long iaddr = (long)p->addr; | ||
611 | int rd = (insn >> 12) & 0xf; | ||
612 | int rn = (insn >> 16) & 0xf; | ||
613 | int rm = insn & 0xf; | ||
614 | long rdv = (rd == 15) ? iaddr + str_pc_offset : regs->uregs[rd]; | ||
615 | long rnv = (rn == 15) ? iaddr + 8 : regs->uregs[rn]; | ||
616 | long rmv = regs->uregs[rm]; /* rm/rmv may be invalid, don't care. */ | ||
617 | long rnv_wb; | ||
618 | |||
619 | rnv_wb = insnslot_3arg_rflags(rnv, rdv, rmv, regs->ARM_cpsr, i_fn); | ||
620 | if (rn != 15) | ||
621 | regs->uregs[rn] = rnv_wb; /* Save Rn in case of writeback. */ | ||
622 | } | ||
623 | |||
624 | static void __kprobes emulate_sat(struct kprobe *p, struct pt_regs *regs) | ||
625 | { | ||
626 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
627 | kprobe_opcode_t insn = p->opcode; | ||
628 | int rd = (insn >> 12) & 0xf; | ||
629 | int rm = insn & 0xf; | ||
630 | long rmv = regs->uregs[rm]; | ||
631 | |||
632 | /* Writes Q flag */ | ||
633 | regs->uregs[rd] = insnslot_1arg_rwflags(rmv, ®s->ARM_cpsr, i_fn); | ||
634 | } | ||
635 | |||
636 | static void __kprobes emulate_sel(struct kprobe *p, struct pt_regs *regs) | ||
637 | { | ||
638 | insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; | ||
639 | kprobe_opcode_t insn = p->opcode; | ||
640 | int rd = (insn >> 12) & 0xf; | ||
641 | int rn = (insn >> 16) & 0xf; | ||
642 | int rm = insn & 0xf; | ||
643 | long rnv = regs->uregs[rn]; | ||
644 | long rmv = regs->uregs[rm]; | ||
645 | |||
646 | /* Reads GE bits */ | ||
647 | regs->uregs[rd] = insnslot_2arg_rflags(rnv, rmv, regs->ARM_cpsr, i_fn); | ||
648 | } | ||
649 | |||
650 | static void __kprobes emulate_none(struct kprobe *p, struct pt_regs *regs) | ||
651 | { | ||
652 | insn_0arg_fn_t *i_fn = (insn_0arg_fn_t *)&p->ainsn.insn[0]; | ||
653 | |||
654 | insnslot_0arg_rflags(regs->ARM_cpsr, i_fn); | ||
655 | } | ||
656 | |||
657 | static void __kprobes emulate_nop(struct kprobe *p, struct pt_regs *regs) | ||
658 | { | ||
659 | } | ||
660 | |||
661 | static void __kprobes | ||
662 | emulate_rd12_modify(struct kprobe *p, struct pt_regs *regs) | ||
663 | { | ||
664 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
665 | kprobe_opcode_t insn = p->opcode; | ||
666 | int rd = (insn >> 12) & 0xf; | ||
667 | long rdv = regs->uregs[rd]; | ||
668 | |||
669 | regs->uregs[rd] = insnslot_1arg_rflags(rdv, regs->ARM_cpsr, i_fn); | ||
670 | } | ||
671 | |||
672 | static void __kprobes | ||
673 | emulate_rd12rn0_modify(struct kprobe *p, struct pt_regs *regs) | ||
674 | { | ||
675 | insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; | ||
676 | kprobe_opcode_t insn = p->opcode; | ||
677 | int rd = (insn >> 12) & 0xf; | ||
678 | int rn = insn & 0xf; | ||
679 | long rdv = regs->uregs[rd]; | ||
680 | long rnv = regs->uregs[rn]; | ||
681 | |||
682 | regs->uregs[rd] = insnslot_2arg_rflags(rdv, rnv, regs->ARM_cpsr, i_fn); | ||
683 | } | ||
684 | |||
685 | static void __kprobes emulate_rd12rm0(struct kprobe *p, struct pt_regs *regs) | ||
686 | { | ||
687 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
688 | kprobe_opcode_t insn = p->opcode; | ||
689 | int rd = (insn >> 12) & 0xf; | ||
690 | int rm = insn & 0xf; | ||
691 | long rmv = regs->uregs[rm]; | ||
692 | |||
693 | regs->uregs[rd] = insnslot_1arg_rflags(rmv, regs->ARM_cpsr, i_fn); | ||
694 | } | ||
695 | |||
696 | static void __kprobes | ||
697 | emulate_rd12rn16rm0_rwflags(struct kprobe *p, struct pt_regs *regs) | ||
698 | { | ||
699 | insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; | ||
700 | kprobe_opcode_t insn = p->opcode; | ||
701 | int rd = (insn >> 12) & 0xf; | ||
702 | int rn = (insn >> 16) & 0xf; | ||
703 | int rm = insn & 0xf; | ||
704 | long rnv = regs->uregs[rn]; | ||
705 | long rmv = regs->uregs[rm]; | ||
706 | |||
707 | regs->uregs[rd] = | ||
708 | insnslot_2arg_rwflags(rnv, rmv, ®s->ARM_cpsr, i_fn); | ||
709 | } | ||
710 | |||
711 | static void __kprobes | ||
712 | emulate_rd16rn12rs8rm0_rwflags(struct kprobe *p, struct pt_regs *regs) | ||
713 | { | ||
714 | insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; | ||
715 | kprobe_opcode_t insn = p->opcode; | ||
716 | int rd = (insn >> 16) & 0xf; | ||
717 | int rn = (insn >> 12) & 0xf; | ||
718 | int rs = (insn >> 8) & 0xf; | ||
719 | int rm = insn & 0xf; | ||
720 | long rnv = regs->uregs[rn]; | ||
721 | long rsv = regs->uregs[rs]; | ||
722 | long rmv = regs->uregs[rm]; | ||
723 | |||
724 | regs->uregs[rd] = | ||
725 | insnslot_3arg_rwflags(rnv, rsv, rmv, ®s->ARM_cpsr, i_fn); | ||
726 | } | ||
727 | |||
728 | static void __kprobes | ||
729 | emulate_rd16rs8rm0_rwflags(struct kprobe *p, struct pt_regs *regs) | ||
730 | { | ||
731 | insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; | ||
732 | kprobe_opcode_t insn = p->opcode; | ||
733 | int rd = (insn >> 16) & 0xf; | ||
734 | int rs = (insn >> 8) & 0xf; | ||
735 | int rm = insn & 0xf; | ||
736 | long rsv = regs->uregs[rs]; | ||
737 | long rmv = regs->uregs[rm]; | ||
738 | |||
739 | regs->uregs[rd] = | ||
740 | insnslot_2arg_rwflags(rsv, rmv, ®s->ARM_cpsr, i_fn); | ||
741 | } | ||
742 | |||
743 | static void __kprobes | ||
744 | emulate_rdhi16rdlo12rs8rm0_rwflags(struct kprobe *p, struct pt_regs *regs) | ||
745 | { | ||
746 | insn_llret_4arg_fn_t *i_fn = (insn_llret_4arg_fn_t *)&p->ainsn.insn[0]; | ||
747 | kprobe_opcode_t insn = p->opcode; | ||
748 | union reg_pair fnr; | ||
749 | int rdhi = (insn >> 16) & 0xf; | ||
750 | int rdlo = (insn >> 12) & 0xf; | ||
751 | int rs = (insn >> 8) & 0xf; | ||
752 | int rm = insn & 0xf; | ||
753 | long rsv = regs->uregs[rs]; | ||
754 | long rmv = regs->uregs[rm]; | ||
755 | |||
756 | fnr.dr = insnslot_llret_4arg_rwflags(regs->uregs[rdhi], | ||
757 | regs->uregs[rdlo], rsv, rmv, | ||
758 | ®s->ARM_cpsr, i_fn); | ||
759 | regs->uregs[rdhi] = fnr.r0; | ||
760 | regs->uregs[rdlo] = fnr.r1; | ||
761 | } | ||
762 | |||
763 | static void __kprobes | ||
764 | emulate_alu_imm_rflags(struct kprobe *p, struct pt_regs *regs) | ||
765 | { | ||
766 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
767 | kprobe_opcode_t insn = p->opcode; | ||
768 | int rd = (insn >> 12) & 0xf; | ||
769 | int rn = (insn >> 16) & 0xf; | ||
770 | long rnv = (rn == 15) ? (long)p->addr + 8 : regs->uregs[rn]; | ||
771 | |||
772 | regs->uregs[rd] = insnslot_1arg_rflags(rnv, regs->ARM_cpsr, i_fn); | ||
773 | } | ||
774 | |||
775 | static void __kprobes | ||
776 | emulate_alu_imm_rwflags(struct kprobe *p, struct pt_regs *regs) | ||
777 | { | ||
778 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
779 | kprobe_opcode_t insn = p->opcode; | ||
780 | int rd = (insn >> 12) & 0xf; | ||
781 | int rn = (insn >> 16) & 0xf; | ||
782 | long rnv = (rn == 15) ? (long)p->addr + 8 : regs->uregs[rn]; | ||
783 | |||
784 | regs->uregs[rd] = insnslot_1arg_rwflags(rnv, ®s->ARM_cpsr, i_fn); | ||
785 | } | ||
786 | |||
787 | static void __kprobes | ||
788 | emulate_alu_tests_imm(struct kprobe *p, struct pt_regs *regs) | ||
789 | { | ||
790 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
791 | kprobe_opcode_t insn = p->opcode; | ||
792 | int rn = (insn >> 16) & 0xf; | ||
793 | long rnv = (rn == 15) ? (long)p->addr + 8 : regs->uregs[rn]; | ||
794 | |||
795 | insnslot_1arg_rwflags(rnv, ®s->ARM_cpsr, i_fn); | ||
796 | } | ||
797 | |||
798 | static void __kprobes | ||
799 | emulate_alu_rflags(struct kprobe *p, struct pt_regs *regs) | ||
800 | { | ||
801 | insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; | ||
802 | kprobe_opcode_t insn = p->opcode; | ||
803 | long ppc = (long)p->addr + 8; | ||
804 | int rd = (insn >> 12) & 0xf; | ||
805 | int rn = (insn >> 16) & 0xf; /* rn/rnv/rs/rsv may be */ | ||
806 | int rs = (insn >> 8) & 0xf; /* invalid, don't care. */ | ||
807 | int rm = insn & 0xf; | ||
808 | long rnv = (rn == 15) ? ppc : regs->uregs[rn]; | ||
809 | long rmv = (rm == 15) ? ppc : regs->uregs[rm]; | ||
810 | long rsv = regs->uregs[rs]; | ||
811 | |||
812 | regs->uregs[rd] = | ||
813 | insnslot_3arg_rflags(rnv, rmv, rsv, regs->ARM_cpsr, i_fn); | ||
814 | } | ||
815 | |||
816 | static void __kprobes | ||
817 | emulate_alu_rwflags(struct kprobe *p, struct pt_regs *regs) | ||
818 | { | ||
819 | insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; | ||
820 | kprobe_opcode_t insn = p->opcode; | ||
821 | long ppc = (long)p->addr + 8; | ||
822 | int rd = (insn >> 12) & 0xf; | ||
823 | int rn = (insn >> 16) & 0xf; /* rn/rnv/rs/rsv may be */ | ||
824 | int rs = (insn >> 8) & 0xf; /* invalid, don't care. */ | ||
825 | int rm = insn & 0xf; | ||
826 | long rnv = (rn == 15) ? ppc : regs->uregs[rn]; | ||
827 | long rmv = (rm == 15) ? ppc : regs->uregs[rm]; | ||
828 | long rsv = regs->uregs[rs]; | ||
829 | |||
830 | regs->uregs[rd] = | ||
831 | insnslot_3arg_rwflags(rnv, rmv, rsv, ®s->ARM_cpsr, i_fn); | ||
832 | } | ||
833 | |||
834 | static void __kprobes | ||
835 | emulate_alu_tests(struct kprobe *p, struct pt_regs *regs) | ||
836 | { | ||
837 | insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; | ||
838 | kprobe_opcode_t insn = p->opcode; | ||
839 | long ppc = (long)p->addr + 8; | ||
840 | int rn = (insn >> 16) & 0xf; | ||
841 | int rs = (insn >> 8) & 0xf; /* rs/rsv may be invalid, don't care. */ | ||
842 | int rm = insn & 0xf; | ||
843 | long rnv = (rn == 15) ? ppc : regs->uregs[rn]; | ||
844 | long rmv = (rm == 15) ? ppc : regs->uregs[rm]; | ||
845 | long rsv = regs->uregs[rs]; | ||
846 | |||
847 | insnslot_3arg_rwflags(rnv, rmv, rsv, ®s->ARM_cpsr, i_fn); | ||
848 | } | ||
849 | |||
850 | static enum kprobe_insn __kprobes | ||
851 | prep_emulate_ldr_str(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
852 | { | ||
853 | int not_imm = (insn & (1 << 26)) ? (insn & (1 << 25)) | ||
854 | : (~insn & (1 << 22)); | ||
855 | |||
856 | if (is_writeback(insn) && is_r15(insn, 16)) | ||
857 | return INSN_REJECTED; /* Writeback to PC */ | ||
858 | |||
859 | insn &= 0xfff00fff; | ||
860 | insn |= 0x00001000; /* Rn = r0, Rd = r1 */ | ||
861 | if (not_imm) { | ||
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_rd12_modify(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
872 | { | ||
873 | if (is_r15(insn, 12)) | ||
874 | return INSN_REJECTED; /* Rd is PC */ | ||
875 | |||
876 | insn &= 0xffff0fff; /* Rd = r0 */ | ||
877 | asi->insn[0] = insn; | ||
878 | asi->insn_handler = emulate_rd12_modify; | ||
879 | return INSN_GOOD; | ||
880 | } | ||
881 | |||
882 | static enum kprobe_insn __kprobes | ||
883 | prep_emulate_rd12rn0_modify(kprobe_opcode_t insn, | ||
884 | struct arch_specific_insn *asi) | ||
885 | { | ||
886 | if (is_r15(insn, 12)) | ||
887 | return INSN_REJECTED; /* Rd is PC */ | ||
888 | |||
889 | insn &= 0xffff0ff0; /* Rd = r0 */ | ||
890 | insn |= 0x00000001; /* Rn = r1 */ | ||
891 | asi->insn[0] = insn; | ||
892 | asi->insn_handler = emulate_rd12rn0_modify; | ||
893 | return INSN_GOOD; | ||
894 | } | ||
895 | |||
896 | static enum kprobe_insn __kprobes | ||
897 | prep_emulate_rd12rm0(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
898 | { | ||
899 | if (is_r15(insn, 12)) | ||
900 | return INSN_REJECTED; /* Rd is PC */ | ||
901 | |||
902 | insn &= 0xffff0ff0; /* Rd = r0, Rm = r0 */ | ||
903 | asi->insn[0] = insn; | ||
904 | asi->insn_handler = emulate_rd12rm0; | ||
905 | return INSN_GOOD; | ||
906 | } | ||
907 | |||
908 | static enum kprobe_insn __kprobes | ||
909 | prep_emulate_rd12rn16rm0_wflags(kprobe_opcode_t insn, | ||
910 | struct arch_specific_insn *asi) | ||
911 | { | ||
912 | if (is_r15(insn, 12)) | ||
913 | return INSN_REJECTED; /* Rd is PC */ | ||
914 | |||
915 | insn &= 0xfff00ff0; /* Rd = r0, Rn = r0 */ | ||
916 | insn |= 0x00000001; /* Rm = r1 */ | ||
917 | asi->insn[0] = insn; | ||
918 | asi->insn_handler = emulate_rd12rn16rm0_rwflags; | ||
919 | return INSN_GOOD; | ||
920 | } | ||
921 | |||
922 | static enum kprobe_insn __kprobes | ||
923 | prep_emulate_rd16rs8rm0_wflags(kprobe_opcode_t insn, | ||
924 | struct arch_specific_insn *asi) | ||
925 | { | ||
926 | if (is_r15(insn, 16)) | ||
927 | return INSN_REJECTED; /* Rd is PC */ | ||
928 | |||
929 | insn &= 0xfff0f0f0; /* Rd = r0, Rs = r0 */ | ||
930 | insn |= 0x00000001; /* Rm = r1 */ | ||
931 | asi->insn[0] = insn; | ||
932 | asi->insn_handler = emulate_rd16rs8rm0_rwflags; | ||
933 | return INSN_GOOD; | ||
934 | } | ||
935 | |||
936 | static enum kprobe_insn __kprobes | ||
937 | prep_emulate_rd16rn12rs8rm0_wflags(kprobe_opcode_t insn, | ||
938 | struct arch_specific_insn *asi) | ||
939 | { | ||
940 | if (is_r15(insn, 16)) | ||
941 | return INSN_REJECTED; /* Rd is PC */ | ||
942 | |||
943 | insn &= 0xfff000f0; /* Rd = r0, Rn = r0 */ | ||
944 | insn |= 0x00000102; /* Rs = r1, Rm = r2 */ | ||
945 | asi->insn[0] = insn; | ||
946 | asi->insn_handler = emulate_rd16rn12rs8rm0_rwflags; | ||
947 | return INSN_GOOD; | ||
948 | } | ||
949 | |||
950 | static enum kprobe_insn __kprobes | ||
951 | prep_emulate_rdhi16rdlo12rs8rm0_wflags(kprobe_opcode_t insn, | ||
952 | struct arch_specific_insn *asi) | ||
953 | { | ||
954 | if (is_r15(insn, 16) || is_r15(insn, 12)) | ||
955 | return INSN_REJECTED; /* RdHi or RdLo is PC */ | ||
956 | |||
957 | insn &= 0xfff000f0; /* RdHi = r0, RdLo = r1 */ | ||
958 | insn |= 0x00001203; /* Rs = r2, Rm = r3 */ | ||
959 | asi->insn[0] = insn; | ||
960 | asi->insn_handler = emulate_rdhi16rdlo12rs8rm0_rwflags; | ||
961 | return INSN_GOOD; | ||
962 | } | ||
963 | |||
964 | /* | ||
965 | * For the instruction masking and comparisons in all the "space_*" | ||
966 | * functions below, Do _not_ rearrange the order of tests unless | ||
967 | * you're very, very sure of what you are doing. For the sake of | ||
968 | * efficiency, the masks for some tests sometimes assume other test | ||
969 | * have been done prior to them so the number of patterns to test | ||
970 | * for an instruction set can be as broad as possible to reduce the | ||
971 | * number of tests needed. | ||
972 | */ | ||
973 | |||
974 | static enum kprobe_insn __kprobes | ||
975 | space_1111(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
976 | { | ||
977 | /* memory hint : 1111 0100 x001 xxxx xxxx xxxx xxxx xxxx : */ | ||
978 | /* PLDI : 1111 0100 x101 xxxx xxxx xxxx xxxx xxxx : */ | ||
979 | /* PLDW : 1111 0101 x001 xxxx xxxx xxxx xxxx xxxx : */ | ||
980 | /* PLD : 1111 0101 x101 xxxx xxxx xxxx xxxx xxxx : */ | ||
981 | if ((insn & 0xfe300000) == 0xf4100000) { | ||
982 | asi->insn_handler = emulate_nop; | ||
983 | return INSN_GOOD_NO_SLOT; | ||
984 | } | ||
985 | |||
986 | /* BLX(1) : 1111 101x xxxx xxxx xxxx xxxx xxxx xxxx : */ | ||
987 | if ((insn & 0xfe000000) == 0xfa000000) { | ||
988 | asi->insn_handler = simulate_blx1; | ||
989 | return INSN_GOOD_NO_SLOT; | ||
990 | } | ||
991 | |||
992 | /* CPS : 1111 0001 0000 xxx0 xxxx xxxx xx0x xxxx */ | ||
993 | /* SETEND: 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */ | ||
994 | |||
995 | /* SRS : 1111 100x x1x0 xxxx xxxx xxxx xxxx xxxx */ | ||
996 | /* RFE : 1111 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ | ||
997 | |||
998 | /* Coprocessor instructions... */ | ||
999 | /* MCRR2 : 1111 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */ | ||
1000 | /* MRRC2 : 1111 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */ | ||
1001 | /* LDC2 : 1111 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ | ||
1002 | /* STC2 : 1111 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ | ||
1003 | /* CDP2 : 1111 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ | ||
1004 | /* MCR2 : 1111 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ | ||
1005 | /* MRC2 : 1111 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ | ||
1006 | |||
1007 | return INSN_REJECTED; | ||
1008 | } | ||
1009 | |||
1010 | static enum kprobe_insn __kprobes | ||
1011 | space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1012 | { | ||
1013 | /* cccc 0001 0xx0 xxxx xxxx xxxx xxxx xxx0 xxxx */ | ||
1014 | if ((insn & 0x0f900010) == 0x01000000) { | ||
1015 | |||
1016 | /* MRS cpsr : cccc 0001 0000 xxxx xxxx xxxx 0000 xxxx */ | ||
1017 | if ((insn & 0x0ff000f0) == 0x01000000) { | ||
1018 | if (is_r15(insn, 12)) | ||
1019 | return INSN_REJECTED; /* Rd is PC */ | ||
1020 | asi->insn_handler = simulate_mrs; | ||
1021 | return INSN_GOOD_NO_SLOT; | ||
1022 | } | ||
1023 | |||
1024 | /* SMLALxy : cccc 0001 0100 xxxx xxxx xxxx 1xx0 xxxx */ | ||
1025 | if ((insn & 0x0ff00090) == 0x01400080) | ||
1026 | return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, | ||
1027 | asi); | ||
1028 | |||
1029 | /* SMULWy : cccc 0001 0010 xxxx xxxx xxxx 1x10 xxxx */ | ||
1030 | /* SMULxy : cccc 0001 0110 xxxx xxxx xxxx 1xx0 xxxx */ | ||
1031 | if ((insn & 0x0ff000b0) == 0x012000a0 || | ||
1032 | (insn & 0x0ff00090) == 0x01600080) | ||
1033 | return prep_emulate_rd16rs8rm0_wflags(insn, asi); | ||
1034 | |||
1035 | /* SMLAxy : cccc 0001 0000 xxxx xxxx xxxx 1xx0 xxxx : Q */ | ||
1036 | /* SMLAWy : cccc 0001 0010 xxxx xxxx xxxx 1x00 xxxx : Q */ | ||
1037 | if ((insn & 0x0ff00090) == 0x01000080 || | ||
1038 | (insn & 0x0ff000b0) == 0x01200080) | ||
1039 | return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); | ||
1040 | |||
1041 | /* BXJ : cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */ | ||
1042 | /* MSR : cccc 0001 0x10 xxxx xxxx xxxx 0000 xxxx */ | ||
1043 | /* MRS spsr : cccc 0001 0100 xxxx xxxx xxxx 0000 xxxx */ | ||
1044 | |||
1045 | /* Other instruction encodings aren't yet defined */ | ||
1046 | return INSN_REJECTED; | ||
1047 | } | ||
1048 | |||
1049 | /* cccc 0001 0xx0 xxxx xxxx xxxx xxxx 0xx1 xxxx */ | ||
1050 | else if ((insn & 0x0f900090) == 0x01000010) { | ||
1051 | |||
1052 | /* BLX(2) : cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */ | ||
1053 | /* BX : cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */ | ||
1054 | if ((insn & 0x0ff000d0) == 0x01200010) { | ||
1055 | if ((insn & 0x0ff000ff) == 0x0120003f) | ||
1056 | return INSN_REJECTED; /* BLX pc */ | ||
1057 | asi->insn_handler = simulate_blx2bx; | ||
1058 | return INSN_GOOD_NO_SLOT; | ||
1059 | } | ||
1060 | |||
1061 | /* CLZ : cccc 0001 0110 xxxx xxxx xxxx 0001 xxxx */ | ||
1062 | if ((insn & 0x0ff000f0) == 0x01600010) | ||
1063 | return prep_emulate_rd12rm0(insn, asi); | ||
1064 | |||
1065 | /* QADD : cccc 0001 0000 xxxx xxxx xxxx 0101 xxxx :Q */ | ||
1066 | /* QSUB : cccc 0001 0010 xxxx xxxx xxxx 0101 xxxx :Q */ | ||
1067 | /* QDADD : cccc 0001 0100 xxxx xxxx xxxx 0101 xxxx :Q */ | ||
1068 | /* QDSUB : cccc 0001 0110 xxxx xxxx xxxx 0101 xxxx :Q */ | ||
1069 | if ((insn & 0x0f9000f0) == 0x01000050) | ||
1070 | return prep_emulate_rd12rn16rm0_wflags(insn, asi); | ||
1071 | |||
1072 | /* BKPT : 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */ | ||
1073 | /* SMC : cccc 0001 0110 xxxx xxxx xxxx 0111 xxxx */ | ||
1074 | |||
1075 | /* Other instruction encodings aren't yet defined */ | ||
1076 | return INSN_REJECTED; | ||
1077 | } | ||
1078 | |||
1079 | /* cccc 0000 xxxx xxxx xxxx xxxx xxxx 1001 xxxx */ | ||
1080 | else if ((insn & 0x0f0000f0) == 0x00000090) { | ||
1081 | |||
1082 | /* MUL : cccc 0000 0000 xxxx xxxx xxxx 1001 xxxx : */ | ||
1083 | /* MULS : cccc 0000 0001 xxxx xxxx xxxx 1001 xxxx :cc */ | ||
1084 | /* MLA : cccc 0000 0010 xxxx xxxx xxxx 1001 xxxx : */ | ||
1085 | /* MLAS : cccc 0000 0011 xxxx xxxx xxxx 1001 xxxx :cc */ | ||
1086 | /* UMAAL : cccc 0000 0100 xxxx xxxx xxxx 1001 xxxx : */ | ||
1087 | /* undef : cccc 0000 0101 xxxx xxxx xxxx 1001 xxxx : */ | ||
1088 | /* MLS : cccc 0000 0110 xxxx xxxx xxxx 1001 xxxx : */ | ||
1089 | /* undef : cccc 0000 0111 xxxx xxxx xxxx 1001 xxxx : */ | ||
1090 | /* UMULL : cccc 0000 1000 xxxx xxxx xxxx 1001 xxxx : */ | ||
1091 | /* UMULLS : cccc 0000 1001 xxxx xxxx xxxx 1001 xxxx :cc */ | ||
1092 | /* UMLAL : cccc 0000 1010 xxxx xxxx xxxx 1001 xxxx : */ | ||
1093 | /* UMLALS : cccc 0000 1011 xxxx xxxx xxxx 1001 xxxx :cc */ | ||
1094 | /* SMULL : cccc 0000 1100 xxxx xxxx xxxx 1001 xxxx : */ | ||
1095 | /* SMULLS : cccc 0000 1101 xxxx xxxx xxxx 1001 xxxx :cc */ | ||
1096 | /* SMLAL : cccc 0000 1110 xxxx xxxx xxxx 1001 xxxx : */ | ||
1097 | /* SMLALS : cccc 0000 1111 xxxx xxxx xxxx 1001 xxxx :cc */ | ||
1098 | if ((insn & 0x00d00000) == 0x00500000) | ||
1099 | return INSN_REJECTED; | ||
1100 | else if ((insn & 0x00e00000) == 0x00000000) | ||
1101 | return prep_emulate_rd16rs8rm0_wflags(insn, asi); | ||
1102 | else if ((insn & 0x00a00000) == 0x00200000) | ||
1103 | return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); | ||
1104 | else | ||
1105 | return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, | ||
1106 | asi); | ||
1107 | } | ||
1108 | |||
1109 | /* cccc 000x xxxx xxxx xxxx xxxx xxxx 1xx1 xxxx */ | ||
1110 | else if ((insn & 0x0e000090) == 0x00000090) { | ||
1111 | |||
1112 | /* SWP : cccc 0001 0000 xxxx xxxx xxxx 1001 xxxx */ | ||
1113 | /* SWPB : cccc 0001 0100 xxxx xxxx xxxx 1001 xxxx */ | ||
1114 | /* ??? : cccc 0001 0x01 xxxx xxxx xxxx 1001 xxxx */ | ||
1115 | /* ??? : cccc 0001 0x10 xxxx xxxx xxxx 1001 xxxx */ | ||
1116 | /* ??? : cccc 0001 0x11 xxxx xxxx xxxx 1001 xxxx */ | ||
1117 | /* STREX : cccc 0001 1000 xxxx xxxx xxxx 1001 xxxx */ | ||
1118 | /* LDREX : cccc 0001 1001 xxxx xxxx xxxx 1001 xxxx */ | ||
1119 | /* STREXD: cccc 0001 1010 xxxx xxxx xxxx 1001 xxxx */ | ||
1120 | /* LDREXD: cccc 0001 1011 xxxx xxxx xxxx 1001 xxxx */ | ||
1121 | /* STREXB: cccc 0001 1100 xxxx xxxx xxxx 1001 xxxx */ | ||
1122 | /* LDREXB: cccc 0001 1101 xxxx xxxx xxxx 1001 xxxx */ | ||
1123 | /* STREXH: cccc 0001 1110 xxxx xxxx xxxx 1001 xxxx */ | ||
1124 | /* LDREXH: cccc 0001 1111 xxxx xxxx xxxx 1001 xxxx */ | ||
1125 | |||
1126 | /* LDRD : cccc 000x xxx0 xxxx xxxx xxxx 1101 xxxx */ | ||
1127 | /* STRD : cccc 000x xxx0 xxxx xxxx xxxx 1111 xxxx */ | ||
1128 | /* LDRH : cccc 000x xxx1 xxxx xxxx xxxx 1011 xxxx */ | ||
1129 | /* STRH : cccc 000x xxx0 xxxx xxxx xxxx 1011 xxxx */ | ||
1130 | /* LDRSB : cccc 000x xxx1 xxxx xxxx xxxx 1101 xxxx */ | ||
1131 | /* LDRSH : cccc 000x xxx1 xxxx xxxx xxxx 1111 xxxx */ | ||
1132 | if ((insn & 0x0f0000f0) == 0x01000090) { | ||
1133 | if ((insn & 0x0fb000f0) == 0x01000090) { | ||
1134 | /* SWP/SWPB */ | ||
1135 | return prep_emulate_rd12rn16rm0_wflags(insn, | ||
1136 | asi); | ||
1137 | } else { | ||
1138 | /* STREX/LDREX variants and unallocaed space */ | ||
1139 | return INSN_REJECTED; | ||
1140 | } | ||
1141 | |||
1142 | } else if ((insn & 0x0e1000d0) == 0x00000d0) { | ||
1143 | /* STRD/LDRD */ | ||
1144 | if ((insn & 0x0000e000) == 0x0000e000) | ||
1145 | return INSN_REJECTED; /* Rd is LR or PC */ | ||
1146 | if (is_writeback(insn) && is_r15(insn, 16)) | ||
1147 | return INSN_REJECTED; /* Writeback to PC */ | ||
1148 | |||
1149 | insn &= 0xfff00fff; | ||
1150 | insn |= 0x00002000; /* Rn = r0, Rd = r2 */ | ||
1151 | if (!(insn & (1 << 22))) { | ||
1152 | /* Register index */ | ||
1153 | insn &= ~0xf; | ||
1154 | insn |= 1; /* Rm = r1 */ | ||
1155 | } | ||
1156 | asi->insn[0] = insn; | ||
1157 | asi->insn_handler = | ||
1158 | (insn & (1 << 5)) ? emulate_strd : emulate_ldrd; | ||
1159 | return INSN_GOOD; | ||
1160 | } | ||
1161 | |||
1162 | /* LDRH/STRH/LDRSB/LDRSH */ | ||
1163 | if (is_r15(insn, 12)) | ||
1164 | return INSN_REJECTED; /* Rd is PC */ | ||
1165 | return prep_emulate_ldr_str(insn, asi); | ||
1166 | } | ||
1167 | |||
1168 | /* cccc 000x xxxx xxxx xxxx xxxx xxxx xxxx xxxx */ | ||
1169 | |||
1170 | /* | ||
1171 | * ALU op with S bit and Rd == 15 : | ||
1172 | * cccc 000x xxx1 xxxx 1111 xxxx xxxx xxxx | ||
1173 | */ | ||
1174 | if ((insn & 0x0e10f000) == 0x0010f000) | ||
1175 | return INSN_REJECTED; | ||
1176 | |||
1177 | /* | ||
1178 | * "mov ip, sp" is the most common kprobe'd instruction by far. | ||
1179 | * Check and optimize for it explicitly. | ||
1180 | */ | ||
1181 | if (insn == 0xe1a0c00d) { | ||
1182 | asi->insn_handler = simulate_mov_ipsp; | ||
1183 | return INSN_GOOD_NO_SLOT; | ||
1184 | } | ||
1185 | |||
1186 | /* | ||
1187 | * Data processing: Immediate-shift / Register-shift | ||
1188 | * ALU op : cccc 000x xxxx xxxx xxxx xxxx xxxx xxxx | ||
1189 | * CPY : cccc 0001 1010 xxxx xxxx 0000 0000 xxxx | ||
1190 | * MOV : cccc 0001 101x xxxx xxxx xxxx xxxx xxxx | ||
1191 | * *S (bit 20) updates condition codes | ||
1192 | * ADC/SBC/RSC reads the C flag | ||
1193 | */ | ||
1194 | insn &= 0xfff00ff0; /* Rn = r0, Rd = r0 */ | ||
1195 | insn |= 0x00000001; /* Rm = r1 */ | ||
1196 | if (insn & 0x010) { | ||
1197 | insn &= 0xfffff0ff; /* register shift */ | ||
1198 | insn |= 0x00000200; /* Rs = r2 */ | ||
1199 | } | ||
1200 | asi->insn[0] = insn; | ||
1201 | |||
1202 | if ((insn & 0x0f900000) == 0x01100000) { | ||
1203 | /* | ||
1204 | * TST : cccc 0001 0001 xxxx xxxx xxxx xxxx xxxx | ||
1205 | * TEQ : cccc 0001 0011 xxxx xxxx xxxx xxxx xxxx | ||
1206 | * CMP : cccc 0001 0101 xxxx xxxx xxxx xxxx xxxx | ||
1207 | * CMN : cccc 0001 0111 xxxx xxxx xxxx xxxx xxxx | ||
1208 | */ | ||
1209 | asi->insn_handler = emulate_alu_tests; | ||
1210 | } else { | ||
1211 | /* ALU ops which write to Rd */ | ||
1212 | asi->insn_handler = (insn & (1 << 20)) ? /* S-bit */ | ||
1213 | emulate_alu_rwflags : emulate_alu_rflags; | ||
1214 | } | ||
1215 | return INSN_GOOD; | ||
1216 | } | ||
1217 | |||
1218 | static enum kprobe_insn __kprobes | ||
1219 | space_cccc_001x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1220 | { | ||
1221 | /* MOVW : cccc 0011 0000 xxxx xxxx xxxx xxxx xxxx */ | ||
1222 | /* MOVT : cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx */ | ||
1223 | if ((insn & 0x0fb00000) == 0x03000000) | ||
1224 | return prep_emulate_rd12_modify(insn, asi); | ||
1225 | |||
1226 | /* hints : cccc 0011 0010 0000 xxxx xxxx xxxx xxxx */ | ||
1227 | if ((insn & 0x0fff0000) == 0x03200000) { | ||
1228 | unsigned op2 = insn & 0x000000ff; | ||
1229 | if (op2 == 0x01 || op2 == 0x04) { | ||
1230 | /* YIELD : cccc 0011 0010 0000 xxxx xxxx 0000 0001 */ | ||
1231 | /* SEV : cccc 0011 0010 0000 xxxx xxxx 0000 0100 */ | ||
1232 | asi->insn[0] = insn; | ||
1233 | asi->insn_handler = emulate_none; | ||
1234 | return INSN_GOOD; | ||
1235 | } else if (op2 <= 0x03) { | ||
1236 | /* NOP : cccc 0011 0010 0000 xxxx xxxx 0000 0000 */ | ||
1237 | /* WFE : cccc 0011 0010 0000 xxxx xxxx 0000 0010 */ | ||
1238 | /* WFI : cccc 0011 0010 0000 xxxx xxxx 0000 0011 */ | ||
1239 | /* | ||
1240 | * We make WFE and WFI true NOPs to avoid stalls due | ||
1241 | * to missing events whilst processing the probe. | ||
1242 | */ | ||
1243 | asi->insn_handler = emulate_nop; | ||
1244 | return INSN_GOOD_NO_SLOT; | ||
1245 | } | ||
1246 | /* For DBG and unallocated hints it's safest to reject them */ | ||
1247 | return INSN_REJECTED; | ||
1248 | } | ||
1249 | |||
1250 | /* | ||
1251 | * MSR : cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx | ||
1252 | * ALU op with S bit and Rd == 15 : | ||
1253 | * cccc 001x xxx1 xxxx 1111 xxxx xxxx xxxx | ||
1254 | */ | ||
1255 | if ((insn & 0x0fb00000) == 0x03200000 || /* MSR */ | ||
1256 | (insn & 0x0e10f000) == 0x0210f000) /* ALU s-bit, R15 */ | ||
1257 | return INSN_REJECTED; | ||
1258 | |||
1259 | /* | ||
1260 | * Data processing: 32-bit Immediate | ||
1261 | * ALU op : cccc 001x xxxx xxxx xxxx xxxx xxxx xxxx | ||
1262 | * MOV : cccc 0011 101x xxxx xxxx xxxx xxxx xxxx | ||
1263 | * *S (bit 20) updates condition codes | ||
1264 | * ADC/SBC/RSC reads the C flag | ||
1265 | */ | ||
1266 | insn &= 0xfff00fff; /* Rn = r0 and Rd = r0 */ | ||
1267 | asi->insn[0] = insn; | ||
1268 | |||
1269 | if ((insn & 0x0f900000) == 0x03100000) { | ||
1270 | /* | ||
1271 | * TST : cccc 0011 0001 xxxx xxxx xxxx xxxx xxxx | ||
1272 | * TEQ : cccc 0011 0011 xxxx xxxx xxxx xxxx xxxx | ||
1273 | * CMP : cccc 0011 0101 xxxx xxxx xxxx xxxx xxxx | ||
1274 | * CMN : cccc 0011 0111 xxxx xxxx xxxx xxxx xxxx | ||
1275 | */ | ||
1276 | asi->insn_handler = emulate_alu_tests_imm; | ||
1277 | } else { | ||
1278 | /* ALU ops which write to Rd */ | ||
1279 | asi->insn_handler = (insn & (1 << 20)) ? /* S-bit */ | ||
1280 | emulate_alu_imm_rwflags : emulate_alu_imm_rflags; | ||
1281 | } | ||
1282 | return INSN_GOOD; | ||
1283 | } | ||
1284 | |||
1285 | static enum kprobe_insn __kprobes | ||
1286 | space_cccc_0110__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1287 | { | ||
1288 | /* SEL : cccc 0110 1000 xxxx xxxx xxxx 1011 xxxx GE: !!! */ | ||
1289 | if ((insn & 0x0ff000f0) == 0x068000b0) { | ||
1290 | if (is_r15(insn, 12)) | ||
1291 | return INSN_REJECTED; /* Rd is PC */ | ||
1292 | insn &= 0xfff00ff0; /* Rd = r0, Rn = r0 */ | ||
1293 | insn |= 0x00000001; /* Rm = r1 */ | ||
1294 | asi->insn[0] = insn; | ||
1295 | asi->insn_handler = emulate_sel; | ||
1296 | return INSN_GOOD; | ||
1297 | } | ||
1298 | |||
1299 | /* SSAT : cccc 0110 101x xxxx xxxx xxxx xx01 xxxx :Q */ | ||
1300 | /* USAT : cccc 0110 111x xxxx xxxx xxxx xx01 xxxx :Q */ | ||
1301 | /* SSAT16 : cccc 0110 1010 xxxx xxxx xxxx 0011 xxxx :Q */ | ||
1302 | /* USAT16 : cccc 0110 1110 xxxx xxxx xxxx 0011 xxxx :Q */ | ||
1303 | if ((insn & 0x0fa00030) == 0x06a00010 || | ||
1304 | (insn & 0x0fb000f0) == 0x06a00030) { | ||
1305 | if (is_r15(insn, 12)) | ||
1306 | return INSN_REJECTED; /* Rd is PC */ | ||
1307 | insn &= 0xffff0ff0; /* Rd = r0, Rm = r0 */ | ||
1308 | asi->insn[0] = insn; | ||
1309 | asi->insn_handler = emulate_sat; | ||
1310 | return INSN_GOOD; | ||
1311 | } | ||
1312 | |||
1313 | /* REV : cccc 0110 1011 xxxx xxxx xxxx 0011 xxxx */ | ||
1314 | /* REV16 : cccc 0110 1011 xxxx xxxx xxxx 1011 xxxx */ | ||
1315 | /* RBIT : cccc 0110 1111 xxxx xxxx xxxx 0011 xxxx */ | ||
1316 | /* REVSH : cccc 0110 1111 xxxx xxxx xxxx 1011 xxxx */ | ||
1317 | if ((insn & 0x0ff00070) == 0x06b00030 || | ||
1318 | (insn & 0x0ff00070) == 0x06f00030) | ||
1319 | return prep_emulate_rd12rm0(insn, asi); | ||
1320 | |||
1321 | /* ??? : cccc 0110 0000 xxxx xxxx xxxx xxx1 xxxx : */ | ||
1322 | /* SADD16 : cccc 0110 0001 xxxx xxxx xxxx 0001 xxxx :GE */ | ||
1323 | /* SADDSUBX : cccc 0110 0001 xxxx xxxx xxxx 0011 xxxx :GE */ | ||
1324 | /* SSUBADDX : cccc 0110 0001 xxxx xxxx xxxx 0101 xxxx :GE */ | ||
1325 | /* SSUB16 : cccc 0110 0001 xxxx xxxx xxxx 0111 xxxx :GE */ | ||
1326 | /* SADD8 : cccc 0110 0001 xxxx xxxx xxxx 1001 xxxx :GE */ | ||
1327 | /* ??? : cccc 0110 0001 xxxx xxxx xxxx 1011 xxxx : */ | ||
1328 | /* ??? : cccc 0110 0001 xxxx xxxx xxxx 1101 xxxx : */ | ||
1329 | /* SSUB8 : cccc 0110 0001 xxxx xxxx xxxx 1111 xxxx :GE */ | ||
1330 | /* QADD16 : cccc 0110 0010 xxxx xxxx xxxx 0001 xxxx : */ | ||
1331 | /* QADDSUBX : cccc 0110 0010 xxxx xxxx xxxx 0011 xxxx : */ | ||
1332 | /* QSUBADDX : cccc 0110 0010 xxxx xxxx xxxx 0101 xxxx : */ | ||
1333 | /* QSUB16 : cccc 0110 0010 xxxx xxxx xxxx 0111 xxxx : */ | ||
1334 | /* QADD8 : cccc 0110 0010 xxxx xxxx xxxx 1001 xxxx : */ | ||
1335 | /* ??? : cccc 0110 0010 xxxx xxxx xxxx 1011 xxxx : */ | ||
1336 | /* ??? : cccc 0110 0010 xxxx xxxx xxxx 1101 xxxx : */ | ||
1337 | /* QSUB8 : cccc 0110 0010 xxxx xxxx xxxx 1111 xxxx : */ | ||
1338 | /* SHADD16 : cccc 0110 0011 xxxx xxxx xxxx 0001 xxxx : */ | ||
1339 | /* SHADDSUBX : cccc 0110 0011 xxxx xxxx xxxx 0011 xxxx : */ | ||
1340 | /* SHSUBADDX : cccc 0110 0011 xxxx xxxx xxxx 0101 xxxx : */ | ||
1341 | /* SHSUB16 : cccc 0110 0011 xxxx xxxx xxxx 0111 xxxx : */ | ||
1342 | /* SHADD8 : cccc 0110 0011 xxxx xxxx xxxx 1001 xxxx : */ | ||
1343 | /* ??? : cccc 0110 0011 xxxx xxxx xxxx 1011 xxxx : */ | ||
1344 | /* ??? : cccc 0110 0011 xxxx xxxx xxxx 1101 xxxx : */ | ||
1345 | /* SHSUB8 : cccc 0110 0011 xxxx xxxx xxxx 1111 xxxx : */ | ||
1346 | /* ??? : cccc 0110 0100 xxxx xxxx xxxx xxx1 xxxx : */ | ||
1347 | /* UADD16 : cccc 0110 0101 xxxx xxxx xxxx 0001 xxxx :GE */ | ||
1348 | /* UADDSUBX : cccc 0110 0101 xxxx xxxx xxxx 0011 xxxx :GE */ | ||
1349 | /* USUBADDX : cccc 0110 0101 xxxx xxxx xxxx 0101 xxxx :GE */ | ||
1350 | /* USUB16 : cccc 0110 0101 xxxx xxxx xxxx 0111 xxxx :GE */ | ||
1351 | /* UADD8 : cccc 0110 0101 xxxx xxxx xxxx 1001 xxxx :GE */ | ||
1352 | /* ??? : cccc 0110 0101 xxxx xxxx xxxx 1011 xxxx : */ | ||
1353 | /* ??? : cccc 0110 0101 xxxx xxxx xxxx 1101 xxxx : */ | ||
1354 | /* USUB8 : cccc 0110 0101 xxxx xxxx xxxx 1111 xxxx :GE */ | ||
1355 | /* UQADD16 : cccc 0110 0110 xxxx xxxx xxxx 0001 xxxx : */ | ||
1356 | /* UQADDSUBX : cccc 0110 0110 xxxx xxxx xxxx 0011 xxxx : */ | ||
1357 | /* UQSUBADDX : cccc 0110 0110 xxxx xxxx xxxx 0101 xxxx : */ | ||
1358 | /* UQSUB16 : cccc 0110 0110 xxxx xxxx xxxx 0111 xxxx : */ | ||
1359 | /* UQADD8 : cccc 0110 0110 xxxx xxxx xxxx 1001 xxxx : */ | ||
1360 | /* ??? : cccc 0110 0110 xxxx xxxx xxxx 1011 xxxx : */ | ||
1361 | /* ??? : cccc 0110 0110 xxxx xxxx xxxx 1101 xxxx : */ | ||
1362 | /* UQSUB8 : cccc 0110 0110 xxxx xxxx xxxx 1111 xxxx : */ | ||
1363 | /* UHADD16 : cccc 0110 0111 xxxx xxxx xxxx 0001 xxxx : */ | ||
1364 | /* UHADDSUBX : cccc 0110 0111 xxxx xxxx xxxx 0011 xxxx : */ | ||
1365 | /* UHSUBADDX : cccc 0110 0111 xxxx xxxx xxxx 0101 xxxx : */ | ||
1366 | /* UHSUB16 : cccc 0110 0111 xxxx xxxx xxxx 0111 xxxx : */ | ||
1367 | /* UHADD8 : cccc 0110 0111 xxxx xxxx xxxx 1001 xxxx : */ | ||
1368 | /* ??? : cccc 0110 0111 xxxx xxxx xxxx 1011 xxxx : */ | ||
1369 | /* ??? : cccc 0110 0111 xxxx xxxx xxxx 1101 xxxx : */ | ||
1370 | /* UHSUB8 : cccc 0110 0111 xxxx xxxx xxxx 1111 xxxx : */ | ||
1371 | if ((insn & 0x0f800010) == 0x06000010) { | ||
1372 | if ((insn & 0x00300000) == 0x00000000 || | ||
1373 | (insn & 0x000000e0) == 0x000000a0 || | ||
1374 | (insn & 0x000000e0) == 0x000000c0) | ||
1375 | return INSN_REJECTED; /* Unallocated space */ | ||
1376 | return prep_emulate_rd12rn16rm0_wflags(insn, asi); | ||
1377 | } | ||
1378 | |||
1379 | /* PKHBT : cccc 0110 1000 xxxx xxxx xxxx x001 xxxx : */ | ||
1380 | /* PKHTB : cccc 0110 1000 xxxx xxxx xxxx x101 xxxx : */ | ||
1381 | if ((insn & 0x0ff00030) == 0x06800010) | ||
1382 | return prep_emulate_rd12rn16rm0_wflags(insn, asi); | ||
1383 | |||
1384 | /* SXTAB16 : cccc 0110 1000 xxxx xxxx xxxx 0111 xxxx : */ | ||
1385 | /* SXTB16 : cccc 0110 1000 1111 xxxx xxxx 0111 xxxx : */ | ||
1386 | /* ??? : cccc 0110 1001 xxxx xxxx xxxx 0111 xxxx : */ | ||
1387 | /* SXTAB : cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx : */ | ||
1388 | /* SXTB : cccc 0110 1010 1111 xxxx xxxx 0111 xxxx : */ | ||
1389 | /* SXTAH : cccc 0110 1011 xxxx xxxx xxxx 0111 xxxx : */ | ||
1390 | /* SXTH : cccc 0110 1011 1111 xxxx xxxx 0111 xxxx : */ | ||
1391 | /* UXTAB16 : cccc 0110 1100 xxxx xxxx xxxx 0111 xxxx : */ | ||
1392 | /* UXTB16 : cccc 0110 1100 1111 xxxx xxxx 0111 xxxx : */ | ||
1393 | /* ??? : cccc 0110 1101 xxxx xxxx xxxx 0111 xxxx : */ | ||
1394 | /* UXTAB : cccc 0110 1110 xxxx xxxx xxxx 0111 xxxx : */ | ||
1395 | /* UXTB : cccc 0110 1110 1111 xxxx xxxx 0111 xxxx : */ | ||
1396 | /* UXTAH : cccc 0110 1111 xxxx xxxx xxxx 0111 xxxx : */ | ||
1397 | /* UXTH : cccc 0110 1111 1111 xxxx xxxx 0111 xxxx : */ | ||
1398 | if ((insn & 0x0f8000f0) == 0x06800070) { | ||
1399 | if ((insn & 0x00300000) == 0x00100000) | ||
1400 | return INSN_REJECTED; /* Unallocated space */ | ||
1401 | |||
1402 | if ((insn & 0x000f0000) == 0x000f0000) | ||
1403 | return prep_emulate_rd12rm0(insn, asi); | ||
1404 | else | ||
1405 | return prep_emulate_rd12rn16rm0_wflags(insn, asi); | ||
1406 | } | ||
1407 | |||
1408 | /* Other instruction encodings aren't yet defined */ | ||
1409 | return INSN_REJECTED; | ||
1410 | } | ||
1411 | |||
1412 | static enum kprobe_insn __kprobes | ||
1413 | space_cccc_0111__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1414 | { | ||
1415 | /* Undef : cccc 0111 1111 xxxx xxxx xxxx 1111 xxxx */ | ||
1416 | if ((insn & 0x0ff000f0) == 0x03f000f0) | ||
1417 | return INSN_REJECTED; | ||
1418 | |||
1419 | /* SMLALD : cccc 0111 0100 xxxx xxxx xxxx 00x1 xxxx */ | ||
1420 | /* SMLSLD : cccc 0111 0100 xxxx xxxx xxxx 01x1 xxxx */ | ||
1421 | if ((insn & 0x0ff00090) == 0x07400010) | ||
1422 | return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, asi); | ||
1423 | |||
1424 | /* SMLAD : cccc 0111 0000 xxxx xxxx xxxx 00x1 xxxx :Q */ | ||
1425 | /* SMUAD : cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx :Q */ | ||
1426 | /* SMLSD : cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx :Q */ | ||
1427 | /* SMUSD : cccc 0111 0000 xxxx 1111 xxxx 01x1 xxxx : */ | ||
1428 | /* SMMLA : cccc 0111 0101 xxxx xxxx xxxx 00x1 xxxx : */ | ||
1429 | /* SMMUL : cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx : */ | ||
1430 | /* USADA8 : cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx : */ | ||
1431 | /* USAD8 : cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx : */ | ||
1432 | if ((insn & 0x0ff00090) == 0x07000010 || | ||
1433 | (insn & 0x0ff000d0) == 0x07500010 || | ||
1434 | (insn & 0x0ff000f0) == 0x07800010) { | ||
1435 | |||
1436 | if ((insn & 0x0000f000) == 0x0000f000) | ||
1437 | return prep_emulate_rd16rs8rm0_wflags(insn, asi); | ||
1438 | else | ||
1439 | return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); | ||
1440 | } | ||
1441 | |||
1442 | /* SMMLS : cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx : */ | ||
1443 | if ((insn & 0x0ff000d0) == 0x075000d0) | ||
1444 | return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); | ||
1445 | |||
1446 | /* SBFX : cccc 0111 101x xxxx xxxx xxxx x101 xxxx : */ | ||
1447 | /* UBFX : cccc 0111 111x xxxx xxxx xxxx x101 xxxx : */ | ||
1448 | if ((insn & 0x0fa00070) == 0x07a00050) | ||
1449 | return prep_emulate_rd12rm0(insn, asi); | ||
1450 | |||
1451 | /* BFI : cccc 0111 110x xxxx xxxx xxxx x001 xxxx : */ | ||
1452 | /* BFC : cccc 0111 110x xxxx xxxx xxxx x001 1111 : */ | ||
1453 | if ((insn & 0x0fe00070) == 0x07c00010) { | ||
1454 | |||
1455 | if ((insn & 0x0000000f) == 0x0000000f) | ||
1456 | return prep_emulate_rd12_modify(insn, asi); | ||
1457 | else | ||
1458 | return prep_emulate_rd12rn0_modify(insn, asi); | ||
1459 | } | ||
1460 | |||
1461 | return INSN_REJECTED; | ||
1462 | } | ||
1463 | |||
1464 | static enum kprobe_insn __kprobes | ||
1465 | space_cccc_01xx(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1466 | { | ||
1467 | /* LDR : cccc 01xx x0x1 xxxx xxxx xxxx xxxx xxxx */ | ||
1468 | /* LDRB : cccc 01xx x1x1 xxxx xxxx xxxx xxxx xxxx */ | ||
1469 | /* LDRBT : cccc 01x0 x111 xxxx xxxx xxxx xxxx xxxx */ | ||
1470 | /* LDRT : cccc 01x0 x011 xxxx xxxx xxxx xxxx xxxx */ | ||
1471 | /* STR : cccc 01xx x0x0 xxxx xxxx xxxx xxxx xxxx */ | ||
1472 | /* STRB : cccc 01xx x1x0 xxxx xxxx xxxx xxxx xxxx */ | ||
1473 | /* STRBT : cccc 01x0 x110 xxxx xxxx xxxx xxxx xxxx */ | ||
1474 | /* STRT : cccc 01x0 x010 xxxx xxxx xxxx xxxx xxxx */ | ||
1475 | |||
1476 | if ((insn & 0x00500000) == 0x00500000 && is_r15(insn, 12)) | ||
1477 | return INSN_REJECTED; /* LDRB into PC */ | ||
1478 | |||
1479 | return prep_emulate_ldr_str(insn, asi); | ||
1480 | } | ||
1481 | |||
1482 | static enum kprobe_insn __kprobes | ||
1483 | space_cccc_100x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1484 | { | ||
1485 | /* LDM(2) : cccc 100x x101 xxxx 0xxx xxxx xxxx xxxx */ | ||
1486 | /* LDM(3) : cccc 100x x1x1 xxxx 1xxx xxxx xxxx xxxx */ | ||
1487 | if ((insn & 0x0e708000) == 0x85000000 || | ||
1488 | (insn & 0x0e508000) == 0x85010000) | ||
1489 | return INSN_REJECTED; | ||
1490 | |||
1491 | /* LDM(1) : cccc 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ | ||
1492 | /* STM(1) : cccc 100x x0x0 xxxx xxxx xxxx xxxx xxxx */ | ||
1493 | asi->insn_handler = ((insn & 0x108000) == 0x008000) ? /* STM & R15 */ | ||
1494 | simulate_stm1_pc : simulate_ldm1stm1; | ||
1495 | return INSN_GOOD_NO_SLOT; | ||
1496 | } | ||
1497 | |||
1498 | static enum kprobe_insn __kprobes | ||
1499 | space_cccc_101x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1500 | { | ||
1501 | /* B : cccc 1010 xxxx xxxx xxxx xxxx xxxx xxxx */ | ||
1502 | /* BL : cccc 1011 xxxx xxxx xxxx xxxx xxxx xxxx */ | ||
1503 | asi->insn_handler = simulate_bbl; | ||
1504 | return INSN_GOOD_NO_SLOT; | ||
1505 | } | ||
1506 | |||
1507 | static enum kprobe_insn __kprobes | ||
1508 | space_cccc_11xx(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1509 | { | ||
1510 | /* Coprocessor instructions... */ | ||
1511 | /* MCRR : cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */ | ||
1512 | /* MRRC : cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */ | ||
1513 | /* LDC : cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ | ||
1514 | /* STC : cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ | ||
1515 | /* CDP : cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ | ||
1516 | /* MCR : cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ | ||
1517 | /* MRC : cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ | ||
1518 | |||
1519 | /* SVC : cccc 1111 xxxx xxxx xxxx xxxx xxxx xxxx */ | ||
1520 | |||
1521 | return INSN_REJECTED; | ||
1522 | } | ||
1523 | |||
1524 | static unsigned long __kprobes __check_eq(unsigned long cpsr) | ||
1525 | { | ||
1526 | return cpsr & PSR_Z_BIT; | ||
1527 | } | ||
1528 | |||
1529 | static unsigned long __kprobes __check_ne(unsigned long cpsr) | ||
1530 | { | ||
1531 | return (~cpsr) & PSR_Z_BIT; | ||
1532 | } | ||
1533 | |||
1534 | static unsigned long __kprobes __check_cs(unsigned long cpsr) | ||
1535 | { | ||
1536 | return cpsr & PSR_C_BIT; | ||
1537 | } | ||
1538 | |||
1539 | static unsigned long __kprobes __check_cc(unsigned long cpsr) | ||
1540 | { | ||
1541 | return (~cpsr) & PSR_C_BIT; | ||
1542 | } | ||
1543 | |||
1544 | static unsigned long __kprobes __check_mi(unsigned long cpsr) | ||
1545 | { | ||
1546 | return cpsr & PSR_N_BIT; | ||
1547 | } | ||
1548 | |||
1549 | static unsigned long __kprobes __check_pl(unsigned long cpsr) | ||
1550 | { | ||
1551 | return (~cpsr) & PSR_N_BIT; | ||
1552 | } | ||
1553 | |||
1554 | static unsigned long __kprobes __check_vs(unsigned long cpsr) | ||
1555 | { | ||
1556 | return cpsr & PSR_V_BIT; | ||
1557 | } | ||
1558 | |||
1559 | static unsigned long __kprobes __check_vc(unsigned long cpsr) | ||
1560 | { | ||
1561 | return (~cpsr) & PSR_V_BIT; | ||
1562 | } | ||
1563 | |||
1564 | static unsigned long __kprobes __check_hi(unsigned long cpsr) | ||
1565 | { | ||
1566 | cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */ | ||
1567 | return cpsr & PSR_C_BIT; | ||
1568 | } | ||
1569 | |||
1570 | static unsigned long __kprobes __check_ls(unsigned long cpsr) | ||
1571 | { | ||
1572 | cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */ | ||
1573 | return (~cpsr) & PSR_C_BIT; | ||
1574 | } | ||
1575 | |||
1576 | static unsigned long __kprobes __check_ge(unsigned long cpsr) | ||
1577 | { | ||
1578 | cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ | ||
1579 | return (~cpsr) & PSR_N_BIT; | ||
1580 | } | ||
1581 | |||
1582 | static unsigned long __kprobes __check_lt(unsigned long cpsr) | ||
1583 | { | ||
1584 | cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ | ||
1585 | return cpsr & PSR_N_BIT; | ||
1586 | } | ||
1587 | |||
1588 | static unsigned long __kprobes __check_gt(unsigned long cpsr) | ||
1589 | { | ||
1590 | unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ | ||
1591 | temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */ | ||
1592 | return (~temp) & PSR_N_BIT; | ||
1593 | } | ||
1594 | |||
1595 | static unsigned long __kprobes __check_le(unsigned long cpsr) | ||
1596 | { | ||
1597 | unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ | ||
1598 | temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */ | ||
1599 | return temp & PSR_N_BIT; | ||
1600 | } | ||
1601 | |||
1602 | static unsigned long __kprobes __check_al(unsigned long cpsr) | ||
1603 | { | ||
1604 | return true; | ||
1605 | } | ||
1606 | |||
1607 | static kprobe_check_cc * const condition_checks[16] = { | ||
1608 | &__check_eq, &__check_ne, &__check_cs, &__check_cc, | ||
1609 | &__check_mi, &__check_pl, &__check_vs, &__check_vc, | ||
1610 | &__check_hi, &__check_ls, &__check_ge, &__check_lt, | ||
1611 | &__check_gt, &__check_le, &__check_al, &__check_al | ||
1612 | }; | ||
1613 | |||
1614 | /* Return: | ||
1615 | * INSN_REJECTED If instruction is one not allowed to kprobe, | ||
1616 | * INSN_GOOD If instruction is supported and uses instruction slot, | ||
1617 | * INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot. | ||
1618 | * | ||
1619 | * For instructions we don't want to kprobe (INSN_REJECTED return result): | ||
1620 | * These are generally ones that modify the processor state making | ||
1621 | * them "hard" to simulate such as switches processor modes or | ||
1622 | * make accesses in alternate modes. Any of these could be simulated | ||
1623 | * if the work was put into it, but low return considering they | ||
1624 | * should also be very rare. | ||
1625 | */ | ||
1626 | enum kprobe_insn __kprobes | ||
1627 | arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1628 | { | ||
1629 | asi->insn_check_cc = condition_checks[insn>>28]; | ||
1630 | asi->insn[1] = KPROBE_RETURN_INSTRUCTION; | ||
1631 | |||
1632 | if ((insn & 0xf0000000) == 0xf0000000) | ||
1633 | |||
1634 | return space_1111(insn, asi); | ||
1635 | |||
1636 | else if ((insn & 0x0e000000) == 0x00000000) | ||
1637 | |||
1638 | return space_cccc_000x(insn, asi); | ||
1639 | |||
1640 | else if ((insn & 0x0e000000) == 0x02000000) | ||
1641 | |||
1642 | return space_cccc_001x(insn, asi); | ||
1643 | |||
1644 | else if ((insn & 0x0f000010) == 0x06000010) | ||
1645 | |||
1646 | return space_cccc_0110__1(insn, asi); | ||
1647 | |||
1648 | else if ((insn & 0x0f000010) == 0x07000010) | ||
1649 | |||
1650 | return space_cccc_0111__1(insn, asi); | ||
1651 | |||
1652 | else if ((insn & 0x0c000000) == 0x04000000) | ||
1653 | |||
1654 | return space_cccc_01xx(insn, asi); | ||
1655 | |||
1656 | else if ((insn & 0x0e000000) == 0x08000000) | ||
1657 | |||
1658 | return space_cccc_100x(insn, asi); | ||
1659 | |||
1660 | else if ((insn & 0x0e000000) == 0x0a000000) | ||
1661 | |||
1662 | return space_cccc_101x(insn, asi); | ||
1663 | |||
1664 | return space_cccc_11xx(insn, asi); | ||
1665 | } | ||
1666 | |||
1667 | void __init arm_kprobe_decode_init(void) | ||
1668 | { | ||
1669 | find_str_pc_offset(); | ||
1670 | } | ||