blob: 8d4464f9471ba8f2df6278db84a06c5212abd503 [file] [log] [blame]
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001/*
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.
Quentin Barnes35aa1df2007-06-11 22:20:10 +000037 *
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
Jon Medhurst221bf152011-04-20 10:52:38 +010064#include "kprobes.h"
65
Quentin Barnes35aa1df2007-06-11 22:20:10 +000066#define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit)))))
67
68#define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25)
69
Jon Medhurst983ebd92011-04-07 13:25:17 +010070#define is_r15(insn, bitpos) (((insn) & (0xf << bitpos)) == (0xf << bitpos))
71
Jon Medhurst54823ac2011-04-08 15:32:55 +010072/*
73 * Test if load/store instructions writeback the address register.
74 * if P (bit 24) == 0 or W (bit 21) == 1
75 */
76#define is_writeback(insn) ((insn ^ 0x01000000) & 0x01200000)
77
Quentin Barnes35aa1df2007-06-11 22:20:10 +000078#define PSR_fs (PSR_f|PSR_s)
79
80#define KPROBE_RETURN_INSTRUCTION 0xe1a0f00e /* mov pc, lr */
Quentin Barnes35aa1df2007-06-11 22:20:10 +000081
82typedef long (insn_0arg_fn_t)(void);
83typedef long (insn_1arg_fn_t)(long);
84typedef long (insn_2arg_fn_t)(long, long);
85typedef long (insn_3arg_fn_t)(long, long, long);
86typedef long (insn_4arg_fn_t)(long, long, long, long);
87typedef long long (insn_llret_0arg_fn_t)(void);
88typedef long long (insn_llret_3arg_fn_t)(long, long, long);
89typedef long long (insn_llret_4arg_fn_t)(long, long, long, long);
90
91union reg_pair {
92 long long dr;
93#ifdef __LITTLE_ENDIAN
94 struct { long r0, r1; };
95#else
96 struct { long r1, r0; };
97#endif
98};
99
100/*
101 * For STR and STM instructions, an ARM core may choose to use either
102 * a +8 or a +12 displacement from the current instruction's address.
103 * Whichever value is chosen for a given core, it must be the same for
104 * both instructions and may not change. This function measures it.
105 */
106
107static int str_pc_offset;
108
109static void __init find_str_pc_offset(void)
110{
111 int addr, scratch, ret;
112
113 __asm__ (
114 "sub %[ret], pc, #4 \n\t"
115 "str pc, %[addr] \n\t"
116 "ldr %[scr], %[addr] \n\t"
117 "sub %[ret], %[scr], %[ret] \n\t"
118 : [ret] "=r" (ret), [scr] "=r" (scratch), [addr] "+m" (addr));
119
120 str_pc_offset = ret;
121}
122
123/*
124 * The insnslot_?arg_r[w]flags() functions below are to keep the
125 * msr -> *fn -> mrs instruction sequences indivisible so that
126 * the state of the CPSR flags aren't inadvertently modified
127 * just before or just after the call.
128 */
129
130static inline long __kprobes
131insnslot_0arg_rflags(long cpsr, insn_0arg_fn_t *fn)
132{
133 register long ret asm("r0");
134
135 __asm__ __volatile__ (
136 "msr cpsr_fs, %[cpsr] \n\t"
137 "mov lr, pc \n\t"
138 "mov pc, %[fn] \n\t"
139 : "=r" (ret)
140 : [cpsr] "r" (cpsr), [fn] "r" (fn)
141 : "lr", "cc"
142 );
143 return ret;
144}
145
146static inline long long __kprobes
147insnslot_llret_0arg_rflags(long cpsr, insn_llret_0arg_fn_t *fn)
148{
149 register long ret0 asm("r0");
150 register long ret1 asm("r1");
151 union reg_pair fnr;
152
153 __asm__ __volatile__ (
154 "msr cpsr_fs, %[cpsr] \n\t"
155 "mov lr, pc \n\t"
156 "mov pc, %[fn] \n\t"
157 : "=r" (ret0), "=r" (ret1)
158 : [cpsr] "r" (cpsr), [fn] "r" (fn)
159 : "lr", "cc"
160 );
161 fnr.r0 = ret0;
162 fnr.r1 = ret1;
163 return fnr.dr;
164}
165
166static inline long __kprobes
167insnslot_1arg_rflags(long r0, long cpsr, insn_1arg_fn_t *fn)
168{
169 register long rr0 asm("r0") = r0;
170 register long ret asm("r0");
171
172 __asm__ __volatile__ (
173 "msr cpsr_fs, %[cpsr] \n\t"
174 "mov lr, pc \n\t"
175 "mov pc, %[fn] \n\t"
176 : "=r" (ret)
177 : "0" (rr0), [cpsr] "r" (cpsr), [fn] "r" (fn)
178 : "lr", "cc"
179 );
180 return ret;
181}
182
183static inline long __kprobes
184insnslot_2arg_rflags(long r0, long r1, long cpsr, insn_2arg_fn_t *fn)
185{
186 register long rr0 asm("r0") = r0;
187 register long rr1 asm("r1") = r1;
188 register long ret asm("r0");
189
190 __asm__ __volatile__ (
191 "msr cpsr_fs, %[cpsr] \n\t"
192 "mov lr, pc \n\t"
193 "mov pc, %[fn] \n\t"
194 : "=r" (ret)
195 : "0" (rr0), "r" (rr1),
196 [cpsr] "r" (cpsr), [fn] "r" (fn)
197 : "lr", "cc"
198 );
199 return ret;
200}
201
202static inline long __kprobes
203insnslot_3arg_rflags(long r0, long r1, long r2, long cpsr, insn_3arg_fn_t *fn)
204{
205 register long rr0 asm("r0") = r0;
206 register long rr1 asm("r1") = r1;
207 register long rr2 asm("r2") = r2;
208 register long ret asm("r0");
209
210 __asm__ __volatile__ (
211 "msr cpsr_fs, %[cpsr] \n\t"
212 "mov lr, pc \n\t"
213 "mov pc, %[fn] \n\t"
214 : "=r" (ret)
215 : "0" (rr0), "r" (rr1), "r" (rr2),
216 [cpsr] "r" (cpsr), [fn] "r" (fn)
217 : "lr", "cc"
218 );
219 return ret;
220}
221
222static inline long long __kprobes
223insnslot_llret_3arg_rflags(long r0, long r1, long r2, long cpsr,
224 insn_llret_3arg_fn_t *fn)
225{
226 register long rr0 asm("r0") = r0;
227 register long rr1 asm("r1") = r1;
228 register long rr2 asm("r2") = r2;
229 register long ret0 asm("r0");
230 register long ret1 asm("r1");
231 union reg_pair fnr;
232
233 __asm__ __volatile__ (
234 "msr cpsr_fs, %[cpsr] \n\t"
235 "mov lr, pc \n\t"
236 "mov pc, %[fn] \n\t"
237 : "=r" (ret0), "=r" (ret1)
238 : "0" (rr0), "r" (rr1), "r" (rr2),
239 [cpsr] "r" (cpsr), [fn] "r" (fn)
240 : "lr", "cc"
241 );
242 fnr.r0 = ret0;
243 fnr.r1 = ret1;
244 return fnr.dr;
245}
246
247static inline long __kprobes
248insnslot_4arg_rflags(long r0, long r1, long r2, long r3, long cpsr,
249 insn_4arg_fn_t *fn)
250{
251 register long rr0 asm("r0") = r0;
252 register long rr1 asm("r1") = r1;
253 register long rr2 asm("r2") = r2;
254 register long rr3 asm("r3") = r3;
255 register long ret asm("r0");
256
257 __asm__ __volatile__ (
258 "msr cpsr_fs, %[cpsr] \n\t"
259 "mov lr, pc \n\t"
260 "mov pc, %[fn] \n\t"
261 : "=r" (ret)
262 : "0" (rr0), "r" (rr1), "r" (rr2), "r" (rr3),
263 [cpsr] "r" (cpsr), [fn] "r" (fn)
264 : "lr", "cc"
265 );
266 return ret;
267}
268
269static inline long __kprobes
270insnslot_1arg_rwflags(long r0, long *cpsr, insn_1arg_fn_t *fn)
271{
272 register long rr0 asm("r0") = r0;
273 register long ret asm("r0");
274 long oldcpsr = *cpsr;
275 long newcpsr;
276
277 __asm__ __volatile__ (
278 "msr cpsr_fs, %[oldcpsr] \n\t"
279 "mov lr, pc \n\t"
280 "mov pc, %[fn] \n\t"
281 "mrs %[newcpsr], cpsr \n\t"
282 : "=r" (ret), [newcpsr] "=r" (newcpsr)
283 : "0" (rr0), [oldcpsr] "r" (oldcpsr), [fn] "r" (fn)
284 : "lr", "cc"
285 );
286 *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs);
287 return ret;
288}
289
290static inline long __kprobes
291insnslot_2arg_rwflags(long r0, long r1, long *cpsr, insn_2arg_fn_t *fn)
292{
293 register long rr0 asm("r0") = r0;
294 register long rr1 asm("r1") = r1;
295 register long ret asm("r0");
296 long oldcpsr = *cpsr;
297 long newcpsr;
298
299 __asm__ __volatile__ (
300 "msr cpsr_fs, %[oldcpsr] \n\t"
301 "mov lr, pc \n\t"
302 "mov pc, %[fn] \n\t"
303 "mrs %[newcpsr], cpsr \n\t"
304 : "=r" (ret), [newcpsr] "=r" (newcpsr)
305 : "0" (rr0), "r" (rr1), [oldcpsr] "r" (oldcpsr), [fn] "r" (fn)
306 : "lr", "cc"
307 );
308 *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs);
309 return ret;
310}
311
312static inline long __kprobes
313insnslot_3arg_rwflags(long r0, long r1, long r2, long *cpsr,
314 insn_3arg_fn_t *fn)
315{
316 register long rr0 asm("r0") = r0;
317 register long rr1 asm("r1") = r1;
318 register long rr2 asm("r2") = r2;
319 register long ret asm("r0");
320 long oldcpsr = *cpsr;
321 long newcpsr;
322
323 __asm__ __volatile__ (
324 "msr cpsr_fs, %[oldcpsr] \n\t"
325 "mov lr, pc \n\t"
326 "mov pc, %[fn] \n\t"
327 "mrs %[newcpsr], cpsr \n\t"
328 : "=r" (ret), [newcpsr] "=r" (newcpsr)
329 : "0" (rr0), "r" (rr1), "r" (rr2),
330 [oldcpsr] "r" (oldcpsr), [fn] "r" (fn)
331 : "lr", "cc"
332 );
333 *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs);
334 return ret;
335}
336
337static inline long __kprobes
338insnslot_4arg_rwflags(long r0, long r1, long r2, long r3, long *cpsr,
339 insn_4arg_fn_t *fn)
340{
341 register long rr0 asm("r0") = r0;
342 register long rr1 asm("r1") = r1;
343 register long rr2 asm("r2") = r2;
344 register long rr3 asm("r3") = r3;
345 register long ret asm("r0");
346 long oldcpsr = *cpsr;
347 long newcpsr;
348
349 __asm__ __volatile__ (
350 "msr cpsr_fs, %[oldcpsr] \n\t"
351 "mov lr, pc \n\t"
352 "mov pc, %[fn] \n\t"
353 "mrs %[newcpsr], cpsr \n\t"
354 : "=r" (ret), [newcpsr] "=r" (newcpsr)
355 : "0" (rr0), "r" (rr1), "r" (rr2), "r" (rr3),
356 [oldcpsr] "r" (oldcpsr), [fn] "r" (fn)
357 : "lr", "cc"
358 );
359 *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs);
360 return ret;
361}
362
363static inline long long __kprobes
364insnslot_llret_4arg_rwflags(long r0, long r1, long r2, long r3, long *cpsr,
365 insn_llret_4arg_fn_t *fn)
366{
367 register long rr0 asm("r0") = r0;
368 register long rr1 asm("r1") = r1;
369 register long rr2 asm("r2") = r2;
370 register long rr3 asm("r3") = r3;
371 register long ret0 asm("r0");
372 register long ret1 asm("r1");
373 long oldcpsr = *cpsr;
374 long newcpsr;
375 union reg_pair fnr;
376
377 __asm__ __volatile__ (
378 "msr cpsr_fs, %[oldcpsr] \n\t"
379 "mov lr, pc \n\t"
380 "mov pc, %[fn] \n\t"
381 "mrs %[newcpsr], cpsr \n\t"
382 : "=r" (ret0), "=r" (ret1), [newcpsr] "=r" (newcpsr)
383 : "0" (rr0), "r" (rr1), "r" (rr2), "r" (rr3),
384 [oldcpsr] "r" (oldcpsr), [fn] "r" (fn)
385 : "lr", "cc"
386 );
387 *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs);
388 fnr.r0 = ret0;
389 fnr.r1 = ret1;
390 return fnr.dr;
391}
392
393/*
394 * To avoid the complications of mimicing single-stepping on a
395 * processor without a Next-PC or a single-step mode, and to
396 * avoid having to deal with the side-effects of boosting, we
397 * simulate or emulate (almost) all ARM instructions.
398 *
399 * "Simulation" is where the instruction's behavior is duplicated in
400 * C code. "Emulation" is where the original instruction is rewritten
401 * and executed, often by altering its registers.
402 *
403 * By having all behavior of the kprobe'd instruction completed before
404 * returning from the kprobe_handler(), all locks (scheduler and
405 * interrupt) can safely be released. There is no need for secondary
406 * breakpoints, no race with MP or preemptable kernels, nor having to
407 * clean up resources counts at a later time impacting overall system
408 * performance. By rewriting the instruction, only the minimum registers
409 * need to be loaded and saved back optimizing performance.
410 *
411 * Calling the insnslot_*_rwflags version of a function doesn't hurt
412 * anything even when the CPSR flags aren't updated by the
413 * instruction. It's just a little slower in return for saving
414 * a little space by not having a duplicate function that doesn't
415 * update the flags. (The same optimization can be said for
416 * instructions that do or don't perform register writeback)
417 * Also, instructions can either read the flags, only write the
418 * flags, or read and write the flags. To save combinations
419 * rather than for sheer performance, flag functions just assume
420 * read and write of flags.
421 */
422
423static void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs)
424{
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000425 kprobe_opcode_t insn = p->opcode;
426 long iaddr = (long)p->addr;
427 int disp = branch_displacement(insn);
428
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000429 if (insn & (1 << 24))
430 regs->ARM_lr = iaddr + 4;
431
432 regs->ARM_pc = iaddr + 8 + disp;
433}
434
435static void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs)
436{
437 kprobe_opcode_t insn = p->opcode;
438 long iaddr = (long)p->addr;
439 int disp = branch_displacement(insn);
440
441 regs->ARM_lr = iaddr + 4;
442 regs->ARM_pc = iaddr + 8 + disp + ((insn >> 23) & 0x2);
443 regs->ARM_cpsr |= PSR_T_BIT;
444}
445
446static void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs)
447{
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000448 kprobe_opcode_t insn = p->opcode;
449 int rm = insn & 0xf;
450 long rmv = regs->uregs[rm];
451
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000452 if (insn & (1 << 5))
453 regs->ARM_lr = (long)p->addr + 4;
454
455 regs->ARM_pc = rmv & ~0x1;
456 regs->ARM_cpsr &= ~PSR_T_BIT;
457 if (rmv & 0x1)
458 regs->ARM_cpsr |= PSR_T_BIT;
459}
460
Jon Medhurstc412aba2011-04-07 13:25:16 +0100461static void __kprobes simulate_mrs(struct kprobe *p, struct pt_regs *regs)
462{
463 kprobe_opcode_t insn = p->opcode;
464 int rd = (insn >> 12) & 0xf;
465 unsigned long mask = 0xf8ff03df; /* Mask out execution state */
466 regs->uregs[rd] = regs->ARM_cpsr & mask;
467}
468
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000469static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs)
470{
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000471 kprobe_opcode_t insn = p->opcode;
472 int rn = (insn >> 16) & 0xf;
473 int lbit = insn & (1 << 20);
474 int wbit = insn & (1 << 21);
475 int ubit = insn & (1 << 23);
476 int pbit = insn & (1 << 24);
477 long *addr = (long *)regs->uregs[rn];
478 int reg_bit_vector;
479 int reg_count;
480
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000481 reg_count = 0;
482 reg_bit_vector = insn & 0xffff;
483 while (reg_bit_vector) {
484 reg_bit_vector &= (reg_bit_vector - 1);
485 ++reg_count;
486 }
487
488 if (!ubit)
489 addr -= reg_count;
Nicolas Pitre2d4b6c92008-08-21 23:22:49 +0100490 addr += (!pbit == !ubit);
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000491
492 reg_bit_vector = insn & 0xffff;
493 while (reg_bit_vector) {
494 int reg = __ffs(reg_bit_vector);
495 reg_bit_vector &= (reg_bit_vector - 1);
496 if (lbit)
497 regs->uregs[reg] = *addr++;
498 else
499 *addr++ = regs->uregs[reg];
500 }
501
502 if (wbit) {
503 if (!ubit)
504 addr -= reg_count;
Nicolas Pitre2d4b6c92008-08-21 23:22:49 +0100505 addr -= (!pbit == !ubit);
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000506 regs->uregs[rn] = (long)addr;
507 }
508}
509
510static void __kprobes simulate_stm1_pc(struct kprobe *p, struct pt_regs *regs)
511{
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000512 regs->ARM_pc = (long)p->addr + str_pc_offset;
513 simulate_ldm1stm1(p, regs);
514 regs->ARM_pc = (long)p->addr + 4;
515}
516
517static void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs)
518{
519 regs->uregs[12] = regs->uregs[13];
520}
521
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000522static void __kprobes emulate_ldrd(struct kprobe *p, struct pt_regs *regs)
523{
524 insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0];
525 kprobe_opcode_t insn = p->opcode;
Viktor Rosendahlcf3cc1a2011-03-28 18:56:05 +0300526 long ppc = (long)p->addr + 8;
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000527 int rd = (insn >> 12) & 0xf;
528 int rn = (insn >> 16) & 0xf;
529 int rm = insn & 0xf; /* rm may be invalid, don't care. */
Viktor Rosendahlcf3cc1a2011-03-28 18:56:05 +0300530 long rmv = (rm == 15) ? ppc : regs->uregs[rm];
531 long rnv = (rn == 15) ? ppc : regs->uregs[rn];
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000532
533 /* Not following the C calling convention here, so need asm(). */
534 __asm__ __volatile__ (
535 "ldr r0, %[rn] \n\t"
536 "ldr r1, %[rm] \n\t"
537 "msr cpsr_fs, %[cpsr]\n\t"
538 "mov lr, pc \n\t"
539 "mov pc, %[i_fn] \n\t"
540 "str r0, %[rn] \n\t" /* in case of writeback */
541 "str r2, %[rd0] \n\t"
542 "str r3, %[rd1] \n\t"
Viktor Rosendahlcf3cc1a2011-03-28 18:56:05 +0300543 : [rn] "+m" (rnv),
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000544 [rd0] "=m" (regs->uregs[rd]),
545 [rd1] "=m" (regs->uregs[rd+1])
Viktor Rosendahlcf3cc1a2011-03-28 18:56:05 +0300546 : [rm] "m" (rmv),
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000547 [cpsr] "r" (regs->ARM_cpsr),
548 [i_fn] "r" (i_fn)
549 : "r0", "r1", "r2", "r3", "lr", "cc"
550 );
Jon Medhurst5c6b76f2011-04-08 15:32:56 +0100551 if (is_writeback(insn))
552 regs->uregs[rn] = rnv;
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000553}
554
555static void __kprobes emulate_strd(struct kprobe *p, struct pt_regs *regs)
556{
557 insn_4arg_fn_t *i_fn = (insn_4arg_fn_t *)&p->ainsn.insn[0];
558 kprobe_opcode_t insn = p->opcode;
Viktor Rosendahlcf3cc1a2011-03-28 18:56:05 +0300559 long ppc = (long)p->addr + 8;
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000560 int rd = (insn >> 12) & 0xf;
561 int rn = (insn >> 16) & 0xf;
562 int rm = insn & 0xf;
Viktor Rosendahlcf3cc1a2011-03-28 18:56:05 +0300563 long rnv = (rn == 15) ? ppc : regs->uregs[rn];
564 /* rm/rmv may be invalid, don't care. */
565 long rmv = (rm == 15) ? ppc : regs->uregs[rm];
566 long rnv_wb;
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000567
Viktor Rosendahlcf3cc1a2011-03-28 18:56:05 +0300568 rnv_wb = insnslot_4arg_rflags(rnv, rmv, regs->uregs[rd],
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000569 regs->uregs[rd+1],
570 regs->ARM_cpsr, i_fn);
Jon Medhurst5c6b76f2011-04-08 15:32:56 +0100571 if (is_writeback(insn))
572 regs->uregs[rn] = rnv_wb;
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000573}
574
575static void __kprobes emulate_ldr(struct kprobe *p, struct pt_regs *regs)
576{
577 insn_llret_3arg_fn_t *i_fn = (insn_llret_3arg_fn_t *)&p->ainsn.insn[0];
578 kprobe_opcode_t insn = p->opcode;
Nicolas Pitre0ebe25f2010-07-14 05:21:22 +0100579 long ppc = (long)p->addr + 8;
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000580 union reg_pair fnr;
581 int rd = (insn >> 12) & 0xf;
582 int rn = (insn >> 16) & 0xf;
583 int rm = insn & 0xf;
584 long rdv;
Nicolas Pitre0ebe25f2010-07-14 05:21:22 +0100585 long rnv = (rn == 15) ? ppc : regs->uregs[rn];
586 long rmv = (rm == 15) ? ppc : regs->uregs[rm];
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000587 long cpsr = regs->ARM_cpsr;
588
589 fnr.dr = insnslot_llret_3arg_rflags(rnv, 0, rmv, cpsr, i_fn);
Viktor Rosendahl0652f062011-03-26 18:11:01 +0100590 if (rn != 15)
591 regs->uregs[rn] = fnr.r0; /* Save Rn in case of writeback. */
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000592 rdv = fnr.r1;
593
594 if (rd == 15) {
595#if __LINUX_ARM_ARCH__ >= 5
596 cpsr &= ~PSR_T_BIT;
597 if (rdv & 0x1)
598 cpsr |= PSR_T_BIT;
599 regs->ARM_cpsr = cpsr;
600 rdv &= ~0x1;
601#else
602 rdv &= ~0x2;
603#endif
604 }
605 regs->uregs[rd] = rdv;
606}
607
608static void __kprobes emulate_str(struct kprobe *p, struct pt_regs *regs)
609{
610 insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0];
611 kprobe_opcode_t insn = p->opcode;
612 long iaddr = (long)p->addr;
613 int rd = (insn >> 12) & 0xf;
614 int rn = (insn >> 16) & 0xf;
615 int rm = insn & 0xf;
616 long rdv = (rd == 15) ? iaddr + str_pc_offset : regs->uregs[rd];
617 long rnv = (rn == 15) ? iaddr + 8 : regs->uregs[rn];
618 long rmv = regs->uregs[rm]; /* rm/rmv may be invalid, don't care. */
Viktor Rosendahl0652f062011-03-26 18:11:01 +0100619 long rnv_wb;
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000620
Viktor Rosendahl0652f062011-03-26 18:11:01 +0100621 rnv_wb = insnslot_3arg_rflags(rnv, rdv, rmv, regs->ARM_cpsr, i_fn);
622 if (rn != 15)
623 regs->uregs[rn] = rnv_wb; /* Save Rn in case of writeback. */
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000624}
625
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000626static void __kprobes emulate_sat(struct kprobe *p, struct pt_regs *regs)
627{
628 insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
629 kprobe_opcode_t insn = p->opcode;
630 int rd = (insn >> 12) & 0xf;
631 int rm = insn & 0xf;
632 long rmv = regs->uregs[rm];
633
634 /* Writes Q flag */
635 regs->uregs[rd] = insnslot_1arg_rwflags(rmv, &regs->ARM_cpsr, i_fn);
636}
637
638static void __kprobes emulate_sel(struct kprobe *p, struct pt_regs *regs)
639{
640 insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0];
641 kprobe_opcode_t insn = p->opcode;
642 int rd = (insn >> 12) & 0xf;
643 int rn = (insn >> 16) & 0xf;
644 int rm = insn & 0xf;
645 long rnv = regs->uregs[rn];
646 long rmv = regs->uregs[rm];
647
648 /* Reads GE bits */
649 regs->uregs[rd] = insnslot_2arg_rflags(rnv, rmv, regs->ARM_cpsr, i_fn);
650}
651
652static void __kprobes emulate_none(struct kprobe *p, struct pt_regs *regs)
653{
654 insn_0arg_fn_t *i_fn = (insn_0arg_fn_t *)&p->ainsn.insn[0];
655
656 insnslot_0arg_rflags(regs->ARM_cpsr, i_fn);
657}
658
Jon Medhurst41713d12011-04-18 08:53:57 +0100659static void __kprobes emulate_nop(struct kprobe *p, struct pt_regs *regs)
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000660{
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000661}
662
Jon Medhurstc9836772011-04-19 10:52:17 +0100663static void __kprobes
664emulate_rd12_modify(struct kprobe *p, struct pt_regs *regs)
665{
666 insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
667 kprobe_opcode_t insn = p->opcode;
668 int rd = (insn >> 12) & 0xf;
669 long rdv = regs->uregs[rd];
670
671 regs->uregs[rd] = insnslot_1arg_rflags(rdv, regs->ARM_cpsr, i_fn);
672}
673
Jon Medhurst20e81552011-04-19 10:52:18 +0100674static void __kprobes
675emulate_rd12rn0_modify(struct kprobe *p, struct pt_regs *regs)
676{
677 insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0];
678 kprobe_opcode_t insn = p->opcode;
679 int rd = (insn >> 12) & 0xf;
680 int rn = insn & 0xf;
681 long rdv = regs->uregs[rd];
682 long rnv = regs->uregs[rn];
683
684 regs->uregs[rd] = insnslot_2arg_rflags(rdv, rnv, regs->ARM_cpsr, i_fn);
685}
686
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000687static void __kprobes emulate_rd12rm0(struct kprobe *p, struct pt_regs *regs)
688{
689 insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
690 kprobe_opcode_t insn = p->opcode;
691 int rd = (insn >> 12) & 0xf;
692 int rm = insn & 0xf;
693 long rmv = regs->uregs[rm];
694
695 regs->uregs[rd] = insnslot_1arg_rflags(rmv, regs->ARM_cpsr, i_fn);
696}
697
698static void __kprobes
699emulate_rd12rn16rm0_rwflags(struct kprobe *p, struct pt_regs *regs)
700{
701 insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0];
702 kprobe_opcode_t insn = p->opcode;
703 int rd = (insn >> 12) & 0xf;
704 int rn = (insn >> 16) & 0xf;
705 int rm = insn & 0xf;
706 long rnv = regs->uregs[rn];
707 long rmv = regs->uregs[rm];
708
709 regs->uregs[rd] =
710 insnslot_2arg_rwflags(rnv, rmv, &regs->ARM_cpsr, i_fn);
711}
712
713static void __kprobes
714emulate_rd16rn12rs8rm0_rwflags(struct kprobe *p, struct pt_regs *regs)
715{
716 insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0];
717 kprobe_opcode_t insn = p->opcode;
718 int rd = (insn >> 16) & 0xf;
719 int rn = (insn >> 12) & 0xf;
720 int rs = (insn >> 8) & 0xf;
721 int rm = insn & 0xf;
722 long rnv = regs->uregs[rn];
723 long rsv = regs->uregs[rs];
724 long rmv = regs->uregs[rm];
725
726 regs->uregs[rd] =
727 insnslot_3arg_rwflags(rnv, rsv, rmv, &regs->ARM_cpsr, i_fn);
728}
729
730static void __kprobes
731emulate_rd16rs8rm0_rwflags(struct kprobe *p, struct pt_regs *regs)
732{
733 insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0];
734 kprobe_opcode_t insn = p->opcode;
735 int rd = (insn >> 16) & 0xf;
736 int rs = (insn >> 8) & 0xf;
737 int rm = insn & 0xf;
738 long rsv = regs->uregs[rs];
739 long rmv = regs->uregs[rm];
740
741 regs->uregs[rd] =
742 insnslot_2arg_rwflags(rsv, rmv, &regs->ARM_cpsr, i_fn);
743}
744
745static void __kprobes
746emulate_rdhi16rdlo12rs8rm0_rwflags(struct kprobe *p, struct pt_regs *regs)
747{
748 insn_llret_4arg_fn_t *i_fn = (insn_llret_4arg_fn_t *)&p->ainsn.insn[0];
749 kprobe_opcode_t insn = p->opcode;
750 union reg_pair fnr;
751 int rdhi = (insn >> 16) & 0xf;
752 int rdlo = (insn >> 12) & 0xf;
753 int rs = (insn >> 8) & 0xf;
754 int rm = insn & 0xf;
755 long rsv = regs->uregs[rs];
756 long rmv = regs->uregs[rm];
757
758 fnr.dr = insnslot_llret_4arg_rwflags(regs->uregs[rdhi],
759 regs->uregs[rdlo], rsv, rmv,
760 &regs->ARM_cpsr, i_fn);
761 regs->uregs[rdhi] = fnr.r0;
762 regs->uregs[rdlo] = fnr.r1;
763}
764
765static void __kprobes
766emulate_alu_imm_rflags(struct kprobe *p, struct pt_regs *regs)
767{
768 insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
769 kprobe_opcode_t insn = p->opcode;
770 int rd = (insn >> 12) & 0xf;
771 int rn = (insn >> 16) & 0xf;
772 long rnv = (rn == 15) ? (long)p->addr + 8 : regs->uregs[rn];
773
774 regs->uregs[rd] = insnslot_1arg_rflags(rnv, regs->ARM_cpsr, i_fn);
775}
776
777static void __kprobes
778emulate_alu_imm_rwflags(struct kprobe *p, struct pt_regs *regs)
779{
780 insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
781 kprobe_opcode_t insn = p->opcode;
782 int rd = (insn >> 12) & 0xf;
783 int rn = (insn >> 16) & 0xf;
784 long rnv = (rn == 15) ? (long)p->addr + 8 : regs->uregs[rn];
785
786 regs->uregs[rd] = insnslot_1arg_rwflags(rnv, &regs->ARM_cpsr, i_fn);
787}
788
789static void __kprobes
Jon Medhurstad111ce2011-04-06 11:17:11 +0100790emulate_alu_tests_imm(struct kprobe *p, struct pt_regs *regs)
791{
792 insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
793 kprobe_opcode_t insn = p->opcode;
794 int rn = (insn >> 16) & 0xf;
795 long rnv = (rn == 15) ? (long)p->addr + 8 : regs->uregs[rn];
796
797 insnslot_1arg_rwflags(rnv, &regs->ARM_cpsr, i_fn);
798}
799
800static void __kprobes
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000801emulate_alu_rflags(struct kprobe *p, struct pt_regs *regs)
802{
803 insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0];
804 kprobe_opcode_t insn = p->opcode;
805 long ppc = (long)p->addr + 8;
806 int rd = (insn >> 12) & 0xf;
807 int rn = (insn >> 16) & 0xf; /* rn/rnv/rs/rsv may be */
808 int rs = (insn >> 8) & 0xf; /* invalid, don't care. */
809 int rm = insn & 0xf;
810 long rnv = (rn == 15) ? ppc : regs->uregs[rn];
811 long rmv = (rm == 15) ? ppc : regs->uregs[rm];
812 long rsv = regs->uregs[rs];
813
814 regs->uregs[rd] =
815 insnslot_3arg_rflags(rnv, rmv, rsv, regs->ARM_cpsr, i_fn);
816}
817
818static void __kprobes
819emulate_alu_rwflags(struct kprobe *p, struct pt_regs *regs)
820{
821 insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0];
822 kprobe_opcode_t insn = p->opcode;
823 long ppc = (long)p->addr + 8;
824 int rd = (insn >> 12) & 0xf;
825 int rn = (insn >> 16) & 0xf; /* rn/rnv/rs/rsv may be */
826 int rs = (insn >> 8) & 0xf; /* invalid, don't care. */
827 int rm = insn & 0xf;
828 long rnv = (rn == 15) ? ppc : regs->uregs[rn];
829 long rmv = (rm == 15) ? ppc : regs->uregs[rm];
830 long rsv = regs->uregs[rs];
831
832 regs->uregs[rd] =
833 insnslot_3arg_rwflags(rnv, rmv, rsv, &regs->ARM_cpsr, i_fn);
834}
835
Jon Medhurstad111ce2011-04-06 11:17:11 +0100836static void __kprobes
837emulate_alu_tests(struct kprobe *p, struct pt_regs *regs)
838{
839 insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0];
840 kprobe_opcode_t insn = p->opcode;
841 long ppc = (long)p->addr + 8;
842 int rn = (insn >> 16) & 0xf;
843 int rs = (insn >> 8) & 0xf; /* rs/rsv may be invalid, don't care. */
844 int rm = insn & 0xf;
845 long rnv = (rn == 15) ? ppc : regs->uregs[rn];
846 long rmv = (rm == 15) ? ppc : regs->uregs[rm];
847 long rsv = regs->uregs[rs];
848
849 insnslot_3arg_rwflags(rnv, rmv, rsv, &regs->ARM_cpsr, i_fn);
850}
851
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000852static enum kprobe_insn __kprobes
853prep_emulate_ldr_str(kprobe_opcode_t insn, struct arch_specific_insn *asi)
854{
Jon Medhurst6823fc82011-04-08 15:32:54 +0100855 int not_imm = (insn & (1 << 26)) ? (insn & (1 << 25))
856 : (~insn & (1 << 22));
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000857
Jon Medhurst54823ac2011-04-08 15:32:55 +0100858 if (is_writeback(insn) && is_r15(insn, 16))
859 return INSN_REJECTED; /* Writeback to PC */
860
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000861 insn &= 0xfff00fff;
862 insn |= 0x00001000; /* Rn = r0, Rd = r1 */
Jon Medhurst6823fc82011-04-08 15:32:54 +0100863 if (not_imm) {
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000864 insn &= ~0xf;
865 insn |= 2; /* Rm = r2 */
866 }
867 asi->insn[0] = insn;
868 asi->insn_handler = (insn & (1 << 20)) ? emulate_ldr : emulate_str;
869 return INSN_GOOD;
870}
871
872static enum kprobe_insn __kprobes
Jon Medhurstc9836772011-04-19 10:52:17 +0100873prep_emulate_rd12_modify(kprobe_opcode_t insn, struct arch_specific_insn *asi)
874{
875 if (is_r15(insn, 12))
876 return INSN_REJECTED; /* Rd is PC */
877
878 insn &= 0xffff0fff; /* Rd = r0 */
879 asi->insn[0] = insn;
880 asi->insn_handler = emulate_rd12_modify;
881 return INSN_GOOD;
882}
883
884static enum kprobe_insn __kprobes
Jon Medhurst20e81552011-04-19 10:52:18 +0100885prep_emulate_rd12rn0_modify(kprobe_opcode_t insn,
886 struct arch_specific_insn *asi)
887{
888 if (is_r15(insn, 12))
889 return INSN_REJECTED; /* Rd is PC */
890
891 insn &= 0xffff0ff0; /* Rd = r0 */
892 insn |= 0x00000001; /* Rn = r1 */
893 asi->insn[0] = insn;
894 asi->insn_handler = emulate_rd12rn0_modify;
895 return INSN_GOOD;
896}
897
898static enum kprobe_insn __kprobes
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000899prep_emulate_rd12rm0(kprobe_opcode_t insn, struct arch_specific_insn *asi)
900{
Jon Medhurst983ebd92011-04-07 13:25:17 +0100901 if (is_r15(insn, 12))
902 return INSN_REJECTED; /* Rd is PC */
903
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000904 insn &= 0xffff0ff0; /* Rd = r0, Rm = r0 */
905 asi->insn[0] = insn;
906 asi->insn_handler = emulate_rd12rm0;
907 return INSN_GOOD;
908}
909
910static enum kprobe_insn __kprobes
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000911prep_emulate_rd12rn16rm0_wflags(kprobe_opcode_t insn,
912 struct arch_specific_insn *asi)
913{
Jon Medhurst983ebd92011-04-07 13:25:17 +0100914 if (is_r15(insn, 12))
915 return INSN_REJECTED; /* Rd is PC */
916
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000917 insn &= 0xfff00ff0; /* Rd = r0, Rn = r0 */
918 insn |= 0x00000001; /* Rm = r1 */
919 asi->insn[0] = insn;
920 asi->insn_handler = emulate_rd12rn16rm0_rwflags;
921 return INSN_GOOD;
922}
923
924static enum kprobe_insn __kprobes
925prep_emulate_rd16rs8rm0_wflags(kprobe_opcode_t insn,
926 struct arch_specific_insn *asi)
927{
Jon Medhurst983ebd92011-04-07 13:25:17 +0100928 if (is_r15(insn, 16))
929 return INSN_REJECTED; /* Rd is PC */
930
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000931 insn &= 0xfff0f0f0; /* Rd = r0, Rs = r0 */
932 insn |= 0x00000001; /* Rm = r1 */
933 asi->insn[0] = insn;
934 asi->insn_handler = emulate_rd16rs8rm0_rwflags;
935 return INSN_GOOD;
936}
937
938static enum kprobe_insn __kprobes
939prep_emulate_rd16rn12rs8rm0_wflags(kprobe_opcode_t insn,
940 struct arch_specific_insn *asi)
941{
Jon Medhurst983ebd92011-04-07 13:25:17 +0100942 if (is_r15(insn, 16))
943 return INSN_REJECTED; /* Rd is PC */
944
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000945 insn &= 0xfff000f0; /* Rd = r0, Rn = r0 */
946 insn |= 0x00000102; /* Rs = r1, Rm = r2 */
947 asi->insn[0] = insn;
948 asi->insn_handler = emulate_rd16rn12rs8rm0_rwflags;
949 return INSN_GOOD;
950}
951
952static enum kprobe_insn __kprobes
953prep_emulate_rdhi16rdlo12rs8rm0_wflags(kprobe_opcode_t insn,
954 struct arch_specific_insn *asi)
955{
Jon Medhurst983ebd92011-04-07 13:25:17 +0100956 if (is_r15(insn, 16) || is_r15(insn, 12))
957 return INSN_REJECTED; /* RdHi or RdLo is PC */
958
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000959 insn &= 0xfff000f0; /* RdHi = r0, RdLo = r1 */
960 insn |= 0x00001203; /* Rs = r2, Rm = r3 */
961 asi->insn[0] = insn;
962 asi->insn_handler = emulate_rdhi16rdlo12rs8rm0_rwflags;
963 return INSN_GOOD;
964}
965
966/*
967 * For the instruction masking and comparisons in all the "space_*"
968 * functions below, Do _not_ rearrange the order of tests unless
969 * you're very, very sure of what you are doing. For the sake of
970 * efficiency, the masks for some tests sometimes assume other test
971 * have been done prior to them so the number of patterns to test
972 * for an instruction set can be as broad as possible to reduce the
973 * number of tests needed.
974 */
975
976static enum kprobe_insn __kprobes
977space_1111(kprobe_opcode_t insn, struct arch_specific_insn *asi)
978{
Jon Medhurst41713d12011-04-18 08:53:57 +0100979 /* memory hint : 1111 0100 x001 xxxx xxxx xxxx xxxx xxxx : */
980 /* PLDI : 1111 0100 x101 xxxx xxxx xxxx xxxx xxxx : */
981 /* PLDW : 1111 0101 x001 xxxx xxxx xxxx xxxx xxxx : */
982 /* PLD : 1111 0101 x101 xxxx xxxx xxxx xxxx xxxx : */
983 if ((insn & 0xfe300000) == 0xf4100000) {
984 asi->insn_handler = emulate_nop;
985 return INSN_GOOD_NO_SLOT;
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000986 }
987
988 /* BLX(1) : 1111 101x xxxx xxxx xxxx xxxx xxxx xxxx : */
989 if ((insn & 0xfe000000) == 0xfa000000) {
990 asi->insn_handler = simulate_blx1;
991 return INSN_GOOD_NO_SLOT;
992 }
993
Jon Medhurst72c2bab2011-04-18 08:53:58 +0100994 /* CPS : 1111 0001 0000 xxx0 xxxx xxxx xx0x xxxx */
995 /* SETEND: 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */
996
997 /* SRS : 1111 100x x1x0 xxxx xxxx xxxx xxxx xxxx */
998 /* RFE : 1111 100x x0x1 xxxx xxxx xxxx xxxx xxxx */
Quentin Barnes35aa1df2007-06-11 22:20:10 +0000999
Jon Medhurstfa1a03b2011-04-18 08:53:54 +01001000 /* Coprocessor instructions... */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001001 /* MCRR2 : 1111 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */
1002 /* MRRC2 : 1111 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */
Jon Medhurstfa1a03b2011-04-18 08:53:54 +01001003 /* LDC2 : 1111 110x xxx1 xxxx xxxx xxxx xxxx xxxx */
1004 /* STC2 : 1111 110x xxx0 xxxx xxxx xxxx xxxx xxxx */
1005 /* CDP2 : 1111 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */
1006 /* MCR2 : 1111 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */
1007 /* MRC2 : 1111 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001008
Jon Medhurstfa1a03b2011-04-18 08:53:54 +01001009 return INSN_REJECTED;
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001010}
1011
1012static enum kprobe_insn __kprobes
1013space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
1014{
1015 /* cccc 0001 0xx0 xxxx xxxx xxxx xxxx xxx0 xxxx */
1016 if ((insn & 0x0f900010) == 0x01000000) {
1017
Jon Medhurst51468ea2011-04-07 13:25:15 +01001018 /* MRS cpsr : cccc 0001 0000 xxxx xxxx xxxx 0000 xxxx */
Jon Medhurstc412aba2011-04-07 13:25:16 +01001019 if ((insn & 0x0ff000f0) == 0x01000000) {
Jon Medhurst983ebd92011-04-07 13:25:17 +01001020 if (is_r15(insn, 12))
1021 return INSN_REJECTED; /* Rd is PC */
Jon Medhurstc412aba2011-04-07 13:25:16 +01001022 asi->insn_handler = simulate_mrs;
1023 return INSN_GOOD_NO_SLOT;
1024 }
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001025
1026 /* SMLALxy : cccc 0001 0100 xxxx xxxx xxxx 1xx0 xxxx */
1027 if ((insn & 0x0ff00090) == 0x01400080)
Jon Medhurstcdc25362011-04-19 10:52:20 +01001028 return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn,
1029 asi);
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001030
1031 /* SMULWy : cccc 0001 0010 xxxx xxxx xxxx 1x10 xxxx */
1032 /* SMULxy : cccc 0001 0110 xxxx xxxx xxxx 1xx0 xxxx */
1033 if ((insn & 0x0ff000b0) == 0x012000a0 ||
1034 (insn & 0x0ff00090) == 0x01600080)
1035 return prep_emulate_rd16rs8rm0_wflags(insn, asi);
1036
1037 /* SMLAxy : cccc 0001 0000 xxxx xxxx xxxx 1xx0 xxxx : Q */
Jon Medhurst75539ae2011-04-07 13:25:18 +01001038 /* SMLAWy : cccc 0001 0010 xxxx xxxx xxxx 1x00 xxxx : Q */
Jon Medhurstf704a6e2011-04-19 10:52:16 +01001039 if ((insn & 0x0ff00090) == 0x01000080 ||
1040 (insn & 0x0ff000b0) == 0x01200080)
1041 return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi);
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001042
Jon Medhurstf704a6e2011-04-19 10:52:16 +01001043 /* BXJ : cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */
1044 /* MSR : cccc 0001 0x10 xxxx xxxx xxxx 0000 xxxx */
1045 /* MRS spsr : cccc 0001 0100 xxxx xxxx xxxx 0000 xxxx */
1046
1047 /* Other instruction encodings aren't yet defined */
1048 return INSN_REJECTED;
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001049 }
1050
1051 /* cccc 0001 0xx0 xxxx xxxx xxxx xxxx 0xx1 xxxx */
1052 else if ((insn & 0x0f900090) == 0x01000010) {
1053
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001054 /* BLX(2) : cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */
1055 /* BX : cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */
1056 if ((insn & 0x0ff000d0) == 0x01200010) {
Jon Medhurst983ebd92011-04-07 13:25:17 +01001057 if ((insn & 0x0ff000ff) == 0x0120003f)
1058 return INSN_REJECTED; /* BLX pc */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001059 asi->insn_handler = simulate_blx2bx;
Jon Medhursta539f5d2011-04-06 11:17:10 +01001060 return INSN_GOOD_NO_SLOT;
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001061 }
1062
1063 /* CLZ : cccc 0001 0110 xxxx xxxx xxxx 0001 xxxx */
1064 if ((insn & 0x0ff000f0) == 0x01600010)
1065 return prep_emulate_rd12rm0(insn, asi);
1066
1067 /* QADD : cccc 0001 0000 xxxx xxxx xxxx 0101 xxxx :Q */
1068 /* QSUB : cccc 0001 0010 xxxx xxxx xxxx 0101 xxxx :Q */
1069 /* QDADD : cccc 0001 0100 xxxx xxxx xxxx 0101 xxxx :Q */
1070 /* QDSUB : cccc 0001 0110 xxxx xxxx xxxx 0101 xxxx :Q */
Jon Medhurstf704a6e2011-04-19 10:52:16 +01001071 if ((insn & 0x0f9000f0) == 0x01000050)
1072 return prep_emulate_rd12rn16rm0_wflags(insn, asi);
1073
1074 /* BKPT : 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */
1075 /* SMC : cccc 0001 0110 xxxx xxxx xxxx 0111 xxxx */
1076
1077 /* Other instruction encodings aren't yet defined */
1078 return INSN_REJECTED;
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001079 }
1080
1081 /* cccc 0000 xxxx xxxx xxxx xxxx xxxx 1001 xxxx */
Jon Medhurstba48d402011-04-07 13:25:19 +01001082 else if ((insn & 0x0f0000f0) == 0x00000090) {
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001083
1084 /* MUL : cccc 0000 0000 xxxx xxxx xxxx 1001 xxxx : */
1085 /* MULS : cccc 0000 0001 xxxx xxxx xxxx 1001 xxxx :cc */
1086 /* MLA : cccc 0000 0010 xxxx xxxx xxxx 1001 xxxx : */
1087 /* MLAS : cccc 0000 0011 xxxx xxxx xxxx 1001 xxxx :cc */
1088 /* UMAAL : cccc 0000 0100 xxxx xxxx xxxx 1001 xxxx : */
Jon Medhurstba48d402011-04-07 13:25:19 +01001089 /* undef : cccc 0000 0101 xxxx xxxx xxxx 1001 xxxx : */
1090 /* MLS : cccc 0000 0110 xxxx xxxx xxxx 1001 xxxx : */
1091 /* undef : cccc 0000 0111 xxxx xxxx xxxx 1001 xxxx : */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001092 /* UMULL : cccc 0000 1000 xxxx xxxx xxxx 1001 xxxx : */
1093 /* UMULLS : cccc 0000 1001 xxxx xxxx xxxx 1001 xxxx :cc */
1094 /* UMLAL : cccc 0000 1010 xxxx xxxx xxxx 1001 xxxx : */
1095 /* UMLALS : cccc 0000 1011 xxxx xxxx xxxx 1001 xxxx :cc */
1096 /* SMULL : cccc 0000 1100 xxxx xxxx xxxx 1001 xxxx : */
1097 /* SMULLS : cccc 0000 1101 xxxx xxxx xxxx 1001 xxxx :cc */
1098 /* SMLAL : cccc 0000 1110 xxxx xxxx xxxx 1001 xxxx : */
1099 /* SMLALS : cccc 0000 1111 xxxx xxxx xxxx 1001 xxxx :cc */
Jon Medhurstcdc25362011-04-19 10:52:20 +01001100 if ((insn & 0x00d00000) == 0x00500000)
Jon Medhurstba48d402011-04-07 13:25:19 +01001101 return INSN_REJECTED;
Jon Medhurstcdc25362011-04-19 10:52:20 +01001102 else if ((insn & 0x00e00000) == 0x00000000)
1103 return prep_emulate_rd16rs8rm0_wflags(insn, asi);
1104 else if ((insn & 0x00a00000) == 0x00200000)
1105 return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi);
1106 else
1107 return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn,
1108 asi);
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001109 }
1110
1111 /* cccc 000x xxxx xxxx xxxx xxxx xxxx 1xx1 xxxx */
1112 else if ((insn & 0x0e000090) == 0x00000090) {
1113
1114 /* SWP : cccc 0001 0000 xxxx xxxx xxxx 1001 xxxx */
1115 /* SWPB : cccc 0001 0100 xxxx xxxx xxxx 1001 xxxx */
Jon Medhurstec58d7f2011-04-08 15:32:53 +01001116 /* ??? : cccc 0001 0x01 xxxx xxxx xxxx 1001 xxxx */
1117 /* ??? : cccc 0001 0x10 xxxx xxxx xxxx 1001 xxxx */
1118 /* ??? : cccc 0001 0x11 xxxx xxxx xxxx 1001 xxxx */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001119 /* STREX : cccc 0001 1000 xxxx xxxx xxxx 1001 xxxx */
1120 /* LDREX : cccc 0001 1001 xxxx xxxx xxxx 1001 xxxx */
Jon Medhurstec58d7f2011-04-08 15:32:53 +01001121 /* STREXD: cccc 0001 1010 xxxx xxxx xxxx 1001 xxxx */
1122 /* LDREXD: cccc 0001 1011 xxxx xxxx xxxx 1001 xxxx */
1123 /* STREXB: cccc 0001 1100 xxxx xxxx xxxx 1001 xxxx */
1124 /* LDREXB: cccc 0001 1101 xxxx xxxx xxxx 1001 xxxx */
1125 /* STREXH: cccc 0001 1110 xxxx xxxx xxxx 1001 xxxx */
1126 /* LDREXH: cccc 0001 1111 xxxx xxxx xxxx 1001 xxxx */
1127
1128 /* LDRD : cccc 000x xxx0 xxxx xxxx xxxx 1101 xxxx */
1129 /* STRD : cccc 000x xxx0 xxxx xxxx xxxx 1111 xxxx */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001130 /* LDRH : cccc 000x xxx1 xxxx xxxx xxxx 1011 xxxx */
1131 /* STRH : cccc 000x xxx0 xxxx xxxx xxxx 1011 xxxx */
1132 /* LDRSB : cccc 000x xxx1 xxxx xxxx xxxx 1101 xxxx */
1133 /* LDRSH : cccc 000x xxx1 xxxx xxxx xxxx 1111 xxxx */
Jon Medhurstec58d7f2011-04-08 15:32:53 +01001134 if ((insn & 0x0f0000f0) == 0x01000090) {
1135 if ((insn & 0x0fb000f0) == 0x01000090) {
1136 /* SWP/SWPB */
1137 return prep_emulate_rd12rn16rm0_wflags(insn,
1138 asi);
1139 } else {
1140 /* STREX/LDREX variants and unallocaed space */
1141 return INSN_REJECTED;
1142 }
1143
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001144 } else if ((insn & 0x0e1000d0) == 0x00000d0) {
1145 /* STRD/LDRD */
Jon Medhurst54823ac2011-04-08 15:32:55 +01001146 if ((insn & 0x0000e000) == 0x0000e000)
1147 return INSN_REJECTED; /* Rd is LR or PC */
1148 if (is_writeback(insn) && is_r15(insn, 16))
1149 return INSN_REJECTED; /* Writeback to PC */
1150
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001151 insn &= 0xfff00fff;
1152 insn |= 0x00002000; /* Rn = r0, Rd = r2 */
Jon Medhurst5c6b76f2011-04-08 15:32:56 +01001153 if (!(insn & (1 << 22))) {
1154 /* Register index */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001155 insn &= ~0xf;
1156 insn |= 1; /* Rm = r1 */
1157 }
1158 asi->insn[0] = insn;
1159 asi->insn_handler =
1160 (insn & (1 << 5)) ? emulate_strd : emulate_ldrd;
1161 return INSN_GOOD;
1162 }
1163
Jon Medhurst54823ac2011-04-08 15:32:55 +01001164 /* LDRH/STRH/LDRSB/LDRSH */
1165 if (is_r15(insn, 12))
1166 return INSN_REJECTED; /* Rd is PC */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001167 return prep_emulate_ldr_str(insn, asi);
1168 }
1169
1170 /* cccc 000x xxxx xxxx xxxx xxxx xxxx xxxx xxxx */
1171
1172 /*
1173 * ALU op with S bit and Rd == 15 :
Jon Medhurstcdc25362011-04-19 10:52:20 +01001174 * cccc 000x xxx1 xxxx 1111 xxxx xxxx xxxx
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001175 */
1176 if ((insn & 0x0e10f000) == 0x0010f000)
1177 return INSN_REJECTED;
1178
1179 /*
1180 * "mov ip, sp" is the most common kprobe'd instruction by far.
1181 * Check and optimize for it explicitly.
1182 */
1183 if (insn == 0xe1a0c00d) {
1184 asi->insn_handler = simulate_mov_ipsp;
1185 return INSN_GOOD_NO_SLOT;
1186 }
1187
1188 /*
1189 * Data processing: Immediate-shift / Register-shift
1190 * ALU op : cccc 000x xxxx xxxx xxxx xxxx xxxx xxxx
1191 * CPY : cccc 0001 1010 xxxx xxxx 0000 0000 xxxx
1192 * MOV : cccc 0001 101x xxxx xxxx xxxx xxxx xxxx
1193 * *S (bit 20) updates condition codes
1194 * ADC/SBC/RSC reads the C flag
1195 */
1196 insn &= 0xfff00ff0; /* Rn = r0, Rd = r0 */
1197 insn |= 0x00000001; /* Rm = r1 */
1198 if (insn & 0x010) {
1199 insn &= 0xfffff0ff; /* register shift */
1200 insn |= 0x00000200; /* Rs = r2 */
1201 }
1202 asi->insn[0] = insn;
Jon Medhurstad111ce2011-04-06 11:17:11 +01001203
1204 if ((insn & 0x0f900000) == 0x01100000) {
1205 /*
1206 * TST : cccc 0001 0001 xxxx xxxx xxxx xxxx xxxx
1207 * TEQ : cccc 0001 0011 xxxx xxxx xxxx xxxx xxxx
1208 * CMP : cccc 0001 0101 xxxx xxxx xxxx xxxx xxxx
1209 * CMN : cccc 0001 0111 xxxx xxxx xxxx xxxx xxxx
1210 */
1211 asi->insn_handler = emulate_alu_tests;
1212 } else {
1213 /* ALU ops which write to Rd */
1214 asi->insn_handler = (insn & (1 << 20)) ? /* S-bit */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001215 emulate_alu_rwflags : emulate_alu_rflags;
Jon Medhurstad111ce2011-04-06 11:17:11 +01001216 }
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001217 return INSN_GOOD;
1218}
1219
1220static enum kprobe_insn __kprobes
1221space_cccc_001x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
1222{
Jon Medhurstc9836772011-04-19 10:52:17 +01001223 /* MOVW : cccc 0011 0000 xxxx xxxx xxxx xxxx xxxx */
1224 /* MOVT : cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx */
1225 if ((insn & 0x0fb00000) == 0x03000000)
1226 return prep_emulate_rd12_modify(insn, asi);
1227
Jon Medhurst94254932011-04-19 10:52:19 +01001228 /* hints : cccc 0011 0010 0000 xxxx xxxx xxxx xxxx */
1229 if ((insn & 0x0fff0000) == 0x03200000) {
1230 unsigned op2 = insn & 0x000000ff;
1231 if (op2 == 0x01 || op2 == 0x04) {
1232 /* YIELD : cccc 0011 0010 0000 xxxx xxxx 0000 0001 */
1233 /* SEV : cccc 0011 0010 0000 xxxx xxxx 0000 0100 */
1234 asi->insn[0] = insn;
1235 asi->insn_handler = emulate_none;
1236 return INSN_GOOD;
1237 } else if (op2 <= 0x03) {
1238 /* NOP : cccc 0011 0010 0000 xxxx xxxx 0000 0000 */
1239 /* WFE : cccc 0011 0010 0000 xxxx xxxx 0000 0010 */
1240 /* WFI : cccc 0011 0010 0000 xxxx xxxx 0000 0011 */
1241 /*
1242 * We make WFE and WFI true NOPs to avoid stalls due
1243 * to missing events whilst processing the probe.
1244 */
1245 asi->insn_handler = emulate_nop;
1246 return INSN_GOOD_NO_SLOT;
1247 }
1248 /* For DBG and unallocated hints it's safest to reject them */
1249 return INSN_REJECTED;
1250 }
1251
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001252 /*
1253 * MSR : cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001254 * ALU op with S bit and Rd == 15 :
1255 * cccc 001x xxx1 xxxx 1111 xxxx xxxx xxxx
1256 */
Will Deaconccdf2e12010-09-27 18:12:12 +01001257 if ((insn & 0x0fb00000) == 0x03200000 || /* MSR */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001258 (insn & 0x0e10f000) == 0x0210f000) /* ALU s-bit, R15 */
1259 return INSN_REJECTED;
1260
1261 /*
1262 * Data processing: 32-bit Immediate
1263 * ALU op : cccc 001x xxxx xxxx xxxx xxxx xxxx xxxx
1264 * MOV : cccc 0011 101x xxxx xxxx xxxx xxxx xxxx
1265 * *S (bit 20) updates condition codes
1266 * ADC/SBC/RSC reads the C flag
1267 */
Jon Medhurst896a74e2011-04-06 11:17:12 +01001268 insn &= 0xfff00fff; /* Rn = r0 and Rd = r0 */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001269 asi->insn[0] = insn;
Jon Medhurstad111ce2011-04-06 11:17:11 +01001270
1271 if ((insn & 0x0f900000) == 0x03100000) {
1272 /*
1273 * TST : cccc 0011 0001 xxxx xxxx xxxx xxxx xxxx
1274 * TEQ : cccc 0011 0011 xxxx xxxx xxxx xxxx xxxx
1275 * CMP : cccc 0011 0101 xxxx xxxx xxxx xxxx xxxx
1276 * CMN : cccc 0011 0111 xxxx xxxx xxxx xxxx xxxx
1277 */
1278 asi->insn_handler = emulate_alu_tests_imm;
1279 } else {
1280 /* ALU ops which write to Rd */
1281 asi->insn_handler = (insn & (1 << 20)) ? /* S-bit */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001282 emulate_alu_imm_rwflags : emulate_alu_imm_rflags;
Jon Medhurstad111ce2011-04-06 11:17:11 +01001283 }
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001284 return INSN_GOOD;
1285}
1286
1287static enum kprobe_insn __kprobes
1288space_cccc_0110__1(kprobe_opcode_t insn, struct arch_specific_insn *asi)
1289{
1290 /* SEL : cccc 0110 1000 xxxx xxxx xxxx 1011 xxxx GE: !!! */
1291 if ((insn & 0x0ff000f0) == 0x068000b0) {
Jon Medhurst983ebd92011-04-07 13:25:17 +01001292 if (is_r15(insn, 12))
1293 return INSN_REJECTED; /* Rd is PC */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001294 insn &= 0xfff00ff0; /* Rd = r0, Rn = r0 */
1295 insn |= 0x00000001; /* Rm = r1 */
1296 asi->insn[0] = insn;
1297 asi->insn_handler = emulate_sel;
1298 return INSN_GOOD;
1299 }
1300
1301 /* SSAT : cccc 0110 101x xxxx xxxx xxxx xx01 xxxx :Q */
1302 /* USAT : cccc 0110 111x xxxx xxxx xxxx xx01 xxxx :Q */
1303 /* SSAT16 : cccc 0110 1010 xxxx xxxx xxxx 0011 xxxx :Q */
1304 /* USAT16 : cccc 0110 1110 xxxx xxxx xxxx 0011 xxxx :Q */
1305 if ((insn & 0x0fa00030) == 0x06a00010 ||
1306 (insn & 0x0fb000f0) == 0x06a00030) {
Jon Medhurst983ebd92011-04-07 13:25:17 +01001307 if (is_r15(insn, 12))
1308 return INSN_REJECTED; /* Rd is PC */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001309 insn &= 0xffff0ff0; /* Rd = r0, Rm = r0 */
1310 asi->insn[0] = insn;
1311 asi->insn_handler = emulate_sat;
1312 return INSN_GOOD;
1313 }
1314
1315 /* REV : cccc 0110 1011 xxxx xxxx xxxx 0011 xxxx */
1316 /* REV16 : cccc 0110 1011 xxxx xxxx xxxx 1011 xxxx */
Jon Medhurst0e384ed2011-04-12 07:45:22 +01001317 /* RBIT : cccc 0110 1111 xxxx xxxx xxxx 0011 xxxx */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001318 /* REVSH : cccc 0110 1111 xxxx xxxx xxxx 1011 xxxx */
1319 if ((insn & 0x0ff00070) == 0x06b00030 ||
Jon Medhurst0e384ed2011-04-12 07:45:22 +01001320 (insn & 0x0ff00070) == 0x06f00030)
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001321 return prep_emulate_rd12rm0(insn, asi);
1322
Jon Medhurst780b5c12011-04-12 07:45:23 +01001323 /* ??? : cccc 0110 0000 xxxx xxxx xxxx xxx1 xxxx : */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001324 /* SADD16 : cccc 0110 0001 xxxx xxxx xxxx 0001 xxxx :GE */
1325 /* SADDSUBX : cccc 0110 0001 xxxx xxxx xxxx 0011 xxxx :GE */
1326 /* SSUBADDX : cccc 0110 0001 xxxx xxxx xxxx 0101 xxxx :GE */
1327 /* SSUB16 : cccc 0110 0001 xxxx xxxx xxxx 0111 xxxx :GE */
1328 /* SADD8 : cccc 0110 0001 xxxx xxxx xxxx 1001 xxxx :GE */
Jon Medhurst780b5c12011-04-12 07:45:23 +01001329 /* ??? : cccc 0110 0001 xxxx xxxx xxxx 1011 xxxx : */
1330 /* ??? : cccc 0110 0001 xxxx xxxx xxxx 1101 xxxx : */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001331 /* SSUB8 : cccc 0110 0001 xxxx xxxx xxxx 1111 xxxx :GE */
1332 /* QADD16 : cccc 0110 0010 xxxx xxxx xxxx 0001 xxxx : */
1333 /* QADDSUBX : cccc 0110 0010 xxxx xxxx xxxx 0011 xxxx : */
1334 /* QSUBADDX : cccc 0110 0010 xxxx xxxx xxxx 0101 xxxx : */
1335 /* QSUB16 : cccc 0110 0010 xxxx xxxx xxxx 0111 xxxx : */
1336 /* QADD8 : cccc 0110 0010 xxxx xxxx xxxx 1001 xxxx : */
Jon Medhurst780b5c12011-04-12 07:45:23 +01001337 /* ??? : cccc 0110 0010 xxxx xxxx xxxx 1011 xxxx : */
1338 /* ??? : cccc 0110 0010 xxxx xxxx xxxx 1101 xxxx : */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001339 /* QSUB8 : cccc 0110 0010 xxxx xxxx xxxx 1111 xxxx : */
1340 /* SHADD16 : cccc 0110 0011 xxxx xxxx xxxx 0001 xxxx : */
1341 /* SHADDSUBX : cccc 0110 0011 xxxx xxxx xxxx 0011 xxxx : */
1342 /* SHSUBADDX : cccc 0110 0011 xxxx xxxx xxxx 0101 xxxx : */
1343 /* SHSUB16 : cccc 0110 0011 xxxx xxxx xxxx 0111 xxxx : */
1344 /* SHADD8 : cccc 0110 0011 xxxx xxxx xxxx 1001 xxxx : */
Jon Medhurst780b5c12011-04-12 07:45:23 +01001345 /* ??? : cccc 0110 0011 xxxx xxxx xxxx 1011 xxxx : */
1346 /* ??? : cccc 0110 0011 xxxx xxxx xxxx 1101 xxxx : */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001347 /* SHSUB8 : cccc 0110 0011 xxxx xxxx xxxx 1111 xxxx : */
Jon Medhurst780b5c12011-04-12 07:45:23 +01001348 /* ??? : cccc 0110 0100 xxxx xxxx xxxx xxx1 xxxx : */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001349 /* UADD16 : cccc 0110 0101 xxxx xxxx xxxx 0001 xxxx :GE */
1350 /* UADDSUBX : cccc 0110 0101 xxxx xxxx xxxx 0011 xxxx :GE */
1351 /* USUBADDX : cccc 0110 0101 xxxx xxxx xxxx 0101 xxxx :GE */
1352 /* USUB16 : cccc 0110 0101 xxxx xxxx xxxx 0111 xxxx :GE */
1353 /* UADD8 : cccc 0110 0101 xxxx xxxx xxxx 1001 xxxx :GE */
Jon Medhurst780b5c12011-04-12 07:45:23 +01001354 /* ??? : cccc 0110 0101 xxxx xxxx xxxx 1011 xxxx : */
1355 /* ??? : cccc 0110 0101 xxxx xxxx xxxx 1101 xxxx : */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001356 /* USUB8 : cccc 0110 0101 xxxx xxxx xxxx 1111 xxxx :GE */
1357 /* UQADD16 : cccc 0110 0110 xxxx xxxx xxxx 0001 xxxx : */
1358 /* UQADDSUBX : cccc 0110 0110 xxxx xxxx xxxx 0011 xxxx : */
1359 /* UQSUBADDX : cccc 0110 0110 xxxx xxxx xxxx 0101 xxxx : */
1360 /* UQSUB16 : cccc 0110 0110 xxxx xxxx xxxx 0111 xxxx : */
1361 /* UQADD8 : cccc 0110 0110 xxxx xxxx xxxx 1001 xxxx : */
Jon Medhurst780b5c12011-04-12 07:45:23 +01001362 /* ??? : cccc 0110 0110 xxxx xxxx xxxx 1011 xxxx : */
1363 /* ??? : cccc 0110 0110 xxxx xxxx xxxx 1101 xxxx : */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001364 /* UQSUB8 : cccc 0110 0110 xxxx xxxx xxxx 1111 xxxx : */
1365 /* UHADD16 : cccc 0110 0111 xxxx xxxx xxxx 0001 xxxx : */
1366 /* UHADDSUBX : cccc 0110 0111 xxxx xxxx xxxx 0011 xxxx : */
1367 /* UHSUBADDX : cccc 0110 0111 xxxx xxxx xxxx 0101 xxxx : */
1368 /* UHSUB16 : cccc 0110 0111 xxxx xxxx xxxx 0111 xxxx : */
1369 /* UHADD8 : cccc 0110 0111 xxxx xxxx xxxx 1001 xxxx : */
Jon Medhurst780b5c12011-04-12 07:45:23 +01001370 /* ??? : cccc 0110 0111 xxxx xxxx xxxx 1011 xxxx : */
1371 /* ??? : cccc 0110 0111 xxxx xxxx xxxx 1101 xxxx : */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001372 /* UHSUB8 : cccc 0110 0111 xxxx xxxx xxxx 1111 xxxx : */
Jon Medhurst780b5c12011-04-12 07:45:23 +01001373 if ((insn & 0x0f800010) == 0x06000010) {
1374 if ((insn & 0x00300000) == 0x00000000 ||
1375 (insn & 0x000000e0) == 0x000000a0 ||
1376 (insn & 0x000000e0) == 0x000000c0)
1377 return INSN_REJECTED; /* Unallocated space */
1378 return prep_emulate_rd12rn16rm0_wflags(insn, asi);
1379 }
1380
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001381 /* PKHBT : cccc 0110 1000 xxxx xxxx xxxx x001 xxxx : */
1382 /* PKHTB : cccc 0110 1000 xxxx xxxx xxxx x101 xxxx : */
Jon Medhurst780b5c12011-04-12 07:45:23 +01001383 if ((insn & 0x0ff00030) == 0x06800010)
1384 return prep_emulate_rd12rn16rm0_wflags(insn, asi);
1385
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001386 /* SXTAB16 : cccc 0110 1000 xxxx xxxx xxxx 0111 xxxx : */
Jon Medhurst8dd7cfb2011-04-12 07:45:24 +01001387 /* SXTB16 : cccc 0110 1000 1111 xxxx xxxx 0111 xxxx : */
Jon Medhurst780b5c12011-04-12 07:45:23 +01001388 /* ??? : cccc 0110 1001 xxxx xxxx xxxx 0111 xxxx : */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001389 /* SXTAB : cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx : */
Jon Medhurst8dd7cfb2011-04-12 07:45:24 +01001390 /* SXTB : cccc 0110 1010 1111 xxxx xxxx 0111 xxxx : */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001391 /* SXTAH : cccc 0110 1011 xxxx xxxx xxxx 0111 xxxx : */
Jon Medhurst8dd7cfb2011-04-12 07:45:24 +01001392 /* SXTH : cccc 0110 1011 1111 xxxx xxxx 0111 xxxx : */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001393 /* UXTAB16 : cccc 0110 1100 xxxx xxxx xxxx 0111 xxxx : */
Jon Medhurst8dd7cfb2011-04-12 07:45:24 +01001394 /* UXTB16 : cccc 0110 1100 1111 xxxx xxxx 0111 xxxx : */
Jon Medhurst780b5c12011-04-12 07:45:23 +01001395 /* ??? : cccc 0110 1101 xxxx xxxx xxxx 0111 xxxx : */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001396 /* UXTAB : cccc 0110 1110 xxxx xxxx xxxx 0111 xxxx : */
Jon Medhurst8dd7cfb2011-04-12 07:45:24 +01001397 /* UXTB : cccc 0110 1110 1111 xxxx xxxx 0111 xxxx : */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001398 /* UXTAH : cccc 0110 1111 xxxx xxxx xxxx 0111 xxxx : */
Jon Medhurst8dd7cfb2011-04-12 07:45:24 +01001399 /* UXTH : cccc 0110 1111 1111 xxxx xxxx 0111 xxxx : */
Jon Medhurst780b5c12011-04-12 07:45:23 +01001400 if ((insn & 0x0f8000f0) == 0x06800070) {
1401 if ((insn & 0x00300000) == 0x00100000)
1402 return INSN_REJECTED; /* Unallocated space */
Jon Medhurst8dd7cfb2011-04-12 07:45:24 +01001403
Jon Medhurstcdc25362011-04-19 10:52:20 +01001404 if ((insn & 0x000f0000) == 0x000f0000)
Jon Medhurst8dd7cfb2011-04-12 07:45:24 +01001405 return prep_emulate_rd12rm0(insn, asi);
Jon Medhurstcdc25362011-04-19 10:52:20 +01001406 else
Jon Medhurst8dd7cfb2011-04-12 07:45:24 +01001407 return prep_emulate_rd12rn16rm0_wflags(insn, asi);
Jon Medhurst780b5c12011-04-12 07:45:23 +01001408 }
1409
1410 /* Other instruction encodings aren't yet defined */
1411 return INSN_REJECTED;
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001412}
1413
1414static enum kprobe_insn __kprobes
1415space_cccc_0111__1(kprobe_opcode_t insn, struct arch_specific_insn *asi)
1416{
1417 /* Undef : cccc 0111 1111 xxxx xxxx xxxx 1111 xxxx */
1418 if ((insn & 0x0ff000f0) == 0x03f000f0)
1419 return INSN_REJECTED;
1420
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001421 /* SMLALD : cccc 0111 0100 xxxx xxxx xxxx 00x1 xxxx */
1422 /* SMLSLD : cccc 0111 0100 xxxx xxxx xxxx 01x1 xxxx */
1423 if ((insn & 0x0ff00090) == 0x07400010)
1424 return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, asi);
1425
1426 /* SMLAD : cccc 0111 0000 xxxx xxxx xxxx 00x1 xxxx :Q */
Jon Medhurst038c3832011-04-12 07:45:25 +01001427 /* SMUAD : cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx :Q */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001428 /* SMLSD : cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx :Q */
Jon Medhurst038c3832011-04-12 07:45:25 +01001429 /* SMUSD : cccc 0111 0000 xxxx 1111 xxxx 01x1 xxxx : */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001430 /* SMMLA : cccc 0111 0101 xxxx xxxx xxxx 00x1 xxxx : */
Jon Medhurst038c3832011-04-12 07:45:25 +01001431 /* SMMUL : cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx : */
Jon Medhurstc6e4ae32011-04-12 07:45:26 +01001432 /* USADA8 : cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx : */
1433 /* USAD8 : cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx : */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001434 if ((insn & 0x0ff00090) == 0x07000010 ||
Jon Medhurstc6e4ae32011-04-12 07:45:26 +01001435 (insn & 0x0ff000d0) == 0x07500010 ||
1436 (insn & 0x0ff000f0) == 0x07800010) {
Jon Medhurst038c3832011-04-12 07:45:25 +01001437
Jon Medhurstcdc25362011-04-19 10:52:20 +01001438 if ((insn & 0x0000f000) == 0x0000f000)
Jon Medhurst038c3832011-04-12 07:45:25 +01001439 return prep_emulate_rd16rs8rm0_wflags(insn, asi);
Jon Medhurstcdc25362011-04-19 10:52:20 +01001440 else
Jon Medhurst038c3832011-04-12 07:45:25 +01001441 return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi);
Jon Medhurst038c3832011-04-12 07:45:25 +01001442 }
1443
1444 /* SMMLS : cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx : */
1445 if ((insn & 0x0ff000d0) == 0x075000d0)
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001446 return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi);
1447
Jon Medhurst20e81552011-04-19 10:52:18 +01001448 /* SBFX : cccc 0111 101x xxxx xxxx xxxx x101 xxxx : */
1449 /* UBFX : cccc 0111 111x xxxx xxxx xxxx x101 xxxx : */
1450 if ((insn & 0x0fa00070) == 0x07a00050)
1451 return prep_emulate_rd12rm0(insn, asi);
1452
1453 /* BFI : cccc 0111 110x xxxx xxxx xxxx x001 xxxx : */
1454 /* BFC : cccc 0111 110x xxxx xxxx xxxx x001 1111 : */
1455 if ((insn & 0x0fe00070) == 0x07c00010) {
1456
1457 if ((insn & 0x0000000f) == 0x0000000f)
1458 return prep_emulate_rd12_modify(insn, asi);
1459 else
1460 return prep_emulate_rd12rn0_modify(insn, asi);
1461 }
1462
Jon Medhurst038c3832011-04-12 07:45:25 +01001463 return INSN_REJECTED;
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001464}
1465
1466static enum kprobe_insn __kprobes
1467space_cccc_01xx(kprobe_opcode_t insn, struct arch_specific_insn *asi)
1468{
1469 /* LDR : cccc 01xx x0x1 xxxx xxxx xxxx xxxx xxxx */
1470 /* LDRB : cccc 01xx x1x1 xxxx xxxx xxxx xxxx xxxx */
1471 /* LDRBT : cccc 01x0 x111 xxxx xxxx xxxx xxxx xxxx */
1472 /* LDRT : cccc 01x0 x011 xxxx xxxx xxxx xxxx xxxx */
1473 /* STR : cccc 01xx x0x0 xxxx xxxx xxxx xxxx xxxx */
1474 /* STRB : cccc 01xx x1x0 xxxx xxxx xxxx xxxx xxxx */
1475 /* STRBT : cccc 01x0 x110 xxxx xxxx xxxx xxxx xxxx */
1476 /* STRT : cccc 01x0 x010 xxxx xxxx xxxx xxxx xxxx */
Jon Medhurst81ff5722011-04-12 07:45:21 +01001477
1478 if ((insn & 0x00500000) == 0x00500000 && is_r15(insn, 12))
1479 return INSN_REJECTED; /* LDRB into PC */
1480
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001481 return prep_emulate_ldr_str(insn, asi);
1482}
1483
1484static enum kprobe_insn __kprobes
1485space_cccc_100x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
1486{
1487 /* LDM(2) : cccc 100x x101 xxxx 0xxx xxxx xxxx xxxx */
1488 /* LDM(3) : cccc 100x x1x1 xxxx 1xxx xxxx xxxx xxxx */
1489 if ((insn & 0x0e708000) == 0x85000000 ||
1490 (insn & 0x0e508000) == 0x85010000)
1491 return INSN_REJECTED;
1492
1493 /* LDM(1) : cccc 100x x0x1 xxxx xxxx xxxx xxxx xxxx */
1494 /* STM(1) : cccc 100x x0x0 xxxx xxxx xxxx xxxx xxxx */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001495 asi->insn_handler = ((insn & 0x108000) == 0x008000) ? /* STM & R15 */
1496 simulate_stm1_pc : simulate_ldm1stm1;
Jon Medhursta539f5d2011-04-06 11:17:10 +01001497 return INSN_GOOD_NO_SLOT;
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001498}
1499
1500static enum kprobe_insn __kprobes
1501space_cccc_101x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
1502{
1503 /* B : cccc 1010 xxxx xxxx xxxx xxxx xxxx xxxx */
1504 /* BL : cccc 1011 xxxx xxxx xxxx xxxx xxxx xxxx */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001505 asi->insn_handler = simulate_bbl;
Jon Medhursta539f5d2011-04-06 11:17:10 +01001506 return INSN_GOOD_NO_SLOT;
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001507}
1508
1509static enum kprobe_insn __kprobes
Jon Medhurstac211c62011-04-18 08:53:55 +01001510space_cccc_11xx(kprobe_opcode_t insn, struct arch_specific_insn *asi)
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001511{
Jon Medhurstac211c62011-04-18 08:53:55 +01001512 /* Coprocessor instructions... */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001513 /* MCRR : cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */
1514 /* MRRC : cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */
Jon Medhurstac211c62011-04-18 08:53:55 +01001515 /* LDC : cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */
1516 /* STC : cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */
1517 /* CDP : cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */
1518 /* MCR : cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */
1519 /* MRC : cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001520
Jon Medhurstac211c62011-04-18 08:53:55 +01001521 /* SVC : cccc 1111 xxxx xxxx xxxx xxxx xxxx xxxx */
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001522
Jon Medhurstfa1a03b2011-04-18 08:53:54 +01001523 return INSN_REJECTED;
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001524}
1525
1526/* Return:
1527 * INSN_REJECTED If instruction is one not allowed to kprobe,
1528 * INSN_GOOD If instruction is supported and uses instruction slot,
1529 * INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot.
1530 *
1531 * For instructions we don't want to kprobe (INSN_REJECTED return result):
1532 * These are generally ones that modify the processor state making
1533 * them "hard" to simulate such as switches processor modes or
1534 * make accesses in alternate modes. Any of these could be simulated
1535 * if the work was put into it, but low return considering they
1536 * should also be very rare.
1537 */
1538enum kprobe_insn __kprobes
1539arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi)
1540{
Jon Medhurst0ab4c022011-07-06 11:25:18 +01001541 asi->insn_check_cc = kprobe_condition_checks[insn>>28];
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001542 asi->insn[1] = KPROBE_RETURN_INSTRUCTION;
1543
Jon Medhurstcdc25362011-04-19 10:52:20 +01001544 if ((insn & 0xf0000000) == 0xf0000000)
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001545
1546 return space_1111(insn, asi);
1547
Jon Medhurstcdc25362011-04-19 10:52:20 +01001548 else if ((insn & 0x0e000000) == 0x00000000)
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001549
1550 return space_cccc_000x(insn, asi);
1551
Jon Medhurstcdc25362011-04-19 10:52:20 +01001552 else if ((insn & 0x0e000000) == 0x02000000)
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001553
1554 return space_cccc_001x(insn, asi);
1555
Jon Medhurstcdc25362011-04-19 10:52:20 +01001556 else if ((insn & 0x0f000010) == 0x06000010)
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001557
1558 return space_cccc_0110__1(insn, asi);
1559
Jon Medhurstcdc25362011-04-19 10:52:20 +01001560 else if ((insn & 0x0f000010) == 0x07000010)
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001561
1562 return space_cccc_0111__1(insn, asi);
1563
Jon Medhurstcdc25362011-04-19 10:52:20 +01001564 else if ((insn & 0x0c000000) == 0x04000000)
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001565
1566 return space_cccc_01xx(insn, asi);
1567
Jon Medhurstcdc25362011-04-19 10:52:20 +01001568 else if ((insn & 0x0e000000) == 0x08000000)
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001569
1570 return space_cccc_100x(insn, asi);
1571
Jon Medhurstcdc25362011-04-19 10:52:20 +01001572 else if ((insn & 0x0e000000) == 0x0a000000)
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001573
1574 return space_cccc_101x(insn, asi);
1575
Jon Medhurstac211c62011-04-18 08:53:55 +01001576 return space_cccc_11xx(insn, asi);
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001577}
1578
1579void __init arm_kprobe_decode_init(void)
1580{
1581 find_str_pc_offset();
1582}