diff options
Diffstat (limited to 'arch/arm/kernel/kprobes-arm.c')
-rw-r--r-- | arch/arm/kernel/kprobes-arm.c | 999 |
1 files changed, 999 insertions, 0 deletions
diff --git a/arch/arm/kernel/kprobes-arm.c b/arch/arm/kernel/kprobes-arm.c new file mode 100644 index 000000000000..79203ee1d039 --- /dev/null +++ b/arch/arm/kernel/kprobes-arm.c | |||
@@ -0,0 +1,999 @@ | |||
1 | /* | ||
2 | * arch/arm/kernel/kprobes-decode.c | ||
3 | * | ||
4 | * Copyright (C) 2006, 2007 Motorola Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | /* | ||
17 | * We do not have hardware single-stepping on ARM, This | ||
18 | * effort is further complicated by the ARM not having a | ||
19 | * "next PC" register. Instructions that change the PC | ||
20 | * can't be safely single-stepped in a MP environment, so | ||
21 | * we have a lot of work to do: | ||
22 | * | ||
23 | * In the prepare phase: | ||
24 | * *) If it is an instruction that does anything | ||
25 | * with the CPU mode, we reject it for a kprobe. | ||
26 | * (This is out of laziness rather than need. The | ||
27 | * instructions could be simulated.) | ||
28 | * | ||
29 | * *) Otherwise, decode the instruction rewriting its | ||
30 | * registers to take fixed, ordered registers and | ||
31 | * setting a handler for it to run the instruction. | ||
32 | * | ||
33 | * In the execution phase by an instruction's handler: | ||
34 | * | ||
35 | * *) If the PC is written to by the instruction, the | ||
36 | * instruction must be fully simulated in software. | ||
37 | * | ||
38 | * *) Otherwise, a modified form of the instruction is | ||
39 | * directly executed. Its handler calls the | ||
40 | * instruction in insn[0]. In insn[1] is a | ||
41 | * "mov pc, lr" to return. | ||
42 | * | ||
43 | * Before calling, load up the reordered registers | ||
44 | * from the original instruction's registers. If one | ||
45 | * of the original input registers is the PC, compute | ||
46 | * and adjust the appropriate input register. | ||
47 | * | ||
48 | * After call completes, copy the output registers to | ||
49 | * the original instruction's original registers. | ||
50 | * | ||
51 | * We don't use a real breakpoint instruction since that | ||
52 | * would have us in the kernel go from SVC mode to SVC | ||
53 | * mode losing the link register. Instead we use an | ||
54 | * undefined instruction. To simplify processing, the | ||
55 | * undefined instruction used for kprobes must be reserved | ||
56 | * exclusively for kprobes use. | ||
57 | * | ||
58 | * TODO: ifdef out some instruction decoding based on architecture. | ||
59 | */ | ||
60 | |||
61 | #include <linux/kernel.h> | ||
62 | #include <linux/kprobes.h> | ||
63 | |||
64 | #include "kprobes.h" | ||
65 | |||
66 | #define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit))))) | ||
67 | |||
68 | #define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25) | ||
69 | |||
70 | #if __LINUX_ARM_ARCH__ >= 6 | ||
71 | #define BLX(reg) "blx "reg" \n\t" | ||
72 | #else | ||
73 | #define BLX(reg) "mov lr, pc \n\t" \ | ||
74 | "mov pc, "reg" \n\t" | ||
75 | #endif | ||
76 | |||
77 | /* | ||
78 | * To avoid the complications of mimicing single-stepping on a | ||
79 | * processor without a Next-PC or a single-step mode, and to | ||
80 | * avoid having to deal with the side-effects of boosting, we | ||
81 | * simulate or emulate (almost) all ARM instructions. | ||
82 | * | ||
83 | * "Simulation" is where the instruction's behavior is duplicated in | ||
84 | * C code. "Emulation" is where the original instruction is rewritten | ||
85 | * and executed, often by altering its registers. | ||
86 | * | ||
87 | * By having all behavior of the kprobe'd instruction completed before | ||
88 | * returning from the kprobe_handler(), all locks (scheduler and | ||
89 | * interrupt) can safely be released. There is no need for secondary | ||
90 | * breakpoints, no race with MP or preemptable kernels, nor having to | ||
91 | * clean up resources counts at a later time impacting overall system | ||
92 | * performance. By rewriting the instruction, only the minimum registers | ||
93 | * need to be loaded and saved back optimizing performance. | ||
94 | * | ||
95 | * Calling the insnslot_*_rwflags version of a function doesn't hurt | ||
96 | * anything even when the CPSR flags aren't updated by the | ||
97 | * instruction. It's just a little slower in return for saving | ||
98 | * a little space by not having a duplicate function that doesn't | ||
99 | * update the flags. (The same optimization can be said for | ||
100 | * instructions that do or don't perform register writeback) | ||
101 | * Also, instructions can either read the flags, only write the | ||
102 | * flags, or read and write the flags. To save combinations | ||
103 | * rather than for sheer performance, flag functions just assume | ||
104 | * read and write of flags. | ||
105 | */ | ||
106 | |||
107 | static void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs) | ||
108 | { | ||
109 | kprobe_opcode_t insn = p->opcode; | ||
110 | long iaddr = (long)p->addr; | ||
111 | int disp = branch_displacement(insn); | ||
112 | |||
113 | if (insn & (1 << 24)) | ||
114 | regs->ARM_lr = iaddr + 4; | ||
115 | |||
116 | regs->ARM_pc = iaddr + 8 + disp; | ||
117 | } | ||
118 | |||
119 | static void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs) | ||
120 | { | ||
121 | kprobe_opcode_t insn = p->opcode; | ||
122 | long iaddr = (long)p->addr; | ||
123 | int disp = branch_displacement(insn); | ||
124 | |||
125 | regs->ARM_lr = iaddr + 4; | ||
126 | regs->ARM_pc = iaddr + 8 + disp + ((insn >> 23) & 0x2); | ||
127 | regs->ARM_cpsr |= PSR_T_BIT; | ||
128 | } | ||
129 | |||
130 | static void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs) | ||
131 | { | ||
132 | kprobe_opcode_t insn = p->opcode; | ||
133 | int rm = insn & 0xf; | ||
134 | long rmv = regs->uregs[rm]; | ||
135 | |||
136 | if (insn & (1 << 5)) | ||
137 | regs->ARM_lr = (long)p->addr + 4; | ||
138 | |||
139 | regs->ARM_pc = rmv & ~0x1; | ||
140 | regs->ARM_cpsr &= ~PSR_T_BIT; | ||
141 | if (rmv & 0x1) | ||
142 | regs->ARM_cpsr |= PSR_T_BIT; | ||
143 | } | ||
144 | |||
145 | static void __kprobes simulate_mrs(struct kprobe *p, struct pt_regs *regs) | ||
146 | { | ||
147 | kprobe_opcode_t insn = p->opcode; | ||
148 | int rd = (insn >> 12) & 0xf; | ||
149 | unsigned long mask = 0xf8ff03df; /* Mask out execution state */ | ||
150 | regs->uregs[rd] = regs->ARM_cpsr & mask; | ||
151 | } | ||
152 | |||
153 | static void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs) | ||
154 | { | ||
155 | regs->uregs[12] = regs->uregs[13]; | ||
156 | } | ||
157 | |||
158 | static void __kprobes | ||
159 | emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) | ||
160 | { | ||
161 | kprobe_opcode_t insn = p->opcode; | ||
162 | unsigned long pc = (unsigned long)p->addr + 8; | ||
163 | int rt = (insn >> 12) & 0xf; | ||
164 | int rn = (insn >> 16) & 0xf; | ||
165 | int rm = insn & 0xf; | ||
166 | |||
167 | register unsigned long rtv asm("r0") = regs->uregs[rt]; | ||
168 | register unsigned long rt2v asm("r1") = regs->uregs[rt+1]; | ||
169 | register unsigned long rnv asm("r2") = (rn == 15) ? pc | ||
170 | : regs->uregs[rn]; | ||
171 | register unsigned long rmv asm("r3") = regs->uregs[rm]; | ||
172 | |||
173 | __asm__ __volatile__ ( | ||
174 | BLX("%[fn]") | ||
175 | : "=r" (rtv), "=r" (rt2v), "=r" (rnv) | ||
176 | : "0" (rtv), "1" (rt2v), "2" (rnv), "r" (rmv), | ||
177 | [fn] "r" (p->ainsn.insn_fn) | ||
178 | : "lr", "memory", "cc" | ||
179 | ); | ||
180 | |||
181 | regs->uregs[rt] = rtv; | ||
182 | regs->uregs[rt+1] = rt2v; | ||
183 | if (is_writeback(insn)) | ||
184 | regs->uregs[rn] = rnv; | ||
185 | } | ||
186 | |||
187 | static void __kprobes | ||
188 | emulate_ldr(struct kprobe *p, struct pt_regs *regs) | ||
189 | { | ||
190 | kprobe_opcode_t insn = p->opcode; | ||
191 | unsigned long pc = (unsigned long)p->addr + 8; | ||
192 | int rt = (insn >> 12) & 0xf; | ||
193 | int rn = (insn >> 16) & 0xf; | ||
194 | int rm = insn & 0xf; | ||
195 | |||
196 | register unsigned long rtv asm("r0"); | ||
197 | register unsigned long rnv asm("r2") = (rn == 15) ? pc | ||
198 | : regs->uregs[rn]; | ||
199 | register unsigned long rmv asm("r3") = regs->uregs[rm]; | ||
200 | |||
201 | __asm__ __volatile__ ( | ||
202 | BLX("%[fn]") | ||
203 | : "=r" (rtv), "=r" (rnv) | ||
204 | : "1" (rnv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn) | ||
205 | : "lr", "memory", "cc" | ||
206 | ); | ||
207 | |||
208 | if (rt == 15) | ||
209 | load_write_pc(rtv, regs); | ||
210 | else | ||
211 | regs->uregs[rt] = rtv; | ||
212 | |||
213 | if (is_writeback(insn)) | ||
214 | regs->uregs[rn] = rnv; | ||
215 | } | ||
216 | |||
217 | static void __kprobes | ||
218 | emulate_str(struct kprobe *p, struct pt_regs *regs) | ||
219 | { | ||
220 | kprobe_opcode_t insn = p->opcode; | ||
221 | unsigned long rtpc = (unsigned long)p->addr + str_pc_offset; | ||
222 | unsigned long rnpc = (unsigned long)p->addr + 8; | ||
223 | int rt = (insn >> 12) & 0xf; | ||
224 | int rn = (insn >> 16) & 0xf; | ||
225 | int rm = insn & 0xf; | ||
226 | |||
227 | register unsigned long rtv asm("r0") = (rt == 15) ? rtpc | ||
228 | : regs->uregs[rt]; | ||
229 | register unsigned long rnv asm("r2") = (rn == 15) ? rnpc | ||
230 | : regs->uregs[rn]; | ||
231 | register unsigned long rmv asm("r3") = regs->uregs[rm]; | ||
232 | |||
233 | __asm__ __volatile__ ( | ||
234 | BLX("%[fn]") | ||
235 | : "=r" (rnv) | ||
236 | : "r" (rtv), "0" (rnv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn) | ||
237 | : "lr", "memory", "cc" | ||
238 | ); | ||
239 | |||
240 | if (is_writeback(insn)) | ||
241 | regs->uregs[rn] = rnv; | ||
242 | } | ||
243 | |||
244 | static void __kprobes | ||
245 | emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, struct pt_regs *regs) | ||
246 | { | ||
247 | kprobe_opcode_t insn = p->opcode; | ||
248 | unsigned long pc = (unsigned long)p->addr + 8; | ||
249 | int rd = (insn >> 12) & 0xf; | ||
250 | int rn = (insn >> 16) & 0xf; | ||
251 | int rm = insn & 0xf; | ||
252 | int rs = (insn >> 8) & 0xf; | ||
253 | |||
254 | register unsigned long rdv asm("r0") = regs->uregs[rd]; | ||
255 | register unsigned long rnv asm("r2") = (rn == 15) ? pc | ||
256 | : regs->uregs[rn]; | ||
257 | register unsigned long rmv asm("r3") = (rm == 15) ? pc | ||
258 | : regs->uregs[rm]; | ||
259 | register unsigned long rsv asm("r1") = regs->uregs[rs]; | ||
260 | unsigned long cpsr = regs->ARM_cpsr; | ||
261 | |||
262 | __asm__ __volatile__ ( | ||
263 | "msr cpsr_fs, %[cpsr] \n\t" | ||
264 | BLX("%[fn]") | ||
265 | "mrs %[cpsr], cpsr \n\t" | ||
266 | : "=r" (rdv), [cpsr] "=r" (cpsr) | ||
267 | : "0" (rdv), "r" (rnv), "r" (rmv), "r" (rsv), | ||
268 | "1" (cpsr), [fn] "r" (p->ainsn.insn_fn) | ||
269 | : "lr", "memory", "cc" | ||
270 | ); | ||
271 | |||
272 | if (rd == 15) | ||
273 | alu_write_pc(rdv, regs); | ||
274 | else | ||
275 | regs->uregs[rd] = rdv; | ||
276 | regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); | ||
277 | } | ||
278 | |||
279 | static void __kprobes | ||
280 | emulate_rd12rn16rm0_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) | ||
281 | { | ||
282 | kprobe_opcode_t insn = p->opcode; | ||
283 | int rd = (insn >> 12) & 0xf; | ||
284 | int rn = (insn >> 16) & 0xf; | ||
285 | int rm = insn & 0xf; | ||
286 | |||
287 | register unsigned long rdv asm("r0") = regs->uregs[rd]; | ||
288 | register unsigned long rnv asm("r2") = regs->uregs[rn]; | ||
289 | register unsigned long rmv asm("r3") = regs->uregs[rm]; | ||
290 | unsigned long cpsr = regs->ARM_cpsr; | ||
291 | |||
292 | __asm__ __volatile__ ( | ||
293 | "msr cpsr_fs, %[cpsr] \n\t" | ||
294 | BLX("%[fn]") | ||
295 | "mrs %[cpsr], cpsr \n\t" | ||
296 | : "=r" (rdv), [cpsr] "=r" (cpsr) | ||
297 | : "0" (rdv), "r" (rnv), "r" (rmv), | ||
298 | "1" (cpsr), [fn] "r" (p->ainsn.insn_fn) | ||
299 | : "lr", "memory", "cc" | ||
300 | ); | ||
301 | |||
302 | regs->uregs[rd] = rdv; | ||
303 | regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); | ||
304 | } | ||
305 | |||
306 | static void __kprobes | ||
307 | emulate_rd16rn12rm0rs8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) | ||
308 | { | ||
309 | kprobe_opcode_t insn = p->opcode; | ||
310 | int rd = (insn >> 16) & 0xf; | ||
311 | int rn = (insn >> 12) & 0xf; | ||
312 | int rm = insn & 0xf; | ||
313 | int rs = (insn >> 8) & 0xf; | ||
314 | |||
315 | register unsigned long rdv asm("r2") = regs->uregs[rd]; | ||
316 | register unsigned long rnv asm("r0") = regs->uregs[rn]; | ||
317 | register unsigned long rmv asm("r3") = regs->uregs[rm]; | ||
318 | register unsigned long rsv asm("r1") = regs->uregs[rs]; | ||
319 | unsigned long cpsr = regs->ARM_cpsr; | ||
320 | |||
321 | __asm__ __volatile__ ( | ||
322 | "msr cpsr_fs, %[cpsr] \n\t" | ||
323 | BLX("%[fn]") | ||
324 | "mrs %[cpsr], cpsr \n\t" | ||
325 | : "=r" (rdv), [cpsr] "=r" (cpsr) | ||
326 | : "0" (rdv), "r" (rnv), "r" (rmv), "r" (rsv), | ||
327 | "1" (cpsr), [fn] "r" (p->ainsn.insn_fn) | ||
328 | : "lr", "memory", "cc" | ||
329 | ); | ||
330 | |||
331 | regs->uregs[rd] = rdv; | ||
332 | regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); | ||
333 | } | ||
334 | |||
335 | static void __kprobes | ||
336 | emulate_rd12rm0_noflags_nopc(struct kprobe *p, struct pt_regs *regs) | ||
337 | { | ||
338 | kprobe_opcode_t insn = p->opcode; | ||
339 | int rd = (insn >> 12) & 0xf; | ||
340 | int rm = insn & 0xf; | ||
341 | |||
342 | register unsigned long rdv asm("r0") = regs->uregs[rd]; | ||
343 | register unsigned long rmv asm("r3") = regs->uregs[rm]; | ||
344 | |||
345 | __asm__ __volatile__ ( | ||
346 | BLX("%[fn]") | ||
347 | : "=r" (rdv) | ||
348 | : "0" (rdv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn) | ||
349 | : "lr", "memory", "cc" | ||
350 | ); | ||
351 | |||
352 | regs->uregs[rd] = rdv; | ||
353 | } | ||
354 | |||
355 | static void __kprobes | ||
356 | emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) | ||
357 | { | ||
358 | kprobe_opcode_t insn = p->opcode; | ||
359 | int rdlo = (insn >> 12) & 0xf; | ||
360 | int rdhi = (insn >> 16) & 0xf; | ||
361 | int rn = insn & 0xf; | ||
362 | int rm = (insn >> 8) & 0xf; | ||
363 | |||
364 | register unsigned long rdlov asm("r0") = regs->uregs[rdlo]; | ||
365 | register unsigned long rdhiv asm("r2") = regs->uregs[rdhi]; | ||
366 | register unsigned long rnv asm("r3") = regs->uregs[rn]; | ||
367 | register unsigned long rmv asm("r1") = regs->uregs[rm]; | ||
368 | unsigned long cpsr = regs->ARM_cpsr; | ||
369 | |||
370 | __asm__ __volatile__ ( | ||
371 | "msr cpsr_fs, %[cpsr] \n\t" | ||
372 | BLX("%[fn]") | ||
373 | "mrs %[cpsr], cpsr \n\t" | ||
374 | : "=r" (rdlov), "=r" (rdhiv), [cpsr] "=r" (cpsr) | ||
375 | : "0" (rdlov), "1" (rdhiv), "r" (rnv), "r" (rmv), | ||
376 | "2" (cpsr), [fn] "r" (p->ainsn.insn_fn) | ||
377 | : "lr", "memory", "cc" | ||
378 | ); | ||
379 | |||
380 | regs->uregs[rdlo] = rdlov; | ||
381 | regs->uregs[rdhi] = rdhiv; | ||
382 | regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); | ||
383 | } | ||
384 | |||
385 | /* | ||
386 | * For the instruction masking and comparisons in all the "space_*" | ||
387 | * functions below, Do _not_ rearrange the order of tests unless | ||
388 | * you're very, very sure of what you are doing. For the sake of | ||
389 | * efficiency, the masks for some tests sometimes assume other test | ||
390 | * have been done prior to them so the number of patterns to test | ||
391 | * for an instruction set can be as broad as possible to reduce the | ||
392 | * number of tests needed. | ||
393 | */ | ||
394 | |||
395 | static const union decode_item arm_1111_table[] = { | ||
396 | /* Unconditional instructions */ | ||
397 | |||
398 | /* memory hint 1111 0100 x001 xxxx xxxx xxxx xxxx xxxx */ | ||
399 | /* PLDI (immediate) 1111 0100 x101 xxxx xxxx xxxx xxxx xxxx */ | ||
400 | /* PLDW (immediate) 1111 0101 x001 xxxx xxxx xxxx xxxx xxxx */ | ||
401 | /* PLD (immediate) 1111 0101 x101 xxxx xxxx xxxx xxxx xxxx */ | ||
402 | DECODE_SIMULATE (0xfe300000, 0xf4100000, kprobe_simulate_nop), | ||
403 | |||
404 | /* memory hint 1111 0110 x001 xxxx xxxx xxxx xxx0 xxxx */ | ||
405 | /* PLDI (register) 1111 0110 x101 xxxx xxxx xxxx xxx0 xxxx */ | ||
406 | /* PLDW (register) 1111 0111 x001 xxxx xxxx xxxx xxx0 xxxx */ | ||
407 | /* PLD (register) 1111 0111 x101 xxxx xxxx xxxx xxx0 xxxx */ | ||
408 | DECODE_SIMULATE (0xfe300010, 0xf6100000, kprobe_simulate_nop), | ||
409 | |||
410 | /* BLX (immediate) 1111 101x xxxx xxxx xxxx xxxx xxxx xxxx */ | ||
411 | DECODE_SIMULATE (0xfe000000, 0xfa000000, simulate_blx1), | ||
412 | |||
413 | /* CPS 1111 0001 0000 xxx0 xxxx xxxx xx0x xxxx */ | ||
414 | /* SETEND 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */ | ||
415 | /* SRS 1111 100x x1x0 xxxx xxxx xxxx xxxx xxxx */ | ||
416 | /* RFE 1111 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ | ||
417 | |||
418 | /* Coprocessor instructions... */ | ||
419 | /* MCRR2 1111 1100 0100 xxxx xxxx xxxx xxxx xxxx */ | ||
420 | /* MRRC2 1111 1100 0101 xxxx xxxx xxxx xxxx xxxx */ | ||
421 | /* LDC2 1111 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ | ||
422 | /* STC2 1111 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ | ||
423 | /* CDP2 1111 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ | ||
424 | /* MCR2 1111 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ | ||
425 | /* MRC2 1111 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ | ||
426 | |||
427 | /* Other unallocated instructions... */ | ||
428 | DECODE_END | ||
429 | }; | ||
430 | |||
431 | static const union decode_item arm_cccc_0001_0xx0____0xxx_table[] = { | ||
432 | /* Miscellaneous instructions */ | ||
433 | |||
434 | /* MRS cpsr cccc 0001 0000 xxxx xxxx xxxx 0000 xxxx */ | ||
435 | DECODE_SIMULATEX(0x0ff000f0, 0x01000000, simulate_mrs, | ||
436 | REGS(0, NOPC, 0, 0, 0)), | ||
437 | |||
438 | /* BX cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */ | ||
439 | DECODE_SIMULATE (0x0ff000f0, 0x01200010, simulate_blx2bx), | ||
440 | |||
441 | /* BLX (register) cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */ | ||
442 | DECODE_SIMULATEX(0x0ff000f0, 0x01200030, simulate_blx2bx, | ||
443 | REGS(0, 0, 0, 0, NOPC)), | ||
444 | |||
445 | /* CLZ cccc 0001 0110 xxxx xxxx xxxx 0001 xxxx */ | ||
446 | DECODE_EMULATEX (0x0ff000f0, 0x01600010, emulate_rd12rm0_noflags_nopc, | ||
447 | REGS(0, NOPC, 0, 0, NOPC)), | ||
448 | |||
449 | /* QADD cccc 0001 0000 xxxx xxxx xxxx 0101 xxxx */ | ||
450 | /* QSUB cccc 0001 0010 xxxx xxxx xxxx 0101 xxxx */ | ||
451 | /* QDADD cccc 0001 0100 xxxx xxxx xxxx 0101 xxxx */ | ||
452 | /* QDSUB cccc 0001 0110 xxxx xxxx xxxx 0101 xxxx */ | ||
453 | DECODE_EMULATEX (0x0f9000f0, 0x01000050, emulate_rd12rn16rm0_rwflags_nopc, | ||
454 | REGS(NOPC, NOPC, 0, 0, NOPC)), | ||
455 | |||
456 | /* BXJ cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */ | ||
457 | /* MSR cccc 0001 0x10 xxxx xxxx xxxx 0000 xxxx */ | ||
458 | /* MRS spsr cccc 0001 0100 xxxx xxxx xxxx 0000 xxxx */ | ||
459 | /* BKPT 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */ | ||
460 | /* SMC cccc 0001 0110 xxxx xxxx xxxx 0111 xxxx */ | ||
461 | /* And unallocated instructions... */ | ||
462 | DECODE_END | ||
463 | }; | ||
464 | |||
465 | static const union decode_item arm_cccc_0001_0xx0____1xx0_table[] = { | ||
466 | /* Halfword multiply and multiply-accumulate */ | ||
467 | |||
468 | /* SMLALxy cccc 0001 0100 xxxx xxxx xxxx 1xx0 xxxx */ | ||
469 | DECODE_EMULATEX (0x0ff00090, 0x01400080, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc, | ||
470 | REGS(NOPC, NOPC, NOPC, 0, NOPC)), | ||
471 | |||
472 | /* SMULWy cccc 0001 0010 xxxx xxxx xxxx 1x10 xxxx */ | ||
473 | DECODE_OR (0x0ff000b0, 0x012000a0), | ||
474 | /* SMULxy cccc 0001 0110 xxxx xxxx xxxx 1xx0 xxxx */ | ||
475 | DECODE_EMULATEX (0x0ff00090, 0x01600080, emulate_rd16rn12rm0rs8_rwflags_nopc, | ||
476 | REGS(NOPC, 0, NOPC, 0, NOPC)), | ||
477 | |||
478 | /* SMLAxy cccc 0001 0000 xxxx xxxx xxxx 1xx0 xxxx */ | ||
479 | DECODE_OR (0x0ff00090, 0x01000080), | ||
480 | /* SMLAWy cccc 0001 0010 xxxx xxxx xxxx 1x00 xxxx */ | ||
481 | DECODE_EMULATEX (0x0ff000b0, 0x01200080, emulate_rd16rn12rm0rs8_rwflags_nopc, | ||
482 | REGS(NOPC, NOPC, NOPC, 0, NOPC)), | ||
483 | |||
484 | DECODE_END | ||
485 | }; | ||
486 | |||
487 | static const union decode_item arm_cccc_0000_____1001_table[] = { | ||
488 | /* Multiply and multiply-accumulate */ | ||
489 | |||
490 | /* MUL cccc 0000 0000 xxxx xxxx xxxx 1001 xxxx */ | ||
491 | /* MULS cccc 0000 0001 xxxx xxxx xxxx 1001 xxxx */ | ||
492 | DECODE_EMULATEX (0x0fe000f0, 0x00000090, emulate_rd16rn12rm0rs8_rwflags_nopc, | ||
493 | REGS(NOPC, 0, NOPC, 0, NOPC)), | ||
494 | |||
495 | /* MLA cccc 0000 0010 xxxx xxxx xxxx 1001 xxxx */ | ||
496 | /* MLAS cccc 0000 0011 xxxx xxxx xxxx 1001 xxxx */ | ||
497 | DECODE_OR (0x0fe000f0, 0x00200090), | ||
498 | /* MLS cccc 0000 0110 xxxx xxxx xxxx 1001 xxxx */ | ||
499 | DECODE_EMULATEX (0x0ff000f0, 0x00600090, emulate_rd16rn12rm0rs8_rwflags_nopc, | ||
500 | REGS(NOPC, NOPC, NOPC, 0, NOPC)), | ||
501 | |||
502 | /* UMAAL cccc 0000 0100 xxxx xxxx xxxx 1001 xxxx */ | ||
503 | DECODE_OR (0x0ff000f0, 0x00400090), | ||
504 | /* UMULL cccc 0000 1000 xxxx xxxx xxxx 1001 xxxx */ | ||
505 | /* UMULLS cccc 0000 1001 xxxx xxxx xxxx 1001 xxxx */ | ||
506 | /* UMLAL cccc 0000 1010 xxxx xxxx xxxx 1001 xxxx */ | ||
507 | /* UMLALS cccc 0000 1011 xxxx xxxx xxxx 1001 xxxx */ | ||
508 | /* SMULL cccc 0000 1100 xxxx xxxx xxxx 1001 xxxx */ | ||
509 | /* SMULLS cccc 0000 1101 xxxx xxxx xxxx 1001 xxxx */ | ||
510 | /* SMLAL cccc 0000 1110 xxxx xxxx xxxx 1001 xxxx */ | ||
511 | /* SMLALS cccc 0000 1111 xxxx xxxx xxxx 1001 xxxx */ | ||
512 | DECODE_EMULATEX (0x0f8000f0, 0x00800090, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc, | ||
513 | REGS(NOPC, NOPC, NOPC, 0, NOPC)), | ||
514 | |||
515 | DECODE_END | ||
516 | }; | ||
517 | |||
518 | static const union decode_item arm_cccc_0001_____1001_table[] = { | ||
519 | /* Synchronization primitives */ | ||
520 | |||
521 | /* SMP/SWPB cccc 0001 0x00 xxxx xxxx xxxx 1001 xxxx */ | ||
522 | DECODE_EMULATEX (0x0fb000f0, 0x01000090, emulate_rd12rn16rm0_rwflags_nopc, | ||
523 | REGS(NOPC, NOPC, 0, 0, NOPC)), | ||
524 | |||
525 | /* LDREX/STREX{,D,B,H} cccc 0001 1xxx xxxx xxxx xxxx 1001 xxxx */ | ||
526 | /* And unallocated instructions... */ | ||
527 | DECODE_END | ||
528 | }; | ||
529 | |||
530 | static const union decode_item arm_cccc_000x_____1xx1_table[] = { | ||
531 | /* Extra load/store instructions */ | ||
532 | |||
533 | /* STRHT cccc 0000 xx10 xxxx xxxx xxxx 1011 xxxx */ | ||
534 | /* ??? cccc 0000 xx10 xxxx xxxx xxxx 11x1 xxxx */ | ||
535 | /* LDRHT cccc 0000 xx11 xxxx xxxx xxxx 1011 xxxx */ | ||
536 | /* LDRSBT cccc 0000 xx11 xxxx xxxx xxxx 1101 xxxx */ | ||
537 | /* LDRSHT cccc 0000 xx11 xxxx xxxx xxxx 1111 xxxx */ | ||
538 | DECODE_REJECT (0x0f200090, 0x00200090), | ||
539 | |||
540 | /* LDRD/STRD lr,pc,{... cccc 000x x0x0 xxxx 111x xxxx 1101 xxxx */ | ||
541 | DECODE_REJECT (0x0e10e0d0, 0x0000e0d0), | ||
542 | |||
543 | /* LDRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1101 xxxx */ | ||
544 | /* STRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx */ | ||
545 | DECODE_EMULATEX (0x0e5000d0, 0x000000d0, emulate_ldrdstrd, | ||
546 | REGS(NOPCWB, NOPCX, 0, 0, NOPC)), | ||
547 | |||
548 | /* LDRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1101 xxxx */ | ||
549 | /* STRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1111 xxxx */ | ||
550 | DECODE_EMULATEX (0x0e5000d0, 0x004000d0, emulate_ldrdstrd, | ||
551 | REGS(NOPCWB, NOPCX, 0, 0, 0)), | ||
552 | |||
553 | /* STRH (register) cccc 000x x0x0 xxxx xxxx xxxx 1011 xxxx */ | ||
554 | DECODE_EMULATEX (0x0e5000f0, 0x000000b0, emulate_str, | ||
555 | REGS(NOPCWB, NOPC, 0, 0, NOPC)), | ||
556 | |||
557 | /* LDRH (register) cccc 000x x0x1 xxxx xxxx xxxx 1011 xxxx */ | ||
558 | /* LDRSB (register) cccc 000x x0x1 xxxx xxxx xxxx 1101 xxxx */ | ||
559 | /* LDRSH (register) cccc 000x x0x1 xxxx xxxx xxxx 1111 xxxx */ | ||
560 | DECODE_EMULATEX (0x0e500090, 0x00100090, emulate_ldr, | ||
561 | REGS(NOPCWB, NOPC, 0, 0, NOPC)), | ||
562 | |||
563 | /* STRH (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1011 xxxx */ | ||
564 | DECODE_EMULATEX (0x0e5000f0, 0x004000b0, emulate_str, | ||
565 | REGS(NOPCWB, NOPC, 0, 0, 0)), | ||
566 | |||
567 | /* LDRH (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1011 xxxx */ | ||
568 | /* LDRSB (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1101 xxxx */ | ||
569 | /* LDRSH (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1111 xxxx */ | ||
570 | DECODE_EMULATEX (0x0e500090, 0x00500090, emulate_ldr, | ||
571 | REGS(NOPCWB, NOPC, 0, 0, 0)), | ||
572 | |||
573 | DECODE_END | ||
574 | }; | ||
575 | |||
576 | static const union decode_item arm_cccc_000x_table[] = { | ||
577 | /* Data-processing (register) */ | ||
578 | |||
579 | /* <op>S PC, ... cccc 000x xxx1 xxxx 1111 xxxx xxxx xxxx */ | ||
580 | DECODE_REJECT (0x0e10f000, 0x0010f000), | ||
581 | |||
582 | /* MOV IP, SP 1110 0001 1010 0000 1100 0000 0000 1101 */ | ||
583 | DECODE_SIMULATE (0xffffffff, 0xe1a0c00d, simulate_mov_ipsp), | ||
584 | |||
585 | /* TST (register) cccc 0001 0001 xxxx xxxx xxxx xxx0 xxxx */ | ||
586 | /* TEQ (register) cccc 0001 0011 xxxx xxxx xxxx xxx0 xxxx */ | ||
587 | /* CMP (register) cccc 0001 0101 xxxx xxxx xxxx xxx0 xxxx */ | ||
588 | /* CMN (register) cccc 0001 0111 xxxx xxxx xxxx xxx0 xxxx */ | ||
589 | DECODE_EMULATEX (0x0f900010, 0x01100000, emulate_rd12rn16rm0rs8_rwflags, | ||
590 | REGS(ANY, 0, 0, 0, ANY)), | ||
591 | |||
592 | /* MOV (register) cccc 0001 101x xxxx xxxx xxxx xxx0 xxxx */ | ||
593 | /* MVN (register) cccc 0001 111x xxxx xxxx xxxx xxx0 xxxx */ | ||
594 | DECODE_EMULATEX (0x0fa00010, 0x01a00000, emulate_rd12rn16rm0rs8_rwflags, | ||
595 | REGS(0, ANY, 0, 0, ANY)), | ||
596 | |||
597 | /* AND (register) cccc 0000 000x xxxx xxxx xxxx xxx0 xxxx */ | ||
598 | /* EOR (register) cccc 0000 001x xxxx xxxx xxxx xxx0 xxxx */ | ||
599 | /* SUB (register) cccc 0000 010x xxxx xxxx xxxx xxx0 xxxx */ | ||
600 | /* RSB (register) cccc 0000 011x xxxx xxxx xxxx xxx0 xxxx */ | ||
601 | /* ADD (register) cccc 0000 100x xxxx xxxx xxxx xxx0 xxxx */ | ||
602 | /* ADC (register) cccc 0000 101x xxxx xxxx xxxx xxx0 xxxx */ | ||
603 | /* SBC (register) cccc 0000 110x xxxx xxxx xxxx xxx0 xxxx */ | ||
604 | /* RSC (register) cccc 0000 111x xxxx xxxx xxxx xxx0 xxxx */ | ||
605 | /* ORR (register) cccc 0001 100x xxxx xxxx xxxx xxx0 xxxx */ | ||
606 | /* BIC (register) cccc 0001 110x xxxx xxxx xxxx xxx0 xxxx */ | ||
607 | DECODE_EMULATEX (0x0e000010, 0x00000000, emulate_rd12rn16rm0rs8_rwflags, | ||
608 | REGS(ANY, ANY, 0, 0, ANY)), | ||
609 | |||
610 | /* TST (reg-shift reg) cccc 0001 0001 xxxx xxxx xxxx 0xx1 xxxx */ | ||
611 | /* TEQ (reg-shift reg) cccc 0001 0011 xxxx xxxx xxxx 0xx1 xxxx */ | ||
612 | /* CMP (reg-shift reg) cccc 0001 0101 xxxx xxxx xxxx 0xx1 xxxx */ | ||
613 | /* CMN (reg-shift reg) cccc 0001 0111 xxxx xxxx xxxx 0xx1 xxxx */ | ||
614 | DECODE_EMULATEX (0x0f900090, 0x01100010, emulate_rd12rn16rm0rs8_rwflags, | ||
615 | REGS(ANY, 0, NOPC, 0, ANY)), | ||
616 | |||
617 | /* MOV (reg-shift reg) cccc 0001 101x xxxx xxxx xxxx 0xx1 xxxx */ | ||
618 | /* MVN (reg-shift reg) cccc 0001 111x xxxx xxxx xxxx 0xx1 xxxx */ | ||
619 | DECODE_EMULATEX (0x0fa00090, 0x01a00010, emulate_rd12rn16rm0rs8_rwflags, | ||
620 | REGS(0, ANY, NOPC, 0, ANY)), | ||
621 | |||
622 | /* AND (reg-shift reg) cccc 0000 000x xxxx xxxx xxxx 0xx1 xxxx */ | ||
623 | /* EOR (reg-shift reg) cccc 0000 001x xxxx xxxx xxxx 0xx1 xxxx */ | ||
624 | /* SUB (reg-shift reg) cccc 0000 010x xxxx xxxx xxxx 0xx1 xxxx */ | ||
625 | /* RSB (reg-shift reg) cccc 0000 011x xxxx xxxx xxxx 0xx1 xxxx */ | ||
626 | /* ADD (reg-shift reg) cccc 0000 100x xxxx xxxx xxxx 0xx1 xxxx */ | ||
627 | /* ADC (reg-shift reg) cccc 0000 101x xxxx xxxx xxxx 0xx1 xxxx */ | ||
628 | /* SBC (reg-shift reg) cccc 0000 110x xxxx xxxx xxxx 0xx1 xxxx */ | ||
629 | /* RSC (reg-shift reg) cccc 0000 111x xxxx xxxx xxxx 0xx1 xxxx */ | ||
630 | /* ORR (reg-shift reg) cccc 0001 100x xxxx xxxx xxxx 0xx1 xxxx */ | ||
631 | /* BIC (reg-shift reg) cccc 0001 110x xxxx xxxx xxxx 0xx1 xxxx */ | ||
632 | DECODE_EMULATEX (0x0e000090, 0x00000010, emulate_rd12rn16rm0rs8_rwflags, | ||
633 | REGS(ANY, ANY, NOPC, 0, ANY)), | ||
634 | |||
635 | DECODE_END | ||
636 | }; | ||
637 | |||
638 | static const union decode_item arm_cccc_001x_table[] = { | ||
639 | /* Data-processing (immediate) */ | ||
640 | |||
641 | /* MOVW cccc 0011 0000 xxxx xxxx xxxx xxxx xxxx */ | ||
642 | /* MOVT cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx */ | ||
643 | DECODE_EMULATEX (0x0fb00000, 0x03000000, emulate_rd12rm0_noflags_nopc, | ||
644 | REGS(0, NOPC, 0, 0, 0)), | ||
645 | |||
646 | /* YIELD cccc 0011 0010 0000 xxxx xxxx 0000 0001 */ | ||
647 | DECODE_OR (0x0fff00ff, 0x03200001), | ||
648 | /* SEV cccc 0011 0010 0000 xxxx xxxx 0000 0100 */ | ||
649 | DECODE_EMULATE (0x0fff00ff, 0x03200004, kprobe_emulate_none), | ||
650 | /* NOP cccc 0011 0010 0000 xxxx xxxx 0000 0000 */ | ||
651 | /* WFE cccc 0011 0010 0000 xxxx xxxx 0000 0010 */ | ||
652 | /* WFI cccc 0011 0010 0000 xxxx xxxx 0000 0011 */ | ||
653 | DECODE_SIMULATE (0x0fff00fc, 0x03200000, kprobe_simulate_nop), | ||
654 | /* DBG cccc 0011 0010 0000 xxxx xxxx ffff xxxx */ | ||
655 | /* unallocated hints cccc 0011 0010 0000 xxxx xxxx xxxx xxxx */ | ||
656 | /* MSR (immediate) cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx */ | ||
657 | DECODE_REJECT (0x0fb00000, 0x03200000), | ||
658 | |||
659 | /* <op>S PC, ... cccc 001x xxx1 xxxx 1111 xxxx xxxx xxxx */ | ||
660 | DECODE_REJECT (0x0e10f000, 0x0210f000), | ||
661 | |||
662 | /* TST (immediate) cccc 0011 0001 xxxx xxxx xxxx xxxx xxxx */ | ||
663 | /* TEQ (immediate) cccc 0011 0011 xxxx xxxx xxxx xxxx xxxx */ | ||
664 | /* CMP (immediate) cccc 0011 0101 xxxx xxxx xxxx xxxx xxxx */ | ||
665 | /* CMN (immediate) cccc 0011 0111 xxxx xxxx xxxx xxxx xxxx */ | ||
666 | DECODE_EMULATEX (0x0f900000, 0x03100000, emulate_rd12rn16rm0rs8_rwflags, | ||
667 | REGS(ANY, 0, 0, 0, 0)), | ||
668 | |||
669 | /* MOV (immediate) cccc 0011 101x xxxx xxxx xxxx xxxx xxxx */ | ||
670 | /* MVN (immediate) cccc 0011 111x xxxx xxxx xxxx xxxx xxxx */ | ||
671 | DECODE_EMULATEX (0x0fa00000, 0x03a00000, emulate_rd12rn16rm0rs8_rwflags, | ||
672 | REGS(0, ANY, 0, 0, 0)), | ||
673 | |||
674 | /* AND (immediate) cccc 0010 000x xxxx xxxx xxxx xxxx xxxx */ | ||
675 | /* EOR (immediate) cccc 0010 001x xxxx xxxx xxxx xxxx xxxx */ | ||
676 | /* SUB (immediate) cccc 0010 010x xxxx xxxx xxxx xxxx xxxx */ | ||
677 | /* RSB (immediate) cccc 0010 011x xxxx xxxx xxxx xxxx xxxx */ | ||
678 | /* ADD (immediate) cccc 0010 100x xxxx xxxx xxxx xxxx xxxx */ | ||
679 | /* ADC (immediate) cccc 0010 101x xxxx xxxx xxxx xxxx xxxx */ | ||
680 | /* SBC (immediate) cccc 0010 110x xxxx xxxx xxxx xxxx xxxx */ | ||
681 | /* RSC (immediate) cccc 0010 111x xxxx xxxx xxxx xxxx xxxx */ | ||
682 | /* ORR (immediate) cccc 0011 100x xxxx xxxx xxxx xxxx xxxx */ | ||
683 | /* BIC (immediate) cccc 0011 110x xxxx xxxx xxxx xxxx xxxx */ | ||
684 | DECODE_EMULATEX (0x0e000000, 0x02000000, emulate_rd12rn16rm0rs8_rwflags, | ||
685 | REGS(ANY, ANY, 0, 0, 0)), | ||
686 | |||
687 | DECODE_END | ||
688 | }; | ||
689 | |||
690 | static const union decode_item arm_cccc_0110_____xxx1_table[] = { | ||
691 | /* Media instructions */ | ||
692 | |||
693 | /* SEL cccc 0110 1000 xxxx xxxx xxxx 1011 xxxx */ | ||
694 | DECODE_EMULATEX (0x0ff000f0, 0x068000b0, emulate_rd12rn16rm0_rwflags_nopc, | ||
695 | REGS(NOPC, NOPC, 0, 0, NOPC)), | ||
696 | |||
697 | /* SSAT cccc 0110 101x xxxx xxxx xxxx xx01 xxxx */ | ||
698 | /* USAT cccc 0110 111x xxxx xxxx xxxx xx01 xxxx */ | ||
699 | DECODE_OR(0x0fa00030, 0x06a00010), | ||
700 | /* SSAT16 cccc 0110 1010 xxxx xxxx xxxx 0011 xxxx */ | ||
701 | /* USAT16 cccc 0110 1110 xxxx xxxx xxxx 0011 xxxx */ | ||
702 | DECODE_EMULATEX (0x0fb000f0, 0x06a00030, emulate_rd12rn16rm0_rwflags_nopc, | ||
703 | REGS(0, NOPC, 0, 0, NOPC)), | ||
704 | |||
705 | /* REV cccc 0110 1011 xxxx xxxx xxxx 0011 xxxx */ | ||
706 | /* REV16 cccc 0110 1011 xxxx xxxx xxxx 1011 xxxx */ | ||
707 | /* RBIT cccc 0110 1111 xxxx xxxx xxxx 0011 xxxx */ | ||
708 | /* REVSH cccc 0110 1111 xxxx xxxx xxxx 1011 xxxx */ | ||
709 | DECODE_EMULATEX (0x0fb00070, 0x06b00030, emulate_rd12rm0_noflags_nopc, | ||
710 | REGS(0, NOPC, 0, 0, NOPC)), | ||
711 | |||
712 | /* ??? cccc 0110 0x00 xxxx xxxx xxxx xxx1 xxxx */ | ||
713 | DECODE_REJECT (0x0fb00010, 0x06000010), | ||
714 | /* ??? cccc 0110 0xxx xxxx xxxx xxxx 1011 xxxx */ | ||
715 | DECODE_REJECT (0x0f8000f0, 0x060000b0), | ||
716 | /* ??? cccc 0110 0xxx xxxx xxxx xxxx 1101 xxxx */ | ||
717 | DECODE_REJECT (0x0f8000f0, 0x060000d0), | ||
718 | /* SADD16 cccc 0110 0001 xxxx xxxx xxxx 0001 xxxx */ | ||
719 | /* SADDSUBX cccc 0110 0001 xxxx xxxx xxxx 0011 xxxx */ | ||
720 | /* SSUBADDX cccc 0110 0001 xxxx xxxx xxxx 0101 xxxx */ | ||
721 | /* SSUB16 cccc 0110 0001 xxxx xxxx xxxx 0111 xxxx */ | ||
722 | /* SADD8 cccc 0110 0001 xxxx xxxx xxxx 1001 xxxx */ | ||
723 | /* SSUB8 cccc 0110 0001 xxxx xxxx xxxx 1111 xxxx */ | ||
724 | /* QADD16 cccc 0110 0010 xxxx xxxx xxxx 0001 xxxx */ | ||
725 | /* QADDSUBX cccc 0110 0010 xxxx xxxx xxxx 0011 xxxx */ | ||
726 | /* QSUBADDX cccc 0110 0010 xxxx xxxx xxxx 0101 xxxx */ | ||
727 | /* QSUB16 cccc 0110 0010 xxxx xxxx xxxx 0111 xxxx */ | ||
728 | /* QADD8 cccc 0110 0010 xxxx xxxx xxxx 1001 xxxx */ | ||
729 | /* QSUB8 cccc 0110 0010 xxxx xxxx xxxx 1111 xxxx */ | ||
730 | /* SHADD16 cccc 0110 0011 xxxx xxxx xxxx 0001 xxxx */ | ||
731 | /* SHADDSUBX cccc 0110 0011 xxxx xxxx xxxx 0011 xxxx */ | ||
732 | /* SHSUBADDX cccc 0110 0011 xxxx xxxx xxxx 0101 xxxx */ | ||
733 | /* SHSUB16 cccc 0110 0011 xxxx xxxx xxxx 0111 xxxx */ | ||
734 | /* SHADD8 cccc 0110 0011 xxxx xxxx xxxx 1001 xxxx */ | ||
735 | /* SHSUB8 cccc 0110 0011 xxxx xxxx xxxx 1111 xxxx */ | ||
736 | /* UADD16 cccc 0110 0101 xxxx xxxx xxxx 0001 xxxx */ | ||
737 | /* UADDSUBX cccc 0110 0101 xxxx xxxx xxxx 0011 xxxx */ | ||
738 | /* USUBADDX cccc 0110 0101 xxxx xxxx xxxx 0101 xxxx */ | ||
739 | /* USUB16 cccc 0110 0101 xxxx xxxx xxxx 0111 xxxx */ | ||
740 | /* UADD8 cccc 0110 0101 xxxx xxxx xxxx 1001 xxxx */ | ||
741 | /* USUB8 cccc 0110 0101 xxxx xxxx xxxx 1111 xxxx */ | ||
742 | /* UQADD16 cccc 0110 0110 xxxx xxxx xxxx 0001 xxxx */ | ||
743 | /* UQADDSUBX cccc 0110 0110 xxxx xxxx xxxx 0011 xxxx */ | ||
744 | /* UQSUBADDX cccc 0110 0110 xxxx xxxx xxxx 0101 xxxx */ | ||
745 | /* UQSUB16 cccc 0110 0110 xxxx xxxx xxxx 0111 xxxx */ | ||
746 | /* UQADD8 cccc 0110 0110 xxxx xxxx xxxx 1001 xxxx */ | ||
747 | /* UQSUB8 cccc 0110 0110 xxxx xxxx xxxx 1111 xxxx */ | ||
748 | /* UHADD16 cccc 0110 0111 xxxx xxxx xxxx 0001 xxxx */ | ||
749 | /* UHADDSUBX cccc 0110 0111 xxxx xxxx xxxx 0011 xxxx */ | ||
750 | /* UHSUBADDX cccc 0110 0111 xxxx xxxx xxxx 0101 xxxx */ | ||
751 | /* UHSUB16 cccc 0110 0111 xxxx xxxx xxxx 0111 xxxx */ | ||
752 | /* UHADD8 cccc 0110 0111 xxxx xxxx xxxx 1001 xxxx */ | ||
753 | /* UHSUB8 cccc 0110 0111 xxxx xxxx xxxx 1111 xxxx */ | ||
754 | DECODE_EMULATEX (0x0f800010, 0x06000010, emulate_rd12rn16rm0_rwflags_nopc, | ||
755 | REGS(NOPC, NOPC, 0, 0, NOPC)), | ||
756 | |||
757 | /* PKHBT cccc 0110 1000 xxxx xxxx xxxx x001 xxxx */ | ||
758 | /* PKHTB cccc 0110 1000 xxxx xxxx xxxx x101 xxxx */ | ||
759 | DECODE_EMULATEX (0x0ff00030, 0x06800010, emulate_rd12rn16rm0_rwflags_nopc, | ||
760 | REGS(NOPC, NOPC, 0, 0, NOPC)), | ||
761 | |||
762 | /* ??? cccc 0110 1001 xxxx xxxx xxxx 0111 xxxx */ | ||
763 | /* ??? cccc 0110 1101 xxxx xxxx xxxx 0111 xxxx */ | ||
764 | DECODE_REJECT (0x0fb000f0, 0x06900070), | ||
765 | |||
766 | /* SXTB16 cccc 0110 1000 1111 xxxx xxxx 0111 xxxx */ | ||
767 | /* SXTB cccc 0110 1010 1111 xxxx xxxx 0111 xxxx */ | ||
768 | /* SXTH cccc 0110 1011 1111 xxxx xxxx 0111 xxxx */ | ||
769 | /* UXTB16 cccc 0110 1100 1111 xxxx xxxx 0111 xxxx */ | ||
770 | /* UXTB cccc 0110 1110 1111 xxxx xxxx 0111 xxxx */ | ||
771 | /* UXTH cccc 0110 1111 1111 xxxx xxxx 0111 xxxx */ | ||
772 | DECODE_EMULATEX (0x0f8f00f0, 0x068f0070, emulate_rd12rm0_noflags_nopc, | ||
773 | REGS(0, NOPC, 0, 0, NOPC)), | ||
774 | |||
775 | /* SXTAB16 cccc 0110 1000 xxxx xxxx xxxx 0111 xxxx */ | ||
776 | /* SXTAB cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx */ | ||
777 | /* SXTAH cccc 0110 1011 xxxx xxxx xxxx 0111 xxxx */ | ||
778 | /* UXTAB16 cccc 0110 1100 xxxx xxxx xxxx 0111 xxxx */ | ||
779 | /* UXTAB cccc 0110 1110 xxxx xxxx xxxx 0111 xxxx */ | ||
780 | /* UXTAH cccc 0110 1111 xxxx xxxx xxxx 0111 xxxx */ | ||
781 | DECODE_EMULATEX (0x0f8000f0, 0x06800070, emulate_rd12rn16rm0_rwflags_nopc, | ||
782 | REGS(NOPCX, NOPC, 0, 0, NOPC)), | ||
783 | |||
784 | DECODE_END | ||
785 | }; | ||
786 | |||
787 | static const union decode_item arm_cccc_0111_____xxx1_table[] = { | ||
788 | /* Media instructions */ | ||
789 | |||
790 | /* UNDEFINED cccc 0111 1111 xxxx xxxx xxxx 1111 xxxx */ | ||
791 | DECODE_REJECT (0x0ff000f0, 0x07f000f0), | ||
792 | |||
793 | /* SMLALD cccc 0111 0100 xxxx xxxx xxxx 00x1 xxxx */ | ||
794 | /* SMLSLD cccc 0111 0100 xxxx xxxx xxxx 01x1 xxxx */ | ||
795 | DECODE_EMULATEX (0x0ff00090, 0x07400010, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc, | ||
796 | REGS(NOPC, NOPC, NOPC, 0, NOPC)), | ||
797 | |||
798 | /* SMUAD cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx */ | ||
799 | /* SMUSD cccc 0111 0000 xxxx 1111 xxxx 01x1 xxxx */ | ||
800 | DECODE_OR (0x0ff0f090, 0x0700f010), | ||
801 | /* SMMUL cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx */ | ||
802 | DECODE_OR (0x0ff0f0d0, 0x0750f010), | ||
803 | /* USAD8 cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx */ | ||
804 | DECODE_EMULATEX (0x0ff0f0f0, 0x0780f010, emulate_rd16rn12rm0rs8_rwflags_nopc, | ||
805 | REGS(NOPC, 0, NOPC, 0, NOPC)), | ||
806 | |||
807 | /* SMLAD cccc 0111 0000 xxxx xxxx xxxx 00x1 xxxx */ | ||
808 | /* SMLSD cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx */ | ||
809 | DECODE_OR (0x0ff00090, 0x07000010), | ||
810 | /* SMMLA cccc 0111 0101 xxxx xxxx xxxx 00x1 xxxx */ | ||
811 | DECODE_OR (0x0ff000d0, 0x07500010), | ||
812 | /* USADA8 cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx */ | ||
813 | DECODE_EMULATEX (0x0ff000f0, 0x07800010, emulate_rd16rn12rm0rs8_rwflags_nopc, | ||
814 | REGS(NOPC, NOPCX, NOPC, 0, NOPC)), | ||
815 | |||
816 | /* SMMLS cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx */ | ||
817 | DECODE_EMULATEX (0x0ff000d0, 0x075000d0, emulate_rd16rn12rm0rs8_rwflags_nopc, | ||
818 | REGS(NOPC, NOPC, NOPC, 0, NOPC)), | ||
819 | |||
820 | /* SBFX cccc 0111 101x xxxx xxxx xxxx x101 xxxx */ | ||
821 | /* UBFX cccc 0111 111x xxxx xxxx xxxx x101 xxxx */ | ||
822 | DECODE_EMULATEX (0x0fa00070, 0x07a00050, emulate_rd12rm0_noflags_nopc, | ||
823 | REGS(0, NOPC, 0, 0, NOPC)), | ||
824 | |||
825 | /* BFC cccc 0111 110x xxxx xxxx xxxx x001 1111 */ | ||
826 | DECODE_EMULATEX (0x0fe0007f, 0x07c0001f, emulate_rd12rm0_noflags_nopc, | ||
827 | REGS(0, NOPC, 0, 0, 0)), | ||
828 | |||
829 | /* BFI cccc 0111 110x xxxx xxxx xxxx x001 xxxx */ | ||
830 | DECODE_EMULATEX (0x0fe00070, 0x07c00010, emulate_rd12rm0_noflags_nopc, | ||
831 | REGS(0, NOPC, 0, 0, NOPCX)), | ||
832 | |||
833 | DECODE_END | ||
834 | }; | ||
835 | |||
836 | static const union decode_item arm_cccc_01xx_table[] = { | ||
837 | /* Load/store word and unsigned byte */ | ||
838 | |||
839 | /* LDRB/STRB pc,[...] cccc 01xx x0xx xxxx xxxx xxxx xxxx xxxx */ | ||
840 | DECODE_REJECT (0x0c40f000, 0x0440f000), | ||
841 | |||
842 | /* STRT cccc 01x0 x010 xxxx xxxx xxxx xxxx xxxx */ | ||
843 | /* LDRT cccc 01x0 x011 xxxx xxxx xxxx xxxx xxxx */ | ||
844 | /* STRBT cccc 01x0 x110 xxxx xxxx xxxx xxxx xxxx */ | ||
845 | /* LDRBT cccc 01x0 x111 xxxx xxxx xxxx xxxx xxxx */ | ||
846 | DECODE_REJECT (0x0d200000, 0x04200000), | ||
847 | |||
848 | /* STR (immediate) cccc 010x x0x0 xxxx xxxx xxxx xxxx xxxx */ | ||
849 | /* STRB (immediate) cccc 010x x1x0 xxxx xxxx xxxx xxxx xxxx */ | ||
850 | DECODE_EMULATEX (0x0e100000, 0x04000000, emulate_str, | ||
851 | REGS(NOPCWB, ANY, 0, 0, 0)), | ||
852 | |||
853 | /* LDR (immediate) cccc 010x x0x1 xxxx xxxx xxxx xxxx xxxx */ | ||
854 | /* LDRB (immediate) cccc 010x x1x1 xxxx xxxx xxxx xxxx xxxx */ | ||
855 | DECODE_EMULATEX (0x0e100000, 0x04100000, emulate_ldr, | ||
856 | REGS(NOPCWB, ANY, 0, 0, 0)), | ||
857 | |||
858 | /* STR (register) cccc 011x x0x0 xxxx xxxx xxxx xxxx xxxx */ | ||
859 | /* STRB (register) cccc 011x x1x0 xxxx xxxx xxxx xxxx xxxx */ | ||
860 | DECODE_EMULATEX (0x0e100000, 0x06000000, emulate_str, | ||
861 | REGS(NOPCWB, ANY, 0, 0, NOPC)), | ||
862 | |||
863 | /* LDR (register) cccc 011x x0x1 xxxx xxxx xxxx xxxx xxxx */ | ||
864 | /* LDRB (register) cccc 011x x1x1 xxxx xxxx xxxx xxxx xxxx */ | ||
865 | DECODE_EMULATEX (0x0e100000, 0x06100000, emulate_ldr, | ||
866 | REGS(NOPCWB, ANY, 0, 0, NOPC)), | ||
867 | |||
868 | DECODE_END | ||
869 | }; | ||
870 | |||
871 | static const union decode_item arm_cccc_100x_table[] = { | ||
872 | /* Block data transfer instructions */ | ||
873 | |||
874 | /* LDM cccc 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ | ||
875 | /* STM cccc 100x x0x0 xxxx xxxx xxxx xxxx xxxx */ | ||
876 | DECODE_CUSTOM (0x0e400000, 0x08000000, kprobe_decode_ldmstm), | ||
877 | |||
878 | /* STM (user registers) cccc 100x x1x0 xxxx xxxx xxxx xxxx xxxx */ | ||
879 | /* LDM (user registers) cccc 100x x1x1 xxxx 0xxx xxxx xxxx xxxx */ | ||
880 | /* LDM (exception ret) cccc 100x x1x1 xxxx 1xxx xxxx xxxx xxxx */ | ||
881 | DECODE_END | ||
882 | }; | ||
883 | |||
884 | const union decode_item kprobe_decode_arm_table[] = { | ||
885 | /* | ||
886 | * Unconditional instructions | ||
887 | * 1111 xxxx xxxx xxxx xxxx xxxx xxxx xxxx | ||
888 | */ | ||
889 | DECODE_TABLE (0xf0000000, 0xf0000000, arm_1111_table), | ||
890 | |||
891 | /* | ||
892 | * Miscellaneous instructions | ||
893 | * cccc 0001 0xx0 xxxx xxxx xxxx 0xxx xxxx | ||
894 | */ | ||
895 | DECODE_TABLE (0x0f900080, 0x01000000, arm_cccc_0001_0xx0____0xxx_table), | ||
896 | |||
897 | /* | ||
898 | * Halfword multiply and multiply-accumulate | ||
899 | * cccc 0001 0xx0 xxxx xxxx xxxx 1xx0 xxxx | ||
900 | */ | ||
901 | DECODE_TABLE (0x0f900090, 0x01000080, arm_cccc_0001_0xx0____1xx0_table), | ||
902 | |||
903 | /* | ||
904 | * Multiply and multiply-accumulate | ||
905 | * cccc 0000 xxxx xxxx xxxx xxxx 1001 xxxx | ||
906 | */ | ||
907 | DECODE_TABLE (0x0f0000f0, 0x00000090, arm_cccc_0000_____1001_table), | ||
908 | |||
909 | /* | ||
910 | * Synchronization primitives | ||
911 | * cccc 0001 xxxx xxxx xxxx xxxx 1001 xxxx | ||
912 | */ | ||
913 | DECODE_TABLE (0x0f0000f0, 0x01000090, arm_cccc_0001_____1001_table), | ||
914 | |||
915 | /* | ||
916 | * Extra load/store instructions | ||
917 | * cccc 000x xxxx xxxx xxxx xxxx 1xx1 xxxx | ||
918 | */ | ||
919 | DECODE_TABLE (0x0e000090, 0x00000090, arm_cccc_000x_____1xx1_table), | ||
920 | |||
921 | /* | ||
922 | * Data-processing (register) | ||
923 | * cccc 000x xxxx xxxx xxxx xxxx xxx0 xxxx | ||
924 | * Data-processing (register-shifted register) | ||
925 | * cccc 000x xxxx xxxx xxxx xxxx 0xx1 xxxx | ||
926 | */ | ||
927 | DECODE_TABLE (0x0e000000, 0x00000000, arm_cccc_000x_table), | ||
928 | |||
929 | /* | ||
930 | * Data-processing (immediate) | ||
931 | * cccc 001x xxxx xxxx xxxx xxxx xxxx xxxx | ||
932 | */ | ||
933 | DECODE_TABLE (0x0e000000, 0x02000000, arm_cccc_001x_table), | ||
934 | |||
935 | /* | ||
936 | * Media instructions | ||
937 | * cccc 011x xxxx xxxx xxxx xxxx xxx1 xxxx | ||
938 | */ | ||
939 | DECODE_TABLE (0x0f000010, 0x06000010, arm_cccc_0110_____xxx1_table), | ||
940 | DECODE_TABLE (0x0f000010, 0x07000010, arm_cccc_0111_____xxx1_table), | ||
941 | |||
942 | /* | ||
943 | * Load/store word and unsigned byte | ||
944 | * cccc 01xx xxxx xxxx xxxx xxxx xxxx xxxx | ||
945 | */ | ||
946 | DECODE_TABLE (0x0c000000, 0x04000000, arm_cccc_01xx_table), | ||
947 | |||
948 | /* | ||
949 | * Block data transfer instructions | ||
950 | * cccc 100x xxxx xxxx xxxx xxxx xxxx xxxx | ||
951 | */ | ||
952 | DECODE_TABLE (0x0e000000, 0x08000000, arm_cccc_100x_table), | ||
953 | |||
954 | /* B cccc 1010 xxxx xxxx xxxx xxxx xxxx xxxx */ | ||
955 | /* BL cccc 1011 xxxx xxxx xxxx xxxx xxxx xxxx */ | ||
956 | DECODE_SIMULATE (0x0e000000, 0x0a000000, simulate_bbl), | ||
957 | |||
958 | /* | ||
959 | * Supervisor Call, and coprocessor instructions | ||
960 | */ | ||
961 | |||
962 | /* MCRR cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx */ | ||
963 | /* MRRC cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx */ | ||
964 | /* LDC cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ | ||
965 | /* STC cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ | ||
966 | /* CDP cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ | ||
967 | /* MCR cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ | ||
968 | /* MRC cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ | ||
969 | /* SVC cccc 1111 xxxx xxxx xxxx xxxx xxxx xxxx */ | ||
970 | DECODE_REJECT (0x0c000000, 0x0c000000), | ||
971 | |||
972 | DECODE_END | ||
973 | }; | ||
974 | |||
975 | static void __kprobes arm_singlestep(struct kprobe *p, struct pt_regs *regs) | ||
976 | { | ||
977 | regs->ARM_pc += 4; | ||
978 | p->ainsn.insn_handler(p, regs); | ||
979 | } | ||
980 | |||
981 | /* Return: | ||
982 | * INSN_REJECTED If instruction is one not allowed to kprobe, | ||
983 | * INSN_GOOD If instruction is supported and uses instruction slot, | ||
984 | * INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot. | ||
985 | * | ||
986 | * For instructions we don't want to kprobe (INSN_REJECTED return result): | ||
987 | * These are generally ones that modify the processor state making | ||
988 | * them "hard" to simulate such as switches processor modes or | ||
989 | * make accesses in alternate modes. Any of these could be simulated | ||
990 | * if the work was put into it, but low return considering they | ||
991 | * should also be very rare. | ||
992 | */ | ||
993 | enum kprobe_insn __kprobes | ||
994 | arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
995 | { | ||
996 | asi->insn_singlestep = arm_singlestep; | ||
997 | asi->insn_check_cc = kprobe_condition_checks[insn>>28]; | ||
998 | return kprobe_decode_insn(insn, asi, kprobe_decode_arm_table, false); | ||
999 | } | ||