Commit | Line | Data |
---|---|---|
35aa1df4 QB |
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; | |
2d4b6c9a | 491 | addr += (!pbit == !ubit); |
35aa1df4 QB |
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; | |
2d4b6c9a | 506 | addr -= (!pbit == !ubit); |
35aa1df4 QB |
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; | |
0ebe25f9 | 586 | long ppc = (long)p->addr + 8; |
35aa1df4 QB |
587 | union reg_pair fnr; |
588 | int rd = (insn >> 12) & 0xf; | |
589 | int rn = (insn >> 16) & 0xf; | |
590 | int rm = insn & 0xf; | |
591 | long rdv; | |
0ebe25f9 NP |
592 | long rnv = (rn == 15) ? ppc : regs->uregs[rn]; |
593 | long rmv = (rm == 15) ? ppc : regs->uregs[rm]; | |
35aa1df4 QB |
594 | long cpsr = regs->ARM_cpsr; |
595 | ||
596 | fnr.dr = insnslot_llret_3arg_rflags(rnv, 0, rmv, cpsr, i_fn); | |
597 | regs->uregs[rn] = fnr.r0; /* Save Rn in case of writeback. */ | |
598 | rdv = fnr.r1; | |
599 | ||
600 | if (rd == 15) { | |
601 | #if __LINUX_ARM_ARCH__ >= 5 | |
602 | cpsr &= ~PSR_T_BIT; | |
603 | if (rdv & 0x1) | |
604 | cpsr |= PSR_T_BIT; | |
605 | regs->ARM_cpsr = cpsr; | |
606 | rdv &= ~0x1; | |
607 | #else | |
608 | rdv &= ~0x2; | |
609 | #endif | |
610 | } | |
611 | regs->uregs[rd] = rdv; | |
612 | } | |
613 | ||
614 | static void __kprobes emulate_str(struct kprobe *p, struct pt_regs *regs) | |
615 | { | |
616 | insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; | |
617 | kprobe_opcode_t insn = p->opcode; | |
618 | long iaddr = (long)p->addr; | |
619 | int rd = (insn >> 12) & 0xf; | |
620 | int rn = (insn >> 16) & 0xf; | |
621 | int rm = insn & 0xf; | |
622 | long rdv = (rd == 15) ? iaddr + str_pc_offset : regs->uregs[rd]; | |
623 | long rnv = (rn == 15) ? iaddr + 8 : regs->uregs[rn]; | |
624 | long rmv = regs->uregs[rm]; /* rm/rmv may be invalid, don't care. */ | |
625 | ||
626 | /* Save Rn in case of writeback. */ | |
627 | regs->uregs[rn] = | |
628 | insnslot_3arg_rflags(rnv, rdv, rmv, regs->ARM_cpsr, i_fn); | |
629 | } | |
630 | ||
631 | static void __kprobes emulate_mrrc(struct kprobe *p, struct pt_regs *regs) | |
632 | { | |
633 | insn_llret_0arg_fn_t *i_fn = (insn_llret_0arg_fn_t *)&p->ainsn.insn[0]; | |
634 | kprobe_opcode_t insn = p->opcode; | |
635 | union reg_pair fnr; | |
636 | int rd = (insn >> 12) & 0xf; | |
637 | int rn = (insn >> 16) & 0xf; | |
638 | ||
639 | fnr.dr = insnslot_llret_0arg_rflags(regs->ARM_cpsr, i_fn); | |
640 | regs->uregs[rn] = fnr.r0; | |
641 | regs->uregs[rd] = fnr.r1; | |
642 | } | |
643 | ||
644 | static void __kprobes emulate_mcrr(struct kprobe *p, struct pt_regs *regs) | |
645 | { | |
646 | insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; | |
647 | kprobe_opcode_t insn = p->opcode; | |
648 | int rd = (insn >> 12) & 0xf; | |
649 | int rn = (insn >> 16) & 0xf; | |
650 | long rnv = regs->uregs[rn]; | |
651 | long rdv = regs->uregs[rd]; | |
652 | ||
653 | insnslot_2arg_rflags(rnv, rdv, regs->ARM_cpsr, i_fn); | |
654 | } | |
655 | ||
656 | static void __kprobes emulate_sat(struct kprobe *p, struct pt_regs *regs) | |
657 | { | |
658 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | |
659 | kprobe_opcode_t insn = p->opcode; | |
660 | int rd = (insn >> 12) & 0xf; | |
661 | int rm = insn & 0xf; | |
662 | long rmv = regs->uregs[rm]; | |
663 | ||
664 | /* Writes Q flag */ | |
665 | regs->uregs[rd] = insnslot_1arg_rwflags(rmv, ®s->ARM_cpsr, i_fn); | |
666 | } | |
667 | ||
668 | static void __kprobes emulate_sel(struct kprobe *p, struct pt_regs *regs) | |
669 | { | |
670 | insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; | |
671 | kprobe_opcode_t insn = p->opcode; | |
672 | int rd = (insn >> 12) & 0xf; | |
673 | int rn = (insn >> 16) & 0xf; | |
674 | int rm = insn & 0xf; | |
675 | long rnv = regs->uregs[rn]; | |
676 | long rmv = regs->uregs[rm]; | |
677 | ||
678 | /* Reads GE bits */ | |
679 | regs->uregs[rd] = insnslot_2arg_rflags(rnv, rmv, regs->ARM_cpsr, i_fn); | |
680 | } | |
681 | ||
682 | static void __kprobes emulate_none(struct kprobe *p, struct pt_regs *regs) | |
683 | { | |
684 | insn_0arg_fn_t *i_fn = (insn_0arg_fn_t *)&p->ainsn.insn[0]; | |
685 | ||
686 | insnslot_0arg_rflags(regs->ARM_cpsr, i_fn); | |
687 | } | |
688 | ||
689 | static void __kprobes emulate_rd12(struct kprobe *p, struct pt_regs *regs) | |
690 | { | |
691 | insn_0arg_fn_t *i_fn = (insn_0arg_fn_t *)&p->ainsn.insn[0]; | |
692 | kprobe_opcode_t insn = p->opcode; | |
693 | int rd = (insn >> 12) & 0xf; | |
694 | ||
695 | regs->uregs[rd] = insnslot_0arg_rflags(regs->ARM_cpsr, i_fn); | |
696 | } | |
697 | ||
698 | static void __kprobes emulate_ird12(struct kprobe *p, struct pt_regs *regs) | |
699 | { | |
700 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | |
701 | kprobe_opcode_t insn = p->opcode; | |
702 | int ird = (insn >> 12) & 0xf; | |
703 | ||
704 | insnslot_1arg_rflags(regs->uregs[ird], regs->ARM_cpsr, i_fn); | |
705 | } | |
706 | ||
707 | static void __kprobes emulate_rn16(struct kprobe *p, struct pt_regs *regs) | |
708 | { | |
709 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | |
710 | kprobe_opcode_t insn = p->opcode; | |
711 | int rn = (insn >> 16) & 0xf; | |
712 | long rnv = regs->uregs[rn]; | |
713 | ||
714 | insnslot_1arg_rflags(rnv, regs->ARM_cpsr, i_fn); | |
715 | } | |
716 | ||
717 | static void __kprobes emulate_rd12rm0(struct kprobe *p, struct pt_regs *regs) | |
718 | { | |
719 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | |
720 | kprobe_opcode_t insn = p->opcode; | |
721 | int rd = (insn >> 12) & 0xf; | |
722 | int rm = insn & 0xf; | |
723 | long rmv = regs->uregs[rm]; | |
724 | ||
725 | regs->uregs[rd] = insnslot_1arg_rflags(rmv, regs->ARM_cpsr, i_fn); | |
726 | } | |
727 | ||
728 | static void __kprobes | |
729 | emulate_rd12rn16rm0_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 >> 12) & 0xf; | |
734 | int rn = (insn >> 16) & 0xf; | |
735 | int rm = insn & 0xf; | |
736 | long rnv = regs->uregs[rn]; | |
737 | long rmv = regs->uregs[rm]; | |
738 | ||
739 | regs->uregs[rd] = | |
740 | insnslot_2arg_rwflags(rnv, rmv, ®s->ARM_cpsr, i_fn); | |
741 | } | |
742 | ||
743 | static void __kprobes | |
744 | emulate_rd16rn12rs8rm0_rwflags(struct kprobe *p, struct pt_regs *regs) | |
745 | { | |
746 | insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; | |
747 | kprobe_opcode_t insn = p->opcode; | |
748 | int rd = (insn >> 16) & 0xf; | |
749 | int rn = (insn >> 12) & 0xf; | |
750 | int rs = (insn >> 8) & 0xf; | |
751 | int rm = insn & 0xf; | |
752 | long rnv = regs->uregs[rn]; | |
753 | long rsv = regs->uregs[rs]; | |
754 | long rmv = regs->uregs[rm]; | |
755 | ||
756 | regs->uregs[rd] = | |
757 | insnslot_3arg_rwflags(rnv, rsv, rmv, ®s->ARM_cpsr, i_fn); | |
758 | } | |
759 | ||
760 | static void __kprobes | |
761 | emulate_rd16rs8rm0_rwflags(struct kprobe *p, struct pt_regs *regs) | |
762 | { | |
763 | insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; | |
764 | kprobe_opcode_t insn = p->opcode; | |
765 | int rd = (insn >> 16) & 0xf; | |
766 | int rs = (insn >> 8) & 0xf; | |
767 | int rm = insn & 0xf; | |
768 | long rsv = regs->uregs[rs]; | |
769 | long rmv = regs->uregs[rm]; | |
770 | ||
771 | regs->uregs[rd] = | |
772 | insnslot_2arg_rwflags(rsv, rmv, ®s->ARM_cpsr, i_fn); | |
773 | } | |
774 | ||
775 | static void __kprobes | |
776 | emulate_rdhi16rdlo12rs8rm0_rwflags(struct kprobe *p, struct pt_regs *regs) | |
777 | { | |
778 | insn_llret_4arg_fn_t *i_fn = (insn_llret_4arg_fn_t *)&p->ainsn.insn[0]; | |
779 | kprobe_opcode_t insn = p->opcode; | |
780 | union reg_pair fnr; | |
781 | int rdhi = (insn >> 16) & 0xf; | |
782 | int rdlo = (insn >> 12) & 0xf; | |
783 | int rs = (insn >> 8) & 0xf; | |
784 | int rm = insn & 0xf; | |
785 | long rsv = regs->uregs[rs]; | |
786 | long rmv = regs->uregs[rm]; | |
787 | ||
788 | fnr.dr = insnslot_llret_4arg_rwflags(regs->uregs[rdhi], | |
789 | regs->uregs[rdlo], rsv, rmv, | |
790 | ®s->ARM_cpsr, i_fn); | |
791 | regs->uregs[rdhi] = fnr.r0; | |
792 | regs->uregs[rdlo] = fnr.r1; | |
793 | } | |
794 | ||
795 | static void __kprobes | |
796 | emulate_alu_imm_rflags(struct kprobe *p, struct pt_regs *regs) | |
797 | { | |
798 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | |
799 | kprobe_opcode_t insn = p->opcode; | |
800 | int rd = (insn >> 12) & 0xf; | |
801 | int rn = (insn >> 16) & 0xf; | |
802 | long rnv = (rn == 15) ? (long)p->addr + 8 : regs->uregs[rn]; | |
803 | ||
804 | regs->uregs[rd] = insnslot_1arg_rflags(rnv, regs->ARM_cpsr, i_fn); | |
805 | } | |
806 | ||
807 | static void __kprobes | |
808 | emulate_alu_imm_rwflags(struct kprobe *p, struct pt_regs *regs) | |
809 | { | |
810 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | |
811 | kprobe_opcode_t insn = p->opcode; | |
812 | int rd = (insn >> 12) & 0xf; | |
813 | int rn = (insn >> 16) & 0xf; | |
814 | long rnv = (rn == 15) ? (long)p->addr + 8 : regs->uregs[rn]; | |
815 | ||
816 | regs->uregs[rd] = insnslot_1arg_rwflags(rnv, ®s->ARM_cpsr, i_fn); | |
817 | } | |
818 | ||
819 | static void __kprobes | |
820 | emulate_alu_rflags(struct kprobe *p, struct pt_regs *regs) | |
821 | { | |
822 | insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; | |
823 | kprobe_opcode_t insn = p->opcode; | |
824 | long ppc = (long)p->addr + 8; | |
825 | int rd = (insn >> 12) & 0xf; | |
826 | int rn = (insn >> 16) & 0xf; /* rn/rnv/rs/rsv may be */ | |
827 | int rs = (insn >> 8) & 0xf; /* invalid, don't care. */ | |
828 | int rm = insn & 0xf; | |
829 | long rnv = (rn == 15) ? ppc : regs->uregs[rn]; | |
830 | long rmv = (rm == 15) ? ppc : regs->uregs[rm]; | |
831 | long rsv = regs->uregs[rs]; | |
832 | ||
833 | regs->uregs[rd] = | |
834 | insnslot_3arg_rflags(rnv, rmv, rsv, regs->ARM_cpsr, i_fn); | |
835 | } | |
836 | ||
837 | static void __kprobes | |
838 | emulate_alu_rwflags(struct kprobe *p, struct pt_regs *regs) | |
839 | { | |
840 | insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; | |
841 | kprobe_opcode_t insn = p->opcode; | |
842 | long ppc = (long)p->addr + 8; | |
843 | int rd = (insn >> 12) & 0xf; | |
844 | int rn = (insn >> 16) & 0xf; /* rn/rnv/rs/rsv may be */ | |
845 | int rs = (insn >> 8) & 0xf; /* invalid, don't care. */ | |
846 | int rm = insn & 0xf; | |
847 | long rnv = (rn == 15) ? ppc : regs->uregs[rn]; | |
848 | long rmv = (rm == 15) ? ppc : regs->uregs[rm]; | |
849 | long rsv = regs->uregs[rs]; | |
850 | ||
851 | regs->uregs[rd] = | |
852 | insnslot_3arg_rwflags(rnv, rmv, rsv, ®s->ARM_cpsr, i_fn); | |
853 | } | |
854 | ||
855 | static enum kprobe_insn __kprobes | |
856 | prep_emulate_ldr_str(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |
857 | { | |
858 | int ibit = (insn & (1 << 26)) ? 25 : 22; | |
859 | ||
860 | insn &= 0xfff00fff; | |
861 | insn |= 0x00001000; /* Rn = r0, Rd = r1 */ | |
862 | if (insn & (1 << ibit)) { | |
863 | insn &= ~0xf; | |
864 | insn |= 2; /* Rm = r2 */ | |
865 | } | |
866 | asi->insn[0] = insn; | |
867 | asi->insn_handler = (insn & (1 << 20)) ? emulate_ldr : emulate_str; | |
868 | return INSN_GOOD; | |
869 | } | |
870 | ||
871 | static enum kprobe_insn __kprobes | |
872 | prep_emulate_rd12rm0(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |
873 | { | |
874 | insn &= 0xffff0ff0; /* Rd = r0, Rm = r0 */ | |
875 | asi->insn[0] = insn; | |
876 | asi->insn_handler = emulate_rd12rm0; | |
877 | return INSN_GOOD; | |
878 | } | |
879 | ||
880 | static enum kprobe_insn __kprobes | |
881 | prep_emulate_rd12(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |
882 | { | |
883 | insn &= 0xffff0fff; /* Rd = r0 */ | |
884 | asi->insn[0] = insn; | |
885 | asi->insn_handler = emulate_rd12; | |
886 | return INSN_GOOD; | |
887 | } | |
888 | ||
889 | static enum kprobe_insn __kprobes | |
890 | prep_emulate_rd12rn16rm0_wflags(kprobe_opcode_t insn, | |
891 | struct arch_specific_insn *asi) | |
892 | { | |
893 | insn &= 0xfff00ff0; /* Rd = r0, Rn = r0 */ | |
894 | insn |= 0x00000001; /* Rm = r1 */ | |
895 | asi->insn[0] = insn; | |
896 | asi->insn_handler = emulate_rd12rn16rm0_rwflags; | |
897 | return INSN_GOOD; | |
898 | } | |
899 | ||
900 | static enum kprobe_insn __kprobes | |
901 | prep_emulate_rd16rs8rm0_wflags(kprobe_opcode_t insn, | |
902 | struct arch_specific_insn *asi) | |
903 | { | |
904 | insn &= 0xfff0f0f0; /* Rd = r0, Rs = r0 */ | |
905 | insn |= 0x00000001; /* Rm = r1 */ | |
906 | asi->insn[0] = insn; | |
907 | asi->insn_handler = emulate_rd16rs8rm0_rwflags; | |
908 | return INSN_GOOD; | |
909 | } | |
910 | ||
911 | static enum kprobe_insn __kprobes | |
912 | prep_emulate_rd16rn12rs8rm0_wflags(kprobe_opcode_t insn, | |
913 | struct arch_specific_insn *asi) | |
914 | { | |
915 | insn &= 0xfff000f0; /* Rd = r0, Rn = r0 */ | |
916 | insn |= 0x00000102; /* Rs = r1, Rm = r2 */ | |
917 | asi->insn[0] = insn; | |
918 | asi->insn_handler = emulate_rd16rn12rs8rm0_rwflags; | |
919 | return INSN_GOOD; | |
920 | } | |
921 | ||
922 | static enum kprobe_insn __kprobes | |
923 | prep_emulate_rdhi16rdlo12rs8rm0_wflags(kprobe_opcode_t insn, | |
924 | struct arch_specific_insn *asi) | |
925 | { | |
926 | insn &= 0xfff000f0; /* RdHi = r0, RdLo = r1 */ | |
927 | insn |= 0x00001203; /* Rs = r2, Rm = r3 */ | |
928 | asi->insn[0] = insn; | |
929 | asi->insn_handler = emulate_rdhi16rdlo12rs8rm0_rwflags; | |
930 | return INSN_GOOD; | |
931 | } | |
932 | ||
933 | /* | |
934 | * For the instruction masking and comparisons in all the "space_*" | |
935 | * functions below, Do _not_ rearrange the order of tests unless | |
936 | * you're very, very sure of what you are doing. For the sake of | |
937 | * efficiency, the masks for some tests sometimes assume other test | |
938 | * have been done prior to them so the number of patterns to test | |
939 | * for an instruction set can be as broad as possible to reduce the | |
940 | * number of tests needed. | |
941 | */ | |
942 | ||
943 | static enum kprobe_insn __kprobes | |
944 | space_1111(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |
945 | { | |
946 | /* CPS mmod == 1 : 1111 0001 0000 xx10 xxxx xxxx xx0x xxxx */ | |
947 | /* RFE : 1111 100x x0x1 xxxx xxxx 1010 xxxx xxxx */ | |
948 | /* SRS : 1111 100x x1x0 1101 xxxx 0101 xxxx xxxx */ | |
949 | if ((insn & 0xfff30020) == 0xf1020000 || | |
950 | (insn & 0xfe500f00) == 0xf8100a00 || | |
951 | (insn & 0xfe5f0f00) == 0xf84d0500) | |
952 | return INSN_REJECTED; | |
953 | ||
954 | /* PLD : 1111 01x1 x101 xxxx xxxx xxxx xxxx xxxx : */ | |
955 | if ((insn & 0xfd700000) == 0xf4500000) { | |
956 | insn &= 0xfff0ffff; /* Rn = r0 */ | |
957 | asi->insn[0] = insn; | |
958 | asi->insn_handler = emulate_rn16; | |
959 | return INSN_GOOD; | |
960 | } | |
961 | ||
962 | /* BLX(1) : 1111 101x xxxx xxxx xxxx xxxx xxxx xxxx : */ | |
963 | if ((insn & 0xfe000000) == 0xfa000000) { | |
964 | asi->insn_handler = simulate_blx1; | |
965 | return INSN_GOOD_NO_SLOT; | |
966 | } | |
967 | ||
968 | /* SETEND : 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */ | |
969 | /* CDP2 : 1111 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ | |
970 | if ((insn & 0xffff00f0) == 0xf1010000 || | |
971 | (insn & 0xff000010) == 0xfe000000) { | |
972 | asi->insn[0] = insn; | |
973 | asi->insn_handler = emulate_none; | |
974 | return INSN_GOOD; | |
975 | } | |
976 | ||
977 | /* MCRR2 : 1111 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */ | |
978 | /* MRRC2 : 1111 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */ | |
979 | if ((insn & 0xffe00000) == 0xfc400000) { | |
980 | insn &= 0xfff00fff; /* Rn = r0 */ | |
981 | insn |= 0x00001000; /* Rd = r1 */ | |
982 | asi->insn[0] = insn; | |
983 | asi->insn_handler = | |
984 | (insn & (1 << 20)) ? emulate_mrrc : emulate_mcrr; | |
985 | return INSN_GOOD; | |
986 | } | |
987 | ||
988 | /* LDC2 : 1111 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ | |
989 | /* STC2 : 1111 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ | |
990 | if ((insn & 0xfe000000) == 0xfc000000) { | |
991 | insn &= 0xfff0ffff; /* Rn = r0 */ | |
992 | asi->insn[0] = insn; | |
993 | asi->insn_handler = emulate_ldcstc; | |
994 | return INSN_GOOD; | |
995 | } | |
996 | ||
997 | /* MCR2 : 1111 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ | |
998 | /* MRC2 : 1111 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ | |
999 | insn &= 0xffff0fff; /* Rd = r0 */ | |
1000 | asi->insn[0] = insn; | |
1001 | asi->insn_handler = (insn & (1 << 20)) ? emulate_rd12 : emulate_ird12; | |
1002 | return INSN_GOOD; | |
1003 | } | |
1004 | ||
1005 | static enum kprobe_insn __kprobes | |
1006 | space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |
1007 | { | |
1008 | /* cccc 0001 0xx0 xxxx xxxx xxxx xxxx xxx0 xxxx */ | |
1009 | if ((insn & 0x0f900010) == 0x01000000) { | |
1010 | ||
1011 | /* BXJ : cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */ | |
1012 | /* MSR : cccc 0001 0x10 xxxx xxxx xxxx 0000 xxxx */ | |
1013 | if ((insn & 0x0ff000f0) == 0x01200020 || | |
1014 | (insn & 0x0fb000f0) == 0x01200000) | |
1015 | return INSN_REJECTED; | |
1016 | ||
1017 | /* MRS : cccc 0001 0x00 xxxx xxxx xxxx 0000 xxxx */ | |
1018 | if ((insn & 0x0fb00010) == 0x01000000) | |
1019 | return prep_emulate_rd12(insn, asi); | |
1020 | ||
1021 | /* SMLALxy : cccc 0001 0100 xxxx xxxx xxxx 1xx0 xxxx */ | |
1022 | if ((insn & 0x0ff00090) == 0x01400080) | |
1023 | return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, asi); | |
1024 | ||
1025 | /* SMULWy : cccc 0001 0010 xxxx xxxx xxxx 1x10 xxxx */ | |
1026 | /* SMULxy : cccc 0001 0110 xxxx xxxx xxxx 1xx0 xxxx */ | |
1027 | if ((insn & 0x0ff000b0) == 0x012000a0 || | |
1028 | (insn & 0x0ff00090) == 0x01600080) | |
1029 | return prep_emulate_rd16rs8rm0_wflags(insn, asi); | |
1030 | ||
1031 | /* SMLAxy : cccc 0001 0000 xxxx xxxx xxxx 1xx0 xxxx : Q */ | |
1032 | /* SMLAWy : cccc 0001 0010 xxxx xxxx xxxx 0x00 xxxx : Q */ | |
1033 | return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); | |
1034 | ||
1035 | } | |
1036 | ||
1037 | /* cccc 0001 0xx0 xxxx xxxx xxxx xxxx 0xx1 xxxx */ | |
1038 | else if ((insn & 0x0f900090) == 0x01000010) { | |
1039 | ||
1040 | /* BKPT : 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */ | |
1041 | if ((insn & 0xfff000f0) == 0xe1200070) | |
1042 | return INSN_REJECTED; | |
1043 | ||
1044 | /* BLX(2) : cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */ | |
1045 | /* BX : cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */ | |
1046 | if ((insn & 0x0ff000d0) == 0x01200010) { | |
1047 | asi->insn[0] = truecc_insn(insn); | |
1048 | asi->insn_handler = simulate_blx2bx; | |
1049 | return INSN_GOOD; | |
1050 | } | |
1051 | ||
1052 | /* CLZ : cccc 0001 0110 xxxx xxxx xxxx 0001 xxxx */ | |
1053 | if ((insn & 0x0ff000f0) == 0x01600010) | |
1054 | return prep_emulate_rd12rm0(insn, asi); | |
1055 | ||
1056 | /* QADD : cccc 0001 0000 xxxx xxxx xxxx 0101 xxxx :Q */ | |
1057 | /* QSUB : cccc 0001 0010 xxxx xxxx xxxx 0101 xxxx :Q */ | |
1058 | /* QDADD : cccc 0001 0100 xxxx xxxx xxxx 0101 xxxx :Q */ | |
1059 | /* QDSUB : cccc 0001 0110 xxxx xxxx xxxx 0101 xxxx :Q */ | |
1060 | return prep_emulate_rd12rn16rm0_wflags(insn, asi); | |
1061 | } | |
1062 | ||
1063 | /* cccc 0000 xxxx xxxx xxxx xxxx xxxx 1001 xxxx */ | |
1064 | else if ((insn & 0x0f000090) == 0x00000090) { | |
1065 | ||
1066 | /* MUL : cccc 0000 0000 xxxx xxxx xxxx 1001 xxxx : */ | |
1067 | /* MULS : cccc 0000 0001 xxxx xxxx xxxx 1001 xxxx :cc */ | |
1068 | /* MLA : cccc 0000 0010 xxxx xxxx xxxx 1001 xxxx : */ | |
1069 | /* MLAS : cccc 0000 0011 xxxx xxxx xxxx 1001 xxxx :cc */ | |
1070 | /* UMAAL : cccc 0000 0100 xxxx xxxx xxxx 1001 xxxx : */ | |
1071 | /* UMULL : cccc 0000 1000 xxxx xxxx xxxx 1001 xxxx : */ | |
1072 | /* UMULLS : cccc 0000 1001 xxxx xxxx xxxx 1001 xxxx :cc */ | |
1073 | /* UMLAL : cccc 0000 1010 xxxx xxxx xxxx 1001 xxxx : */ | |
1074 | /* UMLALS : cccc 0000 1011 xxxx xxxx xxxx 1001 xxxx :cc */ | |
1075 | /* SMULL : cccc 0000 1100 xxxx xxxx xxxx 1001 xxxx : */ | |
1076 | /* SMULLS : cccc 0000 1101 xxxx xxxx xxxx 1001 xxxx :cc */ | |
1077 | /* SMLAL : cccc 0000 1110 xxxx xxxx xxxx 1001 xxxx : */ | |
1078 | /* SMLALS : cccc 0000 1111 xxxx xxxx xxxx 1001 xxxx :cc */ | |
1079 | if ((insn & 0x0fe000f0) == 0x00000090) { | |
1080 | return prep_emulate_rd16rs8rm0_wflags(insn, asi); | |
1081 | } else if ((insn & 0x0fe000f0) == 0x00200090) { | |
1082 | return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); | |
1083 | } else { | |
1084 | return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, asi); | |
1085 | } | |
1086 | } | |
1087 | ||
1088 | /* cccc 000x xxxx xxxx xxxx xxxx xxxx 1xx1 xxxx */ | |
1089 | else if ((insn & 0x0e000090) == 0x00000090) { | |
1090 | ||
1091 | /* SWP : cccc 0001 0000 xxxx xxxx xxxx 1001 xxxx */ | |
1092 | /* SWPB : cccc 0001 0100 xxxx xxxx xxxx 1001 xxxx */ | |
1093 | /* LDRD : cccc 000x xxx0 xxxx xxxx xxxx 1101 xxxx */ | |
1094 | /* STRD : cccc 000x xxx0 xxxx xxxx xxxx 1111 xxxx */ | |
1095 | /* STREX : cccc 0001 1000 xxxx xxxx xxxx 1001 xxxx */ | |
1096 | /* LDREX : cccc 0001 1001 xxxx xxxx xxxx 1001 xxxx */ | |
1097 | /* LDRH : cccc 000x xxx1 xxxx xxxx xxxx 1011 xxxx */ | |
1098 | /* STRH : cccc 000x xxx0 xxxx xxxx xxxx 1011 xxxx */ | |
1099 | /* LDRSB : cccc 000x xxx1 xxxx xxxx xxxx 1101 xxxx */ | |
1100 | /* LDRSH : cccc 000x xxx1 xxxx xxxx xxxx 1111 xxxx */ | |
1101 | if ((insn & 0x0fb000f0) == 0x01000090) { | |
1102 | /* SWP/SWPB */ | |
1103 | return prep_emulate_rd12rn16rm0_wflags(insn, asi); | |
1104 | } else if ((insn & 0x0e1000d0) == 0x00000d0) { | |
1105 | /* STRD/LDRD */ | |
1106 | insn &= 0xfff00fff; | |
1107 | insn |= 0x00002000; /* Rn = r0, Rd = r2 */ | |
1108 | if (insn & (1 << 22)) { | |
1109 | /* I bit */ | |
1110 | insn &= ~0xf; | |
1111 | insn |= 1; /* Rm = r1 */ | |
1112 | } | |
1113 | asi->insn[0] = insn; | |
1114 | asi->insn_handler = | |
1115 | (insn & (1 << 5)) ? emulate_strd : emulate_ldrd; | |
1116 | return INSN_GOOD; | |
1117 | } | |
1118 | ||
1119 | return prep_emulate_ldr_str(insn, asi); | |
1120 | } | |
1121 | ||
1122 | /* cccc 000x xxxx xxxx xxxx xxxx xxxx xxxx xxxx */ | |
1123 | ||
1124 | /* | |
1125 | * ALU op with S bit and Rd == 15 : | |
1126 | * cccc 000x xxx1 xxxx 1111 xxxx xxxx xxxx | |
1127 | */ | |
1128 | if ((insn & 0x0e10f000) == 0x0010f000) | |
1129 | return INSN_REJECTED; | |
1130 | ||
1131 | /* | |
1132 | * "mov ip, sp" is the most common kprobe'd instruction by far. | |
1133 | * Check and optimize for it explicitly. | |
1134 | */ | |
1135 | if (insn == 0xe1a0c00d) { | |
1136 | asi->insn_handler = simulate_mov_ipsp; | |
1137 | return INSN_GOOD_NO_SLOT; | |
1138 | } | |
1139 | ||
1140 | /* | |
1141 | * Data processing: Immediate-shift / Register-shift | |
1142 | * ALU op : cccc 000x xxxx xxxx xxxx xxxx xxxx xxxx | |
1143 | * CPY : cccc 0001 1010 xxxx xxxx 0000 0000 xxxx | |
1144 | * MOV : cccc 0001 101x xxxx xxxx xxxx xxxx xxxx | |
1145 | * *S (bit 20) updates condition codes | |
1146 | * ADC/SBC/RSC reads the C flag | |
1147 | */ | |
1148 | insn &= 0xfff00ff0; /* Rn = r0, Rd = r0 */ | |
1149 | insn |= 0x00000001; /* Rm = r1 */ | |
1150 | if (insn & 0x010) { | |
1151 | insn &= 0xfffff0ff; /* register shift */ | |
1152 | insn |= 0x00000200; /* Rs = r2 */ | |
1153 | } | |
1154 | asi->insn[0] = insn; | |
1155 | asi->insn_handler = (insn & (1 << 20)) ? /* S-bit */ | |
1156 | emulate_alu_rwflags : emulate_alu_rflags; | |
1157 | return INSN_GOOD; | |
1158 | } | |
1159 | ||
1160 | static enum kprobe_insn __kprobes | |
1161 | space_cccc_001x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |
1162 | { | |
1163 | /* | |
1164 | * MSR : cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx | |
ccdf2e1b | 1165 | * Undef : cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx |
35aa1df4 QB |
1166 | * ALU op with S bit and Rd == 15 : |
1167 | * cccc 001x xxx1 xxxx 1111 xxxx xxxx xxxx | |
1168 | */ | |
ccdf2e1b WD |
1169 | if ((insn & 0x0fb00000) == 0x03200000 || /* MSR */ |
1170 | (insn & 0x0ff00000) == 0x03400000 || /* Undef */ | |
35aa1df4 QB |
1171 | (insn & 0x0e10f000) == 0x0210f000) /* ALU s-bit, R15 */ |
1172 | return INSN_REJECTED; | |
1173 | ||
1174 | /* | |
1175 | * Data processing: 32-bit Immediate | |
1176 | * ALU op : cccc 001x xxxx xxxx xxxx xxxx xxxx xxxx | |
1177 | * MOV : cccc 0011 101x xxxx xxxx xxxx xxxx xxxx | |
1178 | * *S (bit 20) updates condition codes | |
1179 | * ADC/SBC/RSC reads the C flag | |
1180 | */ | |
ccdf2e1b | 1181 | insn &= 0xffff0fff; /* Rd = r0 */ |
35aa1df4 QB |
1182 | asi->insn[0] = insn; |
1183 | asi->insn_handler = (insn & (1 << 20)) ? /* S-bit */ | |
1184 | emulate_alu_imm_rwflags : emulate_alu_imm_rflags; | |
1185 | return INSN_GOOD; | |
1186 | } | |
1187 | ||
1188 | static enum kprobe_insn __kprobes | |
1189 | space_cccc_0110__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |
1190 | { | |
1191 | /* SEL : cccc 0110 1000 xxxx xxxx xxxx 1011 xxxx GE: !!! */ | |
1192 | if ((insn & 0x0ff000f0) == 0x068000b0) { | |
1193 | insn &= 0xfff00ff0; /* Rd = r0, Rn = r0 */ | |
1194 | insn |= 0x00000001; /* Rm = r1 */ | |
1195 | asi->insn[0] = insn; | |
1196 | asi->insn_handler = emulate_sel; | |
1197 | return INSN_GOOD; | |
1198 | } | |
1199 | ||
1200 | /* SSAT : cccc 0110 101x xxxx xxxx xxxx xx01 xxxx :Q */ | |
1201 | /* USAT : cccc 0110 111x xxxx xxxx xxxx xx01 xxxx :Q */ | |
1202 | /* SSAT16 : cccc 0110 1010 xxxx xxxx xxxx 0011 xxxx :Q */ | |
1203 | /* USAT16 : cccc 0110 1110 xxxx xxxx xxxx 0011 xxxx :Q */ | |
1204 | if ((insn & 0x0fa00030) == 0x06a00010 || | |
1205 | (insn & 0x0fb000f0) == 0x06a00030) { | |
1206 | insn &= 0xffff0ff0; /* Rd = r0, Rm = r0 */ | |
1207 | asi->insn[0] = insn; | |
1208 | asi->insn_handler = emulate_sat; | |
1209 | return INSN_GOOD; | |
1210 | } | |
1211 | ||
1212 | /* REV : cccc 0110 1011 xxxx xxxx xxxx 0011 xxxx */ | |
1213 | /* REV16 : cccc 0110 1011 xxxx xxxx xxxx 1011 xxxx */ | |
1214 | /* REVSH : cccc 0110 1111 xxxx xxxx xxxx 1011 xxxx */ | |
1215 | if ((insn & 0x0ff00070) == 0x06b00030 || | |
1216 | (insn & 0x0ff000f0) == 0x06f000b0) | |
1217 | return prep_emulate_rd12rm0(insn, asi); | |
1218 | ||
1219 | /* SADD16 : cccc 0110 0001 xxxx xxxx xxxx 0001 xxxx :GE */ | |
1220 | /* SADDSUBX : cccc 0110 0001 xxxx xxxx xxxx 0011 xxxx :GE */ | |
1221 | /* SSUBADDX : cccc 0110 0001 xxxx xxxx xxxx 0101 xxxx :GE */ | |
1222 | /* SSUB16 : cccc 0110 0001 xxxx xxxx xxxx 0111 xxxx :GE */ | |
1223 | /* SADD8 : cccc 0110 0001 xxxx xxxx xxxx 1001 xxxx :GE */ | |
1224 | /* SSUB8 : cccc 0110 0001 xxxx xxxx xxxx 1111 xxxx :GE */ | |
1225 | /* QADD16 : cccc 0110 0010 xxxx xxxx xxxx 0001 xxxx : */ | |
1226 | /* QADDSUBX : cccc 0110 0010 xxxx xxxx xxxx 0011 xxxx : */ | |
1227 | /* QSUBADDX : cccc 0110 0010 xxxx xxxx xxxx 0101 xxxx : */ | |
1228 | /* QSUB16 : cccc 0110 0010 xxxx xxxx xxxx 0111 xxxx : */ | |
1229 | /* QADD8 : cccc 0110 0010 xxxx xxxx xxxx 1001 xxxx : */ | |
1230 | /* QSUB8 : cccc 0110 0010 xxxx xxxx xxxx 1111 xxxx : */ | |
1231 | /* SHADD16 : cccc 0110 0011 xxxx xxxx xxxx 0001 xxxx : */ | |
1232 | /* SHADDSUBX : cccc 0110 0011 xxxx xxxx xxxx 0011 xxxx : */ | |
1233 | /* SHSUBADDX : cccc 0110 0011 xxxx xxxx xxxx 0101 xxxx : */ | |
1234 | /* SHSUB16 : cccc 0110 0011 xxxx xxxx xxxx 0111 xxxx : */ | |
1235 | /* SHADD8 : cccc 0110 0011 xxxx xxxx xxxx 1001 xxxx : */ | |
1236 | /* SHSUB8 : cccc 0110 0011 xxxx xxxx xxxx 1111 xxxx : */ | |
1237 | /* UADD16 : cccc 0110 0101 xxxx xxxx xxxx 0001 xxxx :GE */ | |
1238 | /* UADDSUBX : cccc 0110 0101 xxxx xxxx xxxx 0011 xxxx :GE */ | |
1239 | /* USUBADDX : cccc 0110 0101 xxxx xxxx xxxx 0101 xxxx :GE */ | |
1240 | /* USUB16 : cccc 0110 0101 xxxx xxxx xxxx 0111 xxxx :GE */ | |
1241 | /* UADD8 : cccc 0110 0101 xxxx xxxx xxxx 1001 xxxx :GE */ | |
1242 | /* USUB8 : cccc 0110 0101 xxxx xxxx xxxx 1111 xxxx :GE */ | |
1243 | /* UQADD16 : cccc 0110 0110 xxxx xxxx xxxx 0001 xxxx : */ | |
1244 | /* UQADDSUBX : cccc 0110 0110 xxxx xxxx xxxx 0011 xxxx : */ | |
1245 | /* UQSUBADDX : cccc 0110 0110 xxxx xxxx xxxx 0101 xxxx : */ | |
1246 | /* UQSUB16 : cccc 0110 0110 xxxx xxxx xxxx 0111 xxxx : */ | |
1247 | /* UQADD8 : cccc 0110 0110 xxxx xxxx xxxx 1001 xxxx : */ | |
1248 | /* UQSUB8 : cccc 0110 0110 xxxx xxxx xxxx 1111 xxxx : */ | |
1249 | /* UHADD16 : cccc 0110 0111 xxxx xxxx xxxx 0001 xxxx : */ | |
1250 | /* UHADDSUBX : cccc 0110 0111 xxxx xxxx xxxx 0011 xxxx : */ | |
1251 | /* UHSUBADDX : cccc 0110 0111 xxxx xxxx xxxx 0101 xxxx : */ | |
1252 | /* UHSUB16 : cccc 0110 0111 xxxx xxxx xxxx 0111 xxxx : */ | |
1253 | /* UHADD8 : cccc 0110 0111 xxxx xxxx xxxx 1001 xxxx : */ | |
1254 | /* UHSUB8 : cccc 0110 0111 xxxx xxxx xxxx 1111 xxxx : */ | |
1255 | /* PKHBT : cccc 0110 1000 xxxx xxxx xxxx x001 xxxx : */ | |
1256 | /* PKHTB : cccc 0110 1000 xxxx xxxx xxxx x101 xxxx : */ | |
1257 | /* SXTAB16 : cccc 0110 1000 xxxx xxxx xxxx 0111 xxxx : */ | |
1258 | /* SXTB : cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx : */ | |
1259 | /* SXTAB : cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx : */ | |
1260 | /* SXTAH : cccc 0110 1011 xxxx xxxx xxxx 0111 xxxx : */ | |
1261 | /* UXTAB16 : cccc 0110 1100 xxxx xxxx xxxx 0111 xxxx : */ | |
1262 | /* UXTAB : cccc 0110 1110 xxxx xxxx xxxx 0111 xxxx : */ | |
1263 | /* UXTAH : cccc 0110 1111 xxxx xxxx xxxx 0111 xxxx : */ | |
1264 | return prep_emulate_rd12rn16rm0_wflags(insn, asi); | |
1265 | } | |
1266 | ||
1267 | static enum kprobe_insn __kprobes | |
1268 | space_cccc_0111__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |
1269 | { | |
1270 | /* Undef : cccc 0111 1111 xxxx xxxx xxxx 1111 xxxx */ | |
1271 | if ((insn & 0x0ff000f0) == 0x03f000f0) | |
1272 | return INSN_REJECTED; | |
1273 | ||
1274 | /* USADA8 : cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx */ | |
1275 | /* USAD8 : cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx */ | |
1276 | if ((insn & 0x0ff000f0) == 0x07800010) | |
1277 | return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); | |
1278 | ||
1279 | /* SMLALD : cccc 0111 0100 xxxx xxxx xxxx 00x1 xxxx */ | |
1280 | /* SMLSLD : cccc 0111 0100 xxxx xxxx xxxx 01x1 xxxx */ | |
1281 | if ((insn & 0x0ff00090) == 0x07400010) | |
1282 | return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, asi); | |
1283 | ||
1284 | /* SMLAD : cccc 0111 0000 xxxx xxxx xxxx 00x1 xxxx :Q */ | |
1285 | /* SMLSD : cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx :Q */ | |
1286 | /* SMMLA : cccc 0111 0101 xxxx xxxx xxxx 00x1 xxxx : */ | |
1287 | /* SMMLS : cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx : */ | |
1288 | if ((insn & 0x0ff00090) == 0x07000010 || | |
1289 | (insn & 0x0ff000d0) == 0x07500010 || | |
1290 | (insn & 0x0ff000d0) == 0x075000d0) | |
1291 | return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); | |
1292 | ||
1293 | /* SMUSD : cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx : */ | |
1294 | /* SMUAD : cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx :Q */ | |
1295 | /* SMMUL : cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx : */ | |
1296 | return prep_emulate_rd16rs8rm0_wflags(insn, asi); | |
1297 | } | |
1298 | ||
1299 | static enum kprobe_insn __kprobes | |
1300 | space_cccc_01xx(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |
1301 | { | |
1302 | /* LDR : cccc 01xx x0x1 xxxx xxxx xxxx xxxx xxxx */ | |
1303 | /* LDRB : cccc 01xx x1x1 xxxx xxxx xxxx xxxx xxxx */ | |
1304 | /* LDRBT : cccc 01x0 x111 xxxx xxxx xxxx xxxx xxxx */ | |
1305 | /* LDRT : cccc 01x0 x011 xxxx xxxx xxxx xxxx xxxx */ | |
1306 | /* STR : cccc 01xx x0x0 xxxx xxxx xxxx xxxx xxxx */ | |
1307 | /* STRB : cccc 01xx x1x0 xxxx xxxx xxxx xxxx xxxx */ | |
1308 | /* STRBT : cccc 01x0 x110 xxxx xxxx xxxx xxxx xxxx */ | |
1309 | /* STRT : cccc 01x0 x010 xxxx xxxx xxxx xxxx xxxx */ | |
1310 | return prep_emulate_ldr_str(insn, asi); | |
1311 | } | |
1312 | ||
1313 | static enum kprobe_insn __kprobes | |
1314 | space_cccc_100x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |
1315 | { | |
1316 | /* LDM(2) : cccc 100x x101 xxxx 0xxx xxxx xxxx xxxx */ | |
1317 | /* LDM(3) : cccc 100x x1x1 xxxx 1xxx xxxx xxxx xxxx */ | |
1318 | if ((insn & 0x0e708000) == 0x85000000 || | |
1319 | (insn & 0x0e508000) == 0x85010000) | |
1320 | return INSN_REJECTED; | |
1321 | ||
1322 | /* LDM(1) : cccc 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ | |
1323 | /* STM(1) : cccc 100x x0x0 xxxx xxxx xxxx xxxx xxxx */ | |
1324 | asi->insn[0] = truecc_insn(insn); | |
1325 | asi->insn_handler = ((insn & 0x108000) == 0x008000) ? /* STM & R15 */ | |
1326 | simulate_stm1_pc : simulate_ldm1stm1; | |
1327 | return INSN_GOOD; | |
1328 | } | |
1329 | ||
1330 | static enum kprobe_insn __kprobes | |
1331 | space_cccc_101x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |
1332 | { | |
1333 | /* B : cccc 1010 xxxx xxxx xxxx xxxx xxxx xxxx */ | |
1334 | /* BL : cccc 1011 xxxx xxxx xxxx xxxx xxxx xxxx */ | |
1335 | asi->insn[0] = truecc_insn(insn); | |
1336 | asi->insn_handler = simulate_bbl; | |
1337 | return INSN_GOOD; | |
1338 | } | |
1339 | ||
1340 | static enum kprobe_insn __kprobes | |
1341 | space_cccc_1100_010x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |
1342 | { | |
1343 | /* MCRR : cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */ | |
1344 | /* MRRC : cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */ | |
1345 | insn &= 0xfff00fff; | |
1346 | insn |= 0x00001000; /* Rn = r0, Rd = r1 */ | |
1347 | asi->insn[0] = insn; | |
1348 | asi->insn_handler = (insn & (1 << 20)) ? emulate_mrrc : emulate_mcrr; | |
1349 | return INSN_GOOD; | |
1350 | } | |
1351 | ||
1352 | static enum kprobe_insn __kprobes | |
1353 | space_cccc_110x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |
1354 | { | |
1355 | /* LDC : cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ | |
1356 | /* STC : cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ | |
1357 | insn &= 0xfff0ffff; /* Rn = r0 */ | |
1358 | asi->insn[0] = insn; | |
1359 | asi->insn_handler = emulate_ldcstc; | |
1360 | return INSN_GOOD; | |
1361 | } | |
1362 | ||
1363 | static enum kprobe_insn __kprobes | |
1364 | space_cccc_111x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |
1365 | { | |
1366 | /* BKPT : 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */ | |
1367 | /* SWI : cccc 1111 xxxx xxxx xxxx xxxx xxxx xxxx */ | |
1368 | if ((insn & 0xfff000f0) == 0xe1200070 || | |
1369 | (insn & 0x0f000000) == 0x0f000000) | |
1370 | return INSN_REJECTED; | |
1371 | ||
1372 | /* CDP : cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ | |
1373 | if ((insn & 0x0f000010) == 0x0e000000) { | |
1374 | asi->insn[0] = insn; | |
1375 | asi->insn_handler = emulate_none; | |
1376 | return INSN_GOOD; | |
1377 | } | |
1378 | ||
1379 | /* MCR : cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ | |
1380 | /* MRC : cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ | |
1381 | insn &= 0xffff0fff; /* Rd = r0 */ | |
1382 | asi->insn[0] = insn; | |
1383 | asi->insn_handler = (insn & (1 << 20)) ? emulate_rd12 : emulate_ird12; | |
1384 | return INSN_GOOD; | |
1385 | } | |
1386 | ||
1387 | /* Return: | |
1388 | * INSN_REJECTED If instruction is one not allowed to kprobe, | |
1389 | * INSN_GOOD If instruction is supported and uses instruction slot, | |
1390 | * INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot. | |
1391 | * | |
1392 | * For instructions we don't want to kprobe (INSN_REJECTED return result): | |
1393 | * These are generally ones that modify the processor state making | |
1394 | * them "hard" to simulate such as switches processor modes or | |
1395 | * make accesses in alternate modes. Any of these could be simulated | |
1396 | * if the work was put into it, but low return considering they | |
1397 | * should also be very rare. | |
1398 | */ | |
1399 | enum kprobe_insn __kprobes | |
1400 | arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |
1401 | { | |
1402 | asi->insn[1] = KPROBE_RETURN_INSTRUCTION; | |
1403 | ||
1404 | if ((insn & 0xf0000000) == 0xf0000000) { | |
1405 | ||
1406 | return space_1111(insn, asi); | |
1407 | ||
1408 | } else if ((insn & 0x0e000000) == 0x00000000) { | |
1409 | ||
1410 | return space_cccc_000x(insn, asi); | |
1411 | ||
1412 | } else if ((insn & 0x0e000000) == 0x02000000) { | |
1413 | ||
1414 | return space_cccc_001x(insn, asi); | |
1415 | ||
1416 | } else if ((insn & 0x0f000010) == 0x06000010) { | |
1417 | ||
1418 | return space_cccc_0110__1(insn, asi); | |
1419 | ||
1420 | } else if ((insn & 0x0f000010) == 0x07000010) { | |
1421 | ||
1422 | return space_cccc_0111__1(insn, asi); | |
1423 | ||
1424 | } else if ((insn & 0x0c000000) == 0x04000000) { | |
1425 | ||
1426 | return space_cccc_01xx(insn, asi); | |
1427 | ||
1428 | } else if ((insn & 0x0e000000) == 0x08000000) { | |
1429 | ||
1430 | return space_cccc_100x(insn, asi); | |
1431 | ||
1432 | } else if ((insn & 0x0e000000) == 0x0a000000) { | |
1433 | ||
1434 | return space_cccc_101x(insn, asi); | |
1435 | ||
1436 | } else if ((insn & 0x0fe00000) == 0x0c400000) { | |
1437 | ||
1438 | return space_cccc_1100_010x(insn, asi); | |
1439 | ||
5a5af730 | 1440 | } else if ((insn & 0x0e000000) == 0x0c000000) { |
35aa1df4 QB |
1441 | |
1442 | return space_cccc_110x(insn, asi); | |
1443 | ||
1444 | } | |
1445 | ||
1446 | return space_cccc_111x(insn, asi); | |
1447 | } | |
1448 | ||
1449 | void __init arm_kprobe_decode_init(void) | |
1450 | { | |
1451 | find_str_pc_offset(); | |
1452 | } | |
1453 | ||
1454 | ||
1455 | /* | |
1456 | * All ARM instructions listed below. | |
1457 | * | |
1458 | * Instructions and their general purpose registers are given. | |
1459 | * If a particular register may not use R15, it is prefixed with a "!". | |
1460 | * If marked with a "*" means the value returned by reading R15 | |
1461 | * is implementation defined. | |
1462 | * | |
1463 | * ADC/ADD/AND/BIC/CMN/CMP/EOR/MOV/MVN/ORR/RSB/RSC/SBC/SUB/TEQ | |
1464 | * TST: Rd, Rn, Rm, !Rs | |
1465 | * BX: Rm | |
1466 | * BLX(2): !Rm | |
1467 | * BX: Rm (R15 legal, but discouraged) | |
1468 | * BXJ: !Rm, | |
1469 | * CLZ: !Rd, !Rm | |
1470 | * CPY: Rd, Rm | |
1471 | * LDC/2,STC/2 immediate offset & unindex: Rn | |
1472 | * LDC/2,STC/2 immediate pre/post-indexed: !Rn | |
1473 | * LDM(1/3): !Rn, register_list | |
1474 | * LDM(2): !Rn, !register_list | |
1475 | * LDR,STR,PLD immediate offset: Rd, Rn | |
1476 | * LDR,STR,PLD register offset: Rd, Rn, !Rm | |
1477 | * LDR,STR,PLD scaled register offset: Rd, !Rn, !Rm | |
1478 | * LDR,STR immediate pre/post-indexed: Rd, !Rn | |
1479 | * LDR,STR register pre/post-indexed: Rd, !Rn, !Rm | |
1480 | * LDR,STR scaled register pre/post-indexed: Rd, !Rn, !Rm | |
1481 | * LDRB,STRB immediate offset: !Rd, Rn | |
1482 | * LDRB,STRB register offset: !Rd, Rn, !Rm | |
1483 | * LDRB,STRB scaled register offset: !Rd, !Rn, !Rm | |
1484 | * LDRB,STRB immediate pre/post-indexed: !Rd, !Rn | |
1485 | * LDRB,STRB register pre/post-indexed: !Rd, !Rn, !Rm | |
1486 | * LDRB,STRB scaled register pre/post-indexed: !Rd, !Rn, !Rm | |
1487 | * LDRT,LDRBT,STRBT immediate pre/post-indexed: !Rd, !Rn | |
1488 | * LDRT,LDRBT,STRBT register pre/post-indexed: !Rd, !Rn, !Rm | |
1489 | * LDRT,LDRBT,STRBT scaled register pre/post-indexed: !Rd, !Rn, !Rm | |
1490 | * LDRH/SH/SB/D,STRH/SH/SB/D immediate offset: !Rd, Rn | |
1491 | * LDRH/SH/SB/D,STRH/SH/SB/D register offset: !Rd, Rn, !Rm | |
1492 | * LDRH/SH/SB/D,STRH/SH/SB/D immediate pre/post-indexed: !Rd, !Rn | |
1493 | * LDRH/SH/SB/D,STRH/SH/SB/D register pre/post-indexed: !Rd, !Rn, !Rm | |
1494 | * LDREX: !Rd, !Rn | |
1495 | * MCR/2: !Rd | |
1496 | * MCRR/2,MRRC/2: !Rd, !Rn | |
1497 | * MLA: !Rd, !Rn, !Rm, !Rs | |
1498 | * MOV: Rd | |
1499 | * MRC/2: !Rd (if Rd==15, only changes cond codes, not the register) | |
1500 | * MRS,MSR: !Rd | |
1501 | * MUL: !Rd, !Rm, !Rs | |
1502 | * PKH{BT,TB}: !Rd, !Rn, !Rm | |
1503 | * QDADD,[U]QADD/16/8/SUBX: !Rd, !Rm, !Rn | |
1504 | * QDSUB,[U]QSUB/16/8/ADDX: !Rd, !Rm, !Rn | |
1505 | * REV/16/SH: !Rd, !Rm | |
1506 | * RFE: !Rn | |
1507 | * {S,U}[H]ADD{16,8,SUBX},{S,U}[H]SUB{16,8,ADDX}: !Rd, !Rn, !Rm | |
1508 | * SEL: !Rd, !Rn, !Rm | |
1509 | * SMLA<x><y>,SMLA{D,W<y>},SMLSD,SMML{A,S}: !Rd, !Rn, !Rm, !Rs | |
1510 | * SMLAL<x><y>,SMLA{D,LD},SMLSLD,SMMULL,SMULW<y>: !RdHi, !RdLo, !Rm, !Rs | |
1511 | * SMMUL,SMUAD,SMUL<x><y>,SMUSD: !Rd, !Rm, !Rs | |
1512 | * SSAT/16: !Rd, !Rm | |
1513 | * STM(1/2): !Rn, register_list* (R15 in reg list not recommended) | |
1514 | * STRT immediate pre/post-indexed: Rd*, !Rn | |
1515 | * STRT register pre/post-indexed: Rd*, !Rn, !Rm | |
1516 | * STRT scaled register pre/post-indexed: Rd*, !Rn, !Rm | |
1517 | * STREX: !Rd, !Rn, !Rm | |
1518 | * SWP/B: !Rd, !Rn, !Rm | |
1519 | * {S,U}XTA{B,B16,H}: !Rd, !Rn, !Rm | |
1520 | * {S,U}XT{B,B16,H}: !Rd, !Rm | |
1521 | * UM{AA,LA,UL}L: !RdHi, !RdLo, !Rm, !Rs | |
1522 | * USA{D8,A8,T,T16}: !Rd, !Rm, !Rs | |
1523 | * | |
1524 | * May transfer control by writing R15 (possible mode changes or alternate | |
1525 | * mode accesses marked by "*"): | |
1526 | * ALU op (* with s-bit), B, BL, BKPT, BLX(1/2), BX, BXJ, CPS*, CPY, | |
1527 | * LDM(1), LDM(2/3)*, LDR, MOV, RFE*, SWI* | |
1528 | * | |
1529 | * Instructions that do not take general registers, nor transfer control: | |
1530 | * CDP/2, SETEND, SRS* | |
1531 | */ |