diff options
Diffstat (limited to 'arch/arm/kernel/kprobes-thumb.c')
-rw-r--r-- | arch/arm/kernel/kprobes-thumb.c | 1462 |
1 files changed, 1462 insertions, 0 deletions
diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/kernel/kprobes-thumb.c new file mode 100644 index 000000000000..902ca59e8b11 --- /dev/null +++ b/arch/arm/kernel/kprobes-thumb.c | |||
@@ -0,0 +1,1462 @@ | |||
1 | /* | ||
2 | * arch/arm/kernel/kprobes-thumb.c | ||
3 | * | ||
4 | * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>. | ||
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 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/kprobes.h> | ||
13 | |||
14 | #include "kprobes.h" | ||
15 | |||
16 | |||
17 | /* | ||
18 | * True if current instruction is in an IT block. | ||
19 | */ | ||
20 | #define in_it_block(cpsr) ((cpsr & 0x06000c00) != 0x00000000) | ||
21 | |||
22 | /* | ||
23 | * Return the condition code to check for the currently executing instruction. | ||
24 | * This is in ITSTATE<7:4> which is in CPSR<15:12> but is only valid if | ||
25 | * in_it_block returns true. | ||
26 | */ | ||
27 | #define current_cond(cpsr) ((cpsr >> 12) & 0xf) | ||
28 | |||
29 | /* | ||
30 | * Return the PC value for a probe in thumb code. | ||
31 | * This is the address of the probed instruction plus 4. | ||
32 | * We subtract one because the address will have bit zero set to indicate | ||
33 | * a pointer to thumb code. | ||
34 | */ | ||
35 | static inline unsigned long __kprobes thumb_probe_pc(struct kprobe *p) | ||
36 | { | ||
37 | return (unsigned long)p->addr - 1 + 4; | ||
38 | } | ||
39 | |||
40 | static void __kprobes | ||
41 | t32_simulate_table_branch(struct kprobe *p, struct pt_regs *regs) | ||
42 | { | ||
43 | kprobe_opcode_t insn = p->opcode; | ||
44 | unsigned long pc = thumb_probe_pc(p); | ||
45 | int rn = (insn >> 16) & 0xf; | ||
46 | int rm = insn & 0xf; | ||
47 | |||
48 | unsigned long rnv = (rn == 15) ? pc : regs->uregs[rn]; | ||
49 | unsigned long rmv = regs->uregs[rm]; | ||
50 | unsigned int halfwords; | ||
51 | |||
52 | if (insn & 0x10) /* TBH */ | ||
53 | halfwords = ((u16 *)rnv)[rmv]; | ||
54 | else /* TBB */ | ||
55 | halfwords = ((u8 *)rnv)[rmv]; | ||
56 | |||
57 | regs->ARM_pc = pc + 2 * halfwords; | ||
58 | } | ||
59 | |||
60 | static void __kprobes | ||
61 | t32_simulate_mrs(struct kprobe *p, struct pt_regs *regs) | ||
62 | { | ||
63 | kprobe_opcode_t insn = p->opcode; | ||
64 | int rd = (insn >> 8) & 0xf; | ||
65 | unsigned long mask = 0xf8ff03df; /* Mask out execution state */ | ||
66 | regs->uregs[rd] = regs->ARM_cpsr & mask; | ||
67 | } | ||
68 | |||
69 | static void __kprobes | ||
70 | t32_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs) | ||
71 | { | ||
72 | kprobe_opcode_t insn = p->opcode; | ||
73 | unsigned long pc = thumb_probe_pc(p); | ||
74 | |||
75 | long offset = insn & 0x7ff; /* imm11 */ | ||
76 | offset += (insn & 0x003f0000) >> 5; /* imm6 */ | ||
77 | offset += (insn & 0x00002000) << 4; /* J1 */ | ||
78 | offset += (insn & 0x00000800) << 7; /* J2 */ | ||
79 | offset -= (insn & 0x04000000) >> 7; /* Apply sign bit */ | ||
80 | |||
81 | regs->ARM_pc = pc + (offset * 2); | ||
82 | } | ||
83 | |||
84 | static enum kprobe_insn __kprobes | ||
85 | t32_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
86 | { | ||
87 | int cc = (insn >> 22) & 0xf; | ||
88 | asi->insn_check_cc = kprobe_condition_checks[cc]; | ||
89 | asi->insn_handler = t32_simulate_cond_branch; | ||
90 | return INSN_GOOD_NO_SLOT; | ||
91 | } | ||
92 | |||
93 | static void __kprobes | ||
94 | t32_simulate_branch(struct kprobe *p, struct pt_regs *regs) | ||
95 | { | ||
96 | kprobe_opcode_t insn = p->opcode; | ||
97 | unsigned long pc = thumb_probe_pc(p); | ||
98 | |||
99 | long offset = insn & 0x7ff; /* imm11 */ | ||
100 | offset += (insn & 0x03ff0000) >> 5; /* imm10 */ | ||
101 | offset += (insn & 0x00002000) << 9; /* J1 */ | ||
102 | offset += (insn & 0x00000800) << 10; /* J2 */ | ||
103 | if (insn & 0x04000000) | ||
104 | offset -= 0x00800000; /* Apply sign bit */ | ||
105 | else | ||
106 | offset ^= 0x00600000; /* Invert J1 and J2 */ | ||
107 | |||
108 | if (insn & (1 << 14)) { | ||
109 | /* BL or BLX */ | ||
110 | regs->ARM_lr = (unsigned long)p->addr + 4; | ||
111 | if (!(insn & (1 << 12))) { | ||
112 | /* BLX so switch to ARM mode */ | ||
113 | regs->ARM_cpsr &= ~PSR_T_BIT; | ||
114 | pc &= ~3; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | regs->ARM_pc = pc + (offset * 2); | ||
119 | } | ||
120 | |||
121 | static void __kprobes | ||
122 | t32_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs) | ||
123 | { | ||
124 | kprobe_opcode_t insn = p->opcode; | ||
125 | unsigned long addr = thumb_probe_pc(p) & ~3; | ||
126 | int rt = (insn >> 12) & 0xf; | ||
127 | unsigned long rtv; | ||
128 | |||
129 | long offset = insn & 0xfff; | ||
130 | if (insn & 0x00800000) | ||
131 | addr += offset; | ||
132 | else | ||
133 | addr -= offset; | ||
134 | |||
135 | if (insn & 0x00400000) { | ||
136 | /* LDR */ | ||
137 | rtv = *(unsigned long *)addr; | ||
138 | if (rt == 15) { | ||
139 | bx_write_pc(rtv, regs); | ||
140 | return; | ||
141 | } | ||
142 | } else if (insn & 0x00200000) { | ||
143 | /* LDRH */ | ||
144 | if (insn & 0x01000000) | ||
145 | rtv = *(s16 *)addr; | ||
146 | else | ||
147 | rtv = *(u16 *)addr; | ||
148 | } else { | ||
149 | /* LDRB */ | ||
150 | if (insn & 0x01000000) | ||
151 | rtv = *(s8 *)addr; | ||
152 | else | ||
153 | rtv = *(u8 *)addr; | ||
154 | } | ||
155 | |||
156 | regs->uregs[rt] = rtv; | ||
157 | } | ||
158 | |||
159 | static enum kprobe_insn __kprobes | ||
160 | t32_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
161 | { | ||
162 | enum kprobe_insn ret = kprobe_decode_ldmstm(insn, asi); | ||
163 | |||
164 | /* Fixup modified instruction to have halfwords in correct order...*/ | ||
165 | insn = asi->insn[0]; | ||
166 | ((u16 *)asi->insn)[0] = insn >> 16; | ||
167 | ((u16 *)asi->insn)[1] = insn & 0xffff; | ||
168 | |||
169 | return ret; | ||
170 | } | ||
171 | |||
172 | static void __kprobes | ||
173 | t32_emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) | ||
174 | { | ||
175 | kprobe_opcode_t insn = p->opcode; | ||
176 | unsigned long pc = thumb_probe_pc(p) & ~3; | ||
177 | int rt1 = (insn >> 12) & 0xf; | ||
178 | int rt2 = (insn >> 8) & 0xf; | ||
179 | int rn = (insn >> 16) & 0xf; | ||
180 | |||
181 | register unsigned long rt1v asm("r0") = regs->uregs[rt1]; | ||
182 | register unsigned long rt2v asm("r1") = regs->uregs[rt2]; | ||
183 | register unsigned long rnv asm("r2") = (rn == 15) ? pc | ||
184 | : regs->uregs[rn]; | ||
185 | |||
186 | __asm__ __volatile__ ( | ||
187 | "blx %[fn]" | ||
188 | : "=r" (rt1v), "=r" (rt2v), "=r" (rnv) | ||
189 | : "0" (rt1v), "1" (rt2v), "2" (rnv), [fn] "r" (p->ainsn.insn_fn) | ||
190 | : "lr", "memory", "cc" | ||
191 | ); | ||
192 | |||
193 | if (rn != 15) | ||
194 | regs->uregs[rn] = rnv; /* Writeback base register */ | ||
195 | regs->uregs[rt1] = rt1v; | ||
196 | regs->uregs[rt2] = rt2v; | ||
197 | } | ||
198 | |||
199 | static void __kprobes | ||
200 | t32_emulate_ldrstr(struct kprobe *p, struct pt_regs *regs) | ||
201 | { | ||
202 | kprobe_opcode_t insn = p->opcode; | ||
203 | int rt = (insn >> 12) & 0xf; | ||
204 | int rn = (insn >> 16) & 0xf; | ||
205 | int rm = insn & 0xf; | ||
206 | |||
207 | register unsigned long rtv asm("r0") = regs->uregs[rt]; | ||
208 | register unsigned long rnv asm("r2") = regs->uregs[rn]; | ||
209 | register unsigned long rmv asm("r3") = regs->uregs[rm]; | ||
210 | |||
211 | __asm__ __volatile__ ( | ||
212 | "blx %[fn]" | ||
213 | : "=r" (rtv), "=r" (rnv) | ||
214 | : "0" (rtv), "1" (rnv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn) | ||
215 | : "lr", "memory", "cc" | ||
216 | ); | ||
217 | |||
218 | regs->uregs[rn] = rnv; /* Writeback base register */ | ||
219 | if (rt == 15) /* Can't be true for a STR as they aren't allowed */ | ||
220 | bx_write_pc(rtv, regs); | ||
221 | else | ||
222 | regs->uregs[rt] = rtv; | ||
223 | } | ||
224 | |||
225 | static void __kprobes | ||
226 | t32_emulate_rd8rn16rm0_rwflags(struct kprobe *p, struct pt_regs *regs) | ||
227 | { | ||
228 | kprobe_opcode_t insn = p->opcode; | ||
229 | int rd = (insn >> 8) & 0xf; | ||
230 | int rn = (insn >> 16) & 0xf; | ||
231 | int rm = insn & 0xf; | ||
232 | |||
233 | register unsigned long rdv asm("r1") = regs->uregs[rd]; | ||
234 | register unsigned long rnv asm("r2") = regs->uregs[rn]; | ||
235 | register unsigned long rmv asm("r3") = regs->uregs[rm]; | ||
236 | unsigned long cpsr = regs->ARM_cpsr; | ||
237 | |||
238 | __asm__ __volatile__ ( | ||
239 | "msr cpsr_fs, %[cpsr] \n\t" | ||
240 | "blx %[fn] \n\t" | ||
241 | "mrs %[cpsr], cpsr \n\t" | ||
242 | : "=r" (rdv), [cpsr] "=r" (cpsr) | ||
243 | : "0" (rdv), "r" (rnv), "r" (rmv), | ||
244 | "1" (cpsr), [fn] "r" (p->ainsn.insn_fn) | ||
245 | : "lr", "memory", "cc" | ||
246 | ); | ||
247 | |||
248 | regs->uregs[rd] = rdv; | ||
249 | regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); | ||
250 | } | ||
251 | |||
252 | static void __kprobes | ||
253 | t32_emulate_rd8pc16_noflags(struct kprobe *p, struct pt_regs *regs) | ||
254 | { | ||
255 | kprobe_opcode_t insn = p->opcode; | ||
256 | unsigned long pc = thumb_probe_pc(p); | ||
257 | int rd = (insn >> 8) & 0xf; | ||
258 | |||
259 | register unsigned long rdv asm("r1") = regs->uregs[rd]; | ||
260 | register unsigned long rnv asm("r2") = pc & ~3; | ||
261 | |||
262 | __asm__ __volatile__ ( | ||
263 | "blx %[fn]" | ||
264 | : "=r" (rdv) | ||
265 | : "0" (rdv), "r" (rnv), [fn] "r" (p->ainsn.insn_fn) | ||
266 | : "lr", "memory", "cc" | ||
267 | ); | ||
268 | |||
269 | regs->uregs[rd] = rdv; | ||
270 | } | ||
271 | |||
272 | static void __kprobes | ||
273 | t32_emulate_rd8rn16_noflags(struct kprobe *p, struct pt_regs *regs) | ||
274 | { | ||
275 | kprobe_opcode_t insn = p->opcode; | ||
276 | int rd = (insn >> 8) & 0xf; | ||
277 | int rn = (insn >> 16) & 0xf; | ||
278 | |||
279 | register unsigned long rdv asm("r1") = regs->uregs[rd]; | ||
280 | register unsigned long rnv asm("r2") = regs->uregs[rn]; | ||
281 | |||
282 | __asm__ __volatile__ ( | ||
283 | "blx %[fn]" | ||
284 | : "=r" (rdv) | ||
285 | : "0" (rdv), "r" (rnv), [fn] "r" (p->ainsn.insn_fn) | ||
286 | : "lr", "memory", "cc" | ||
287 | ); | ||
288 | |||
289 | regs->uregs[rd] = rdv; | ||
290 | } | ||
291 | |||
292 | static void __kprobes | ||
293 | t32_emulate_rdlo12rdhi8rn16rm0_noflags(struct kprobe *p, struct pt_regs *regs) | ||
294 | { | ||
295 | kprobe_opcode_t insn = p->opcode; | ||
296 | int rdlo = (insn >> 12) & 0xf; | ||
297 | int rdhi = (insn >> 8) & 0xf; | ||
298 | int rn = (insn >> 16) & 0xf; | ||
299 | int rm = insn & 0xf; | ||
300 | |||
301 | register unsigned long rdlov asm("r0") = regs->uregs[rdlo]; | ||
302 | register unsigned long rdhiv asm("r1") = regs->uregs[rdhi]; | ||
303 | register unsigned long rnv asm("r2") = regs->uregs[rn]; | ||
304 | register unsigned long rmv asm("r3") = regs->uregs[rm]; | ||
305 | |||
306 | __asm__ __volatile__ ( | ||
307 | "blx %[fn]" | ||
308 | : "=r" (rdlov), "=r" (rdhiv) | ||
309 | : "0" (rdlov), "1" (rdhiv), "r" (rnv), "r" (rmv), | ||
310 | [fn] "r" (p->ainsn.insn_fn) | ||
311 | : "lr", "memory", "cc" | ||
312 | ); | ||
313 | |||
314 | regs->uregs[rdlo] = rdlov; | ||
315 | regs->uregs[rdhi] = rdhiv; | ||
316 | } | ||
317 | |||
318 | /* These emulation encodings are functionally equivalent... */ | ||
319 | #define t32_emulate_rd8rn16rm0ra12_noflags \ | ||
320 | t32_emulate_rdlo12rdhi8rn16rm0_noflags | ||
321 | |||
322 | static const union decode_item t32_table_1110_100x_x0xx[] = { | ||
323 | /* Load/store multiple instructions */ | ||
324 | |||
325 | /* Rn is PC 1110 100x x0xx 1111 xxxx xxxx xxxx xxxx */ | ||
326 | DECODE_REJECT (0xfe4f0000, 0xe80f0000), | ||
327 | |||
328 | /* SRS 1110 1000 00x0 xxxx xxxx xxxx xxxx xxxx */ | ||
329 | /* RFE 1110 1000 00x1 xxxx xxxx xxxx xxxx xxxx */ | ||
330 | DECODE_REJECT (0xffc00000, 0xe8000000), | ||
331 | /* SRS 1110 1001 10x0 xxxx xxxx xxxx xxxx xxxx */ | ||
332 | /* RFE 1110 1001 10x1 xxxx xxxx xxxx xxxx xxxx */ | ||
333 | DECODE_REJECT (0xffc00000, 0xe9800000), | ||
334 | |||
335 | /* STM Rn, {...pc} 1110 100x x0x0 xxxx 1xxx xxxx xxxx xxxx */ | ||
336 | DECODE_REJECT (0xfe508000, 0xe8008000), | ||
337 | /* LDM Rn, {...lr,pc} 1110 100x x0x1 xxxx 11xx xxxx xxxx xxxx */ | ||
338 | DECODE_REJECT (0xfe50c000, 0xe810c000), | ||
339 | /* LDM/STM Rn, {...sp} 1110 100x x0xx xxxx xx1x xxxx xxxx xxxx */ | ||
340 | DECODE_REJECT (0xfe402000, 0xe8002000), | ||
341 | |||
342 | /* STMIA 1110 1000 10x0 xxxx xxxx xxxx xxxx xxxx */ | ||
343 | /* LDMIA 1110 1000 10x1 xxxx xxxx xxxx xxxx xxxx */ | ||
344 | /* STMDB 1110 1001 00x0 xxxx xxxx xxxx xxxx xxxx */ | ||
345 | /* LDMDB 1110 1001 00x1 xxxx xxxx xxxx xxxx xxxx */ | ||
346 | DECODE_CUSTOM (0xfe400000, 0xe8000000, t32_decode_ldmstm), | ||
347 | |||
348 | DECODE_END | ||
349 | }; | ||
350 | |||
351 | static const union decode_item t32_table_1110_100x_x1xx[] = { | ||
352 | /* Load/store dual, load/store exclusive, table branch */ | ||
353 | |||
354 | /* STRD (immediate) 1110 1000 x110 xxxx xxxx xxxx xxxx xxxx */ | ||
355 | /* LDRD (immediate) 1110 1000 x111 xxxx xxxx xxxx xxxx xxxx */ | ||
356 | DECODE_OR (0xff600000, 0xe8600000), | ||
357 | /* STRD (immediate) 1110 1001 x1x0 xxxx xxxx xxxx xxxx xxxx */ | ||
358 | /* LDRD (immediate) 1110 1001 x1x1 xxxx xxxx xxxx xxxx xxxx */ | ||
359 | DECODE_EMULATEX (0xff400000, 0xe9400000, t32_emulate_ldrdstrd, | ||
360 | REGS(NOPCWB, NOSPPC, NOSPPC, 0, 0)), | ||
361 | |||
362 | /* TBB 1110 1000 1101 xxxx xxxx xxxx 0000 xxxx */ | ||
363 | /* TBH 1110 1000 1101 xxxx xxxx xxxx 0001 xxxx */ | ||
364 | DECODE_SIMULATEX(0xfff000e0, 0xe8d00000, t32_simulate_table_branch, | ||
365 | REGS(NOSP, 0, 0, 0, NOSPPC)), | ||
366 | |||
367 | /* STREX 1110 1000 0100 xxxx xxxx xxxx xxxx xxxx */ | ||
368 | /* LDREX 1110 1000 0101 xxxx xxxx xxxx xxxx xxxx */ | ||
369 | /* STREXB 1110 1000 1100 xxxx xxxx xxxx 0100 xxxx */ | ||
370 | /* STREXH 1110 1000 1100 xxxx xxxx xxxx 0101 xxxx */ | ||
371 | /* STREXD 1110 1000 1100 xxxx xxxx xxxx 0111 xxxx */ | ||
372 | /* LDREXB 1110 1000 1101 xxxx xxxx xxxx 0100 xxxx */ | ||
373 | /* LDREXH 1110 1000 1101 xxxx xxxx xxxx 0101 xxxx */ | ||
374 | /* LDREXD 1110 1000 1101 xxxx xxxx xxxx 0111 xxxx */ | ||
375 | /* And unallocated instructions... */ | ||
376 | DECODE_END | ||
377 | }; | ||
378 | |||
379 | static const union decode_item t32_table_1110_101x[] = { | ||
380 | /* Data-processing (shifted register) */ | ||
381 | |||
382 | /* TST 1110 1010 0001 xxxx xxxx 1111 xxxx xxxx */ | ||
383 | /* TEQ 1110 1010 1001 xxxx xxxx 1111 xxxx xxxx */ | ||
384 | DECODE_EMULATEX (0xff700f00, 0xea100f00, t32_emulate_rd8rn16rm0_rwflags, | ||
385 | REGS(NOSPPC, 0, 0, 0, NOSPPC)), | ||
386 | |||
387 | /* CMN 1110 1011 0001 xxxx xxxx 1111 xxxx xxxx */ | ||
388 | DECODE_OR (0xfff00f00, 0xeb100f00), | ||
389 | /* CMP 1110 1011 1011 xxxx xxxx 1111 xxxx xxxx */ | ||
390 | DECODE_EMULATEX (0xfff00f00, 0xebb00f00, t32_emulate_rd8rn16rm0_rwflags, | ||
391 | REGS(NOPC, 0, 0, 0, NOSPPC)), | ||
392 | |||
393 | /* MOV 1110 1010 010x 1111 xxxx xxxx xxxx xxxx */ | ||
394 | /* MVN 1110 1010 011x 1111 xxxx xxxx xxxx xxxx */ | ||
395 | DECODE_EMULATEX (0xffcf0000, 0xea4f0000, t32_emulate_rd8rn16rm0_rwflags, | ||
396 | REGS(0, 0, NOSPPC, 0, NOSPPC)), | ||
397 | |||
398 | /* ??? 1110 1010 101x xxxx xxxx xxxx xxxx xxxx */ | ||
399 | /* ??? 1110 1010 111x xxxx xxxx xxxx xxxx xxxx */ | ||
400 | DECODE_REJECT (0xffa00000, 0xeaa00000), | ||
401 | /* ??? 1110 1011 001x xxxx xxxx xxxx xxxx xxxx */ | ||
402 | DECODE_REJECT (0xffe00000, 0xeb200000), | ||
403 | /* ??? 1110 1011 100x xxxx xxxx xxxx xxxx xxxx */ | ||
404 | DECODE_REJECT (0xffe00000, 0xeb800000), | ||
405 | /* ??? 1110 1011 111x xxxx xxxx xxxx xxxx xxxx */ | ||
406 | DECODE_REJECT (0xffe00000, 0xebe00000), | ||
407 | |||
408 | /* ADD/SUB SP, SP, Rm, LSL #0..3 */ | ||
409 | /* 1110 1011 x0xx 1101 x000 1101 xx00 xxxx */ | ||
410 | DECODE_EMULATEX (0xff4f7f30, 0xeb0d0d00, t32_emulate_rd8rn16rm0_rwflags, | ||
411 | REGS(SP, 0, SP, 0, NOSPPC)), | ||
412 | |||
413 | /* ADD/SUB SP, SP, Rm, shift */ | ||
414 | /* 1110 1011 x0xx 1101 xxxx 1101 xxxx xxxx */ | ||
415 | DECODE_REJECT (0xff4f0f00, 0xeb0d0d00), | ||
416 | |||
417 | /* ADD/SUB Rd, SP, Rm, shift */ | ||
418 | /* 1110 1011 x0xx 1101 xxxx xxxx xxxx xxxx */ | ||
419 | DECODE_EMULATEX (0xff4f0000, 0xeb0d0000, t32_emulate_rd8rn16rm0_rwflags, | ||
420 | REGS(SP, 0, NOPC, 0, NOSPPC)), | ||
421 | |||
422 | /* AND 1110 1010 000x xxxx xxxx xxxx xxxx xxxx */ | ||
423 | /* BIC 1110 1010 001x xxxx xxxx xxxx xxxx xxxx */ | ||
424 | /* ORR 1110 1010 010x xxxx xxxx xxxx xxxx xxxx */ | ||
425 | /* ORN 1110 1010 011x xxxx xxxx xxxx xxxx xxxx */ | ||
426 | /* EOR 1110 1010 100x xxxx xxxx xxxx xxxx xxxx */ | ||
427 | /* PKH 1110 1010 110x xxxx xxxx xxxx xxxx xxxx */ | ||
428 | /* ADD 1110 1011 000x xxxx xxxx xxxx xxxx xxxx */ | ||
429 | /* ADC 1110 1011 010x xxxx xxxx xxxx xxxx xxxx */ | ||
430 | /* SBC 1110 1011 011x xxxx xxxx xxxx xxxx xxxx */ | ||
431 | /* SUB 1110 1011 101x xxxx xxxx xxxx xxxx xxxx */ | ||
432 | /* RSB 1110 1011 110x xxxx xxxx xxxx xxxx xxxx */ | ||
433 | DECODE_EMULATEX (0xfe000000, 0xea000000, t32_emulate_rd8rn16rm0_rwflags, | ||
434 | REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)), | ||
435 | |||
436 | DECODE_END | ||
437 | }; | ||
438 | |||
439 | static const union decode_item t32_table_1111_0x0x___0[] = { | ||
440 | /* Data-processing (modified immediate) */ | ||
441 | |||
442 | /* TST 1111 0x00 0001 xxxx 0xxx 1111 xxxx xxxx */ | ||
443 | /* TEQ 1111 0x00 1001 xxxx 0xxx 1111 xxxx xxxx */ | ||
444 | DECODE_EMULATEX (0xfb708f00, 0xf0100f00, t32_emulate_rd8rn16rm0_rwflags, | ||
445 | REGS(NOSPPC, 0, 0, 0, 0)), | ||
446 | |||
447 | /* CMN 1111 0x01 0001 xxxx 0xxx 1111 xxxx xxxx */ | ||
448 | DECODE_OR (0xfbf08f00, 0xf1100f00), | ||
449 | /* CMP 1111 0x01 1011 xxxx 0xxx 1111 xxxx xxxx */ | ||
450 | DECODE_EMULATEX (0xfbf08f00, 0xf1b00f00, t32_emulate_rd8rn16rm0_rwflags, | ||
451 | REGS(NOPC, 0, 0, 0, 0)), | ||
452 | |||
453 | /* MOV 1111 0x00 010x 1111 0xxx xxxx xxxx xxxx */ | ||
454 | /* MVN 1111 0x00 011x 1111 0xxx xxxx xxxx xxxx */ | ||
455 | DECODE_EMULATEX (0xfbcf8000, 0xf04f0000, t32_emulate_rd8rn16rm0_rwflags, | ||
456 | REGS(0, 0, NOSPPC, 0, 0)), | ||
457 | |||
458 | /* ??? 1111 0x00 101x xxxx 0xxx xxxx xxxx xxxx */ | ||
459 | DECODE_REJECT (0xfbe08000, 0xf0a00000), | ||
460 | /* ??? 1111 0x00 110x xxxx 0xxx xxxx xxxx xxxx */ | ||
461 | /* ??? 1111 0x00 111x xxxx 0xxx xxxx xxxx xxxx */ | ||
462 | DECODE_REJECT (0xfbc08000, 0xf0c00000), | ||
463 | /* ??? 1111 0x01 001x xxxx 0xxx xxxx xxxx xxxx */ | ||
464 | DECODE_REJECT (0xfbe08000, 0xf1200000), | ||
465 | /* ??? 1111 0x01 100x xxxx 0xxx xxxx xxxx xxxx */ | ||
466 | DECODE_REJECT (0xfbe08000, 0xf1800000), | ||
467 | /* ??? 1111 0x01 111x xxxx 0xxx xxxx xxxx xxxx */ | ||
468 | DECODE_REJECT (0xfbe08000, 0xf1e00000), | ||
469 | |||
470 | /* ADD Rd, SP, #imm 1111 0x01 000x 1101 0xxx xxxx xxxx xxxx */ | ||
471 | /* SUB Rd, SP, #imm 1111 0x01 101x 1101 0xxx xxxx xxxx xxxx */ | ||
472 | DECODE_EMULATEX (0xfb4f8000, 0xf10d0000, t32_emulate_rd8rn16rm0_rwflags, | ||
473 | REGS(SP, 0, NOPC, 0, 0)), | ||
474 | |||
475 | /* AND 1111 0x00 000x xxxx 0xxx xxxx xxxx xxxx */ | ||
476 | /* BIC 1111 0x00 001x xxxx 0xxx xxxx xxxx xxxx */ | ||
477 | /* ORR 1111 0x00 010x xxxx 0xxx xxxx xxxx xxxx */ | ||
478 | /* ORN 1111 0x00 011x xxxx 0xxx xxxx xxxx xxxx */ | ||
479 | /* EOR 1111 0x00 100x xxxx 0xxx xxxx xxxx xxxx */ | ||
480 | /* ADD 1111 0x01 000x xxxx 0xxx xxxx xxxx xxxx */ | ||
481 | /* ADC 1111 0x01 010x xxxx 0xxx xxxx xxxx xxxx */ | ||
482 | /* SBC 1111 0x01 011x xxxx 0xxx xxxx xxxx xxxx */ | ||
483 | /* SUB 1111 0x01 101x xxxx 0xxx xxxx xxxx xxxx */ | ||
484 | /* RSB 1111 0x01 110x xxxx 0xxx xxxx xxxx xxxx */ | ||
485 | DECODE_EMULATEX (0xfa008000, 0xf0000000, t32_emulate_rd8rn16rm0_rwflags, | ||
486 | REGS(NOSPPC, 0, NOSPPC, 0, 0)), | ||
487 | |||
488 | DECODE_END | ||
489 | }; | ||
490 | |||
491 | static const union decode_item t32_table_1111_0x1x___0[] = { | ||
492 | /* Data-processing (plain binary immediate) */ | ||
493 | |||
494 | /* ADDW Rd, PC, #imm 1111 0x10 0000 1111 0xxx xxxx xxxx xxxx */ | ||
495 | DECODE_OR (0xfbff8000, 0xf20f0000), | ||
496 | /* SUBW Rd, PC, #imm 1111 0x10 1010 1111 0xxx xxxx xxxx xxxx */ | ||
497 | DECODE_EMULATEX (0xfbff8000, 0xf2af0000, t32_emulate_rd8pc16_noflags, | ||
498 | REGS(PC, 0, NOSPPC, 0, 0)), | ||
499 | |||
500 | /* ADDW SP, SP, #imm 1111 0x10 0000 1101 0xxx 1101 xxxx xxxx */ | ||
501 | DECODE_OR (0xfbff8f00, 0xf20d0d00), | ||
502 | /* SUBW SP, SP, #imm 1111 0x10 1010 1101 0xxx 1101 xxxx xxxx */ | ||
503 | DECODE_EMULATEX (0xfbff8f00, 0xf2ad0d00, t32_emulate_rd8rn16_noflags, | ||
504 | REGS(SP, 0, SP, 0, 0)), | ||
505 | |||
506 | /* ADDW 1111 0x10 0000 xxxx 0xxx xxxx xxxx xxxx */ | ||
507 | DECODE_OR (0xfbf08000, 0xf2000000), | ||
508 | /* SUBW 1111 0x10 1010 xxxx 0xxx xxxx xxxx xxxx */ | ||
509 | DECODE_EMULATEX (0xfbf08000, 0xf2a00000, t32_emulate_rd8rn16_noflags, | ||
510 | REGS(NOPCX, 0, NOSPPC, 0, 0)), | ||
511 | |||
512 | /* MOVW 1111 0x10 0100 xxxx 0xxx xxxx xxxx xxxx */ | ||
513 | /* MOVT 1111 0x10 1100 xxxx 0xxx xxxx xxxx xxxx */ | ||
514 | DECODE_EMULATEX (0xfb708000, 0xf2400000, t32_emulate_rd8rn16_noflags, | ||
515 | REGS(0, 0, NOSPPC, 0, 0)), | ||
516 | |||
517 | /* SSAT16 1111 0x11 0010 xxxx 0000 xxxx 00xx xxxx */ | ||
518 | /* SSAT 1111 0x11 00x0 xxxx 0xxx xxxx xxxx xxxx */ | ||
519 | /* USAT16 1111 0x11 1010 xxxx 0000 xxxx 00xx xxxx */ | ||
520 | /* USAT 1111 0x11 10x0 xxxx 0xxx xxxx xxxx xxxx */ | ||
521 | DECODE_EMULATEX (0xfb508000, 0xf3000000, t32_emulate_rd8rn16rm0_rwflags, | ||
522 | REGS(NOSPPC, 0, NOSPPC, 0, 0)), | ||
523 | |||
524 | /* SFBX 1111 0x11 0100 xxxx 0xxx xxxx xxxx xxxx */ | ||
525 | /* UFBX 1111 0x11 1100 xxxx 0xxx xxxx xxxx xxxx */ | ||
526 | DECODE_EMULATEX (0xfb708000, 0xf3400000, t32_emulate_rd8rn16_noflags, | ||
527 | REGS(NOSPPC, 0, NOSPPC, 0, 0)), | ||
528 | |||
529 | /* BFC 1111 0x11 0110 1111 0xxx xxxx xxxx xxxx */ | ||
530 | DECODE_EMULATEX (0xfbff8000, 0xf36f0000, t32_emulate_rd8rn16_noflags, | ||
531 | REGS(0, 0, NOSPPC, 0, 0)), | ||
532 | |||
533 | /* BFI 1111 0x11 0110 xxxx 0xxx xxxx xxxx xxxx */ | ||
534 | DECODE_EMULATEX (0xfbf08000, 0xf3600000, t32_emulate_rd8rn16_noflags, | ||
535 | REGS(NOSPPCX, 0, NOSPPC, 0, 0)), | ||
536 | |||
537 | DECODE_END | ||
538 | }; | ||
539 | |||
540 | static const union decode_item t32_table_1111_0xxx___1[] = { | ||
541 | /* Branches and miscellaneous control */ | ||
542 | |||
543 | /* YIELD 1111 0011 1010 xxxx 10x0 x000 0000 0001 */ | ||
544 | DECODE_OR (0xfff0d7ff, 0xf3a08001), | ||
545 | /* SEV 1111 0011 1010 xxxx 10x0 x000 0000 0100 */ | ||
546 | DECODE_EMULATE (0xfff0d7ff, 0xf3a08004, kprobe_emulate_none), | ||
547 | /* NOP 1111 0011 1010 xxxx 10x0 x000 0000 0000 */ | ||
548 | /* WFE 1111 0011 1010 xxxx 10x0 x000 0000 0010 */ | ||
549 | /* WFI 1111 0011 1010 xxxx 10x0 x000 0000 0011 */ | ||
550 | DECODE_SIMULATE (0xfff0d7fc, 0xf3a08000, kprobe_simulate_nop), | ||
551 | |||
552 | /* MRS Rd, CPSR 1111 0011 1110 xxxx 10x0 xxxx xxxx xxxx */ | ||
553 | DECODE_SIMULATEX(0xfff0d000, 0xf3e08000, t32_simulate_mrs, | ||
554 | REGS(0, 0, NOSPPC, 0, 0)), | ||
555 | |||
556 | /* | ||
557 | * Unsupported instructions | ||
558 | * 1111 0x11 1xxx xxxx 10x0 xxxx xxxx xxxx | ||
559 | * | ||
560 | * MSR 1111 0011 100x xxxx 10x0 xxxx xxxx xxxx | ||
561 | * DBG hint 1111 0011 1010 xxxx 10x0 x000 1111 xxxx | ||
562 | * Unallocated hints 1111 0011 1010 xxxx 10x0 x000 xxxx xxxx | ||
563 | * CPS 1111 0011 1010 xxxx 10x0 xxxx xxxx xxxx | ||
564 | * CLREX/DSB/DMB/ISB 1111 0011 1011 xxxx 10x0 xxxx xxxx xxxx | ||
565 | * BXJ 1111 0011 1100 xxxx 10x0 xxxx xxxx xxxx | ||
566 | * SUBS PC,LR,#<imm8> 1111 0011 1101 xxxx 10x0 xxxx xxxx xxxx | ||
567 | * MRS Rd, SPSR 1111 0011 1111 xxxx 10x0 xxxx xxxx xxxx | ||
568 | * SMC 1111 0111 1111 xxxx 1000 xxxx xxxx xxxx | ||
569 | * UNDEFINED 1111 0111 1111 xxxx 1010 xxxx xxxx xxxx | ||
570 | * ??? 1111 0111 1xxx xxxx 1010 xxxx xxxx xxxx | ||
571 | */ | ||
572 | DECODE_REJECT (0xfb80d000, 0xf3808000), | ||
573 | |||
574 | /* Bcc 1111 0xxx xxxx xxxx 10x0 xxxx xxxx xxxx */ | ||
575 | DECODE_CUSTOM (0xf800d000, 0xf0008000, t32_decode_cond_branch), | ||
576 | |||
577 | /* BLX 1111 0xxx xxxx xxxx 11x0 xxxx xxxx xxx0 */ | ||
578 | DECODE_OR (0xf800d001, 0xf000c000), | ||
579 | /* B 1111 0xxx xxxx xxxx 10x1 xxxx xxxx xxxx */ | ||
580 | /* BL 1111 0xxx xxxx xxxx 11x1 xxxx xxxx xxxx */ | ||
581 | DECODE_SIMULATE (0xf8009000, 0xf0009000, t32_simulate_branch), | ||
582 | |||
583 | DECODE_END | ||
584 | }; | ||
585 | |||
586 | static const union decode_item t32_table_1111_100x_x0x1__1111[] = { | ||
587 | /* Memory hints */ | ||
588 | |||
589 | /* PLD (literal) 1111 1000 x001 1111 1111 xxxx xxxx xxxx */ | ||
590 | /* PLI (literal) 1111 1001 x001 1111 1111 xxxx xxxx xxxx */ | ||
591 | DECODE_SIMULATE (0xfe7ff000, 0xf81ff000, kprobe_simulate_nop), | ||
592 | |||
593 | /* PLD{W} (immediate) 1111 1000 10x1 xxxx 1111 xxxx xxxx xxxx */ | ||
594 | DECODE_OR (0xffd0f000, 0xf890f000), | ||
595 | /* PLD{W} (immediate) 1111 1000 00x1 xxxx 1111 1100 xxxx xxxx */ | ||
596 | DECODE_OR (0xffd0ff00, 0xf810fc00), | ||
597 | /* PLI (immediate) 1111 1001 1001 xxxx 1111 xxxx xxxx xxxx */ | ||
598 | DECODE_OR (0xfff0f000, 0xf990f000), | ||
599 | /* PLI (immediate) 1111 1001 0001 xxxx 1111 1100 xxxx xxxx */ | ||
600 | DECODE_SIMULATEX(0xfff0ff00, 0xf910fc00, kprobe_simulate_nop, | ||
601 | REGS(NOPCX, 0, 0, 0, 0)), | ||
602 | |||
603 | /* PLD{W} (register) 1111 1000 00x1 xxxx 1111 0000 00xx xxxx */ | ||
604 | DECODE_OR (0xffd0ffc0, 0xf810f000), | ||
605 | /* PLI (register) 1111 1001 0001 xxxx 1111 0000 00xx xxxx */ | ||
606 | DECODE_SIMULATEX(0xfff0ffc0, 0xf910f000, kprobe_simulate_nop, | ||
607 | REGS(NOPCX, 0, 0, 0, NOSPPC)), | ||
608 | |||
609 | /* Other unallocated instructions... */ | ||
610 | DECODE_END | ||
611 | }; | ||
612 | |||
613 | static const union decode_item t32_table_1111_100x[] = { | ||
614 | /* Store/Load single data item */ | ||
615 | |||
616 | /* ??? 1111 100x x11x xxxx xxxx xxxx xxxx xxxx */ | ||
617 | DECODE_REJECT (0xfe600000, 0xf8600000), | ||
618 | |||
619 | /* ??? 1111 1001 0101 xxxx xxxx xxxx xxxx xxxx */ | ||
620 | DECODE_REJECT (0xfff00000, 0xf9500000), | ||
621 | |||
622 | /* ??? 1111 100x 0xxx xxxx xxxx 10x0 xxxx xxxx */ | ||
623 | DECODE_REJECT (0xfe800d00, 0xf8000800), | ||
624 | |||
625 | /* STRBT 1111 1000 0000 xxxx xxxx 1110 xxxx xxxx */ | ||
626 | /* STRHT 1111 1000 0010 xxxx xxxx 1110 xxxx xxxx */ | ||
627 | /* STRT 1111 1000 0100 xxxx xxxx 1110 xxxx xxxx */ | ||
628 | /* LDRBT 1111 1000 0001 xxxx xxxx 1110 xxxx xxxx */ | ||
629 | /* LDRSBT 1111 1001 0001 xxxx xxxx 1110 xxxx xxxx */ | ||
630 | /* LDRHT 1111 1000 0011 xxxx xxxx 1110 xxxx xxxx */ | ||
631 | /* LDRSHT 1111 1001 0011 xxxx xxxx 1110 xxxx xxxx */ | ||
632 | /* LDRT 1111 1000 0101 xxxx xxxx 1110 xxxx xxxx */ | ||
633 | DECODE_REJECT (0xfe800f00, 0xf8000e00), | ||
634 | |||
635 | /* STR{,B,H} Rn,[PC...] 1111 1000 xxx0 1111 xxxx xxxx xxxx xxxx */ | ||
636 | DECODE_REJECT (0xff1f0000, 0xf80f0000), | ||
637 | |||
638 | /* STR{,B,H} PC,[Rn...] 1111 1000 xxx0 xxxx 1111 xxxx xxxx xxxx */ | ||
639 | DECODE_REJECT (0xff10f000, 0xf800f000), | ||
640 | |||
641 | /* LDR (literal) 1111 1000 x101 1111 xxxx xxxx xxxx xxxx */ | ||
642 | DECODE_SIMULATEX(0xff7f0000, 0xf85f0000, t32_simulate_ldr_literal, | ||
643 | REGS(PC, ANY, 0, 0, 0)), | ||
644 | |||
645 | /* STR (immediate) 1111 1000 0100 xxxx xxxx 1xxx xxxx xxxx */ | ||
646 | /* LDR (immediate) 1111 1000 0101 xxxx xxxx 1xxx xxxx xxxx */ | ||
647 | DECODE_OR (0xffe00800, 0xf8400800), | ||
648 | /* STR (immediate) 1111 1000 1100 xxxx xxxx xxxx xxxx xxxx */ | ||
649 | /* LDR (immediate) 1111 1000 1101 xxxx xxxx xxxx xxxx xxxx */ | ||
650 | DECODE_EMULATEX (0xffe00000, 0xf8c00000, t32_emulate_ldrstr, | ||
651 | REGS(NOPCX, ANY, 0, 0, 0)), | ||
652 | |||
653 | /* STR (register) 1111 1000 0100 xxxx xxxx 0000 00xx xxxx */ | ||
654 | /* LDR (register) 1111 1000 0101 xxxx xxxx 0000 00xx xxxx */ | ||
655 | DECODE_EMULATEX (0xffe00fc0, 0xf8400000, t32_emulate_ldrstr, | ||
656 | REGS(NOPCX, ANY, 0, 0, NOSPPC)), | ||
657 | |||
658 | /* LDRB (literal) 1111 1000 x001 1111 xxxx xxxx xxxx xxxx */ | ||
659 | /* LDRSB (literal) 1111 1001 x001 1111 xxxx xxxx xxxx xxxx */ | ||
660 | /* LDRH (literal) 1111 1000 x011 1111 xxxx xxxx xxxx xxxx */ | ||
661 | /* LDRSH (literal) 1111 1001 x011 1111 xxxx xxxx xxxx xxxx */ | ||
662 | DECODE_EMULATEX (0xfe5f0000, 0xf81f0000, t32_simulate_ldr_literal, | ||
663 | REGS(PC, NOSPPCX, 0, 0, 0)), | ||
664 | |||
665 | /* STRB (immediate) 1111 1000 0000 xxxx xxxx 1xxx xxxx xxxx */ | ||
666 | /* STRH (immediate) 1111 1000 0010 xxxx xxxx 1xxx xxxx xxxx */ | ||
667 | /* LDRB (immediate) 1111 1000 0001 xxxx xxxx 1xxx xxxx xxxx */ | ||
668 | /* LDRSB (immediate) 1111 1001 0001 xxxx xxxx 1xxx xxxx xxxx */ | ||
669 | /* LDRH (immediate) 1111 1000 0011 xxxx xxxx 1xxx xxxx xxxx */ | ||
670 | /* LDRSH (immediate) 1111 1001 0011 xxxx xxxx 1xxx xxxx xxxx */ | ||
671 | DECODE_OR (0xfec00800, 0xf8000800), | ||
672 | /* STRB (immediate) 1111 1000 1000 xxxx xxxx xxxx xxxx xxxx */ | ||
673 | /* STRH (immediate) 1111 1000 1010 xxxx xxxx xxxx xxxx xxxx */ | ||
674 | /* LDRB (immediate) 1111 1000 1001 xxxx xxxx xxxx xxxx xxxx */ | ||
675 | /* LDRSB (immediate) 1111 1001 1001 xxxx xxxx xxxx xxxx xxxx */ | ||
676 | /* LDRH (immediate) 1111 1000 1011 xxxx xxxx xxxx xxxx xxxx */ | ||
677 | /* LDRSH (immediate) 1111 1001 1011 xxxx xxxx xxxx xxxx xxxx */ | ||
678 | DECODE_EMULATEX (0xfec00000, 0xf8800000, t32_emulate_ldrstr, | ||
679 | REGS(NOPCX, NOSPPCX, 0, 0, 0)), | ||
680 | |||
681 | /* STRB (register) 1111 1000 0000 xxxx xxxx 0000 00xx xxxx */ | ||
682 | /* STRH (register) 1111 1000 0010 xxxx xxxx 0000 00xx xxxx */ | ||
683 | /* LDRB (register) 1111 1000 0001 xxxx xxxx 0000 00xx xxxx */ | ||
684 | /* LDRSB (register) 1111 1001 0001 xxxx xxxx 0000 00xx xxxx */ | ||
685 | /* LDRH (register) 1111 1000 0011 xxxx xxxx 0000 00xx xxxx */ | ||
686 | /* LDRSH (register) 1111 1001 0011 xxxx xxxx 0000 00xx xxxx */ | ||
687 | DECODE_EMULATEX (0xfe800fc0, 0xf8000000, t32_emulate_ldrstr, | ||
688 | REGS(NOPCX, NOSPPCX, 0, 0, NOSPPC)), | ||
689 | |||
690 | /* Other unallocated instructions... */ | ||
691 | DECODE_END | ||
692 | }; | ||
693 | |||
694 | static const union decode_item t32_table_1111_1010___1111[] = { | ||
695 | /* Data-processing (register) */ | ||
696 | |||
697 | /* ??? 1111 1010 011x xxxx 1111 xxxx 1xxx xxxx */ | ||
698 | DECODE_REJECT (0xffe0f080, 0xfa60f080), | ||
699 | |||
700 | /* SXTH 1111 1010 0000 1111 1111 xxxx 1xxx xxxx */ | ||
701 | /* UXTH 1111 1010 0001 1111 1111 xxxx 1xxx xxxx */ | ||
702 | /* SXTB16 1111 1010 0010 1111 1111 xxxx 1xxx xxxx */ | ||
703 | /* UXTB16 1111 1010 0011 1111 1111 xxxx 1xxx xxxx */ | ||
704 | /* SXTB 1111 1010 0100 1111 1111 xxxx 1xxx xxxx */ | ||
705 | /* UXTB 1111 1010 0101 1111 1111 xxxx 1xxx xxxx */ | ||
706 | DECODE_EMULATEX (0xff8ff080, 0xfa0ff080, t32_emulate_rd8rn16rm0_rwflags, | ||
707 | REGS(0, 0, NOSPPC, 0, NOSPPC)), | ||
708 | |||
709 | |||
710 | /* ??? 1111 1010 1xxx xxxx 1111 xxxx 0x11 xxxx */ | ||
711 | DECODE_REJECT (0xff80f0b0, 0xfa80f030), | ||
712 | /* ??? 1111 1010 1x11 xxxx 1111 xxxx 0xxx xxxx */ | ||
713 | DECODE_REJECT (0xffb0f080, 0xfab0f000), | ||
714 | |||
715 | /* SADD16 1111 1010 1001 xxxx 1111 xxxx 0000 xxxx */ | ||
716 | /* SASX 1111 1010 1010 xxxx 1111 xxxx 0000 xxxx */ | ||
717 | /* SSAX 1111 1010 1110 xxxx 1111 xxxx 0000 xxxx */ | ||
718 | /* SSUB16 1111 1010 1101 xxxx 1111 xxxx 0000 xxxx */ | ||
719 | /* SADD8 1111 1010 1000 xxxx 1111 xxxx 0000 xxxx */ | ||
720 | /* SSUB8 1111 1010 1100 xxxx 1111 xxxx 0000 xxxx */ | ||
721 | |||
722 | /* QADD16 1111 1010 1001 xxxx 1111 xxxx 0001 xxxx */ | ||
723 | /* QASX 1111 1010 1010 xxxx 1111 xxxx 0001 xxxx */ | ||
724 | /* QSAX 1111 1010 1110 xxxx 1111 xxxx 0001 xxxx */ | ||
725 | /* QSUB16 1111 1010 1101 xxxx 1111 xxxx 0001 xxxx */ | ||
726 | /* QADD8 1111 1010 1000 xxxx 1111 xxxx 0001 xxxx */ | ||
727 | /* QSUB8 1111 1010 1100 xxxx 1111 xxxx 0001 xxxx */ | ||
728 | |||
729 | /* SHADD16 1111 1010 1001 xxxx 1111 xxxx 0010 xxxx */ | ||
730 | /* SHASX 1111 1010 1010 xxxx 1111 xxxx 0010 xxxx */ | ||
731 | /* SHSAX 1111 1010 1110 xxxx 1111 xxxx 0010 xxxx */ | ||
732 | /* SHSUB16 1111 1010 1101 xxxx 1111 xxxx 0010 xxxx */ | ||
733 | /* SHADD8 1111 1010 1000 xxxx 1111 xxxx 0010 xxxx */ | ||
734 | /* SHSUB8 1111 1010 1100 xxxx 1111 xxxx 0010 xxxx */ | ||
735 | |||
736 | /* UADD16 1111 1010 1001 xxxx 1111 xxxx 0100 xxxx */ | ||
737 | /* UASX 1111 1010 1010 xxxx 1111 xxxx 0100 xxxx */ | ||
738 | /* USAX 1111 1010 1110 xxxx 1111 xxxx 0100 xxxx */ | ||
739 | /* USUB16 1111 1010 1101 xxxx 1111 xxxx 0100 xxxx */ | ||
740 | /* UADD8 1111 1010 1000 xxxx 1111 xxxx 0100 xxxx */ | ||
741 | /* USUB8 1111 1010 1100 xxxx 1111 xxxx 0100 xxxx */ | ||
742 | |||
743 | /* UQADD16 1111 1010 1001 xxxx 1111 xxxx 0101 xxxx */ | ||
744 | /* UQASX 1111 1010 1010 xxxx 1111 xxxx 0101 xxxx */ | ||
745 | /* UQSAX 1111 1010 1110 xxxx 1111 xxxx 0101 xxxx */ | ||
746 | /* UQSUB16 1111 1010 1101 xxxx 1111 xxxx 0101 xxxx */ | ||
747 | /* UQADD8 1111 1010 1000 xxxx 1111 xxxx 0101 xxxx */ | ||
748 | /* UQSUB8 1111 1010 1100 xxxx 1111 xxxx 0101 xxxx */ | ||
749 | |||
750 | /* UHADD16 1111 1010 1001 xxxx 1111 xxxx 0110 xxxx */ | ||
751 | /* UHASX 1111 1010 1010 xxxx 1111 xxxx 0110 xxxx */ | ||
752 | /* UHSAX 1111 1010 1110 xxxx 1111 xxxx 0110 xxxx */ | ||
753 | /* UHSUB16 1111 1010 1101 xxxx 1111 xxxx 0110 xxxx */ | ||
754 | /* UHADD8 1111 1010 1000 xxxx 1111 xxxx 0110 xxxx */ | ||
755 | /* UHSUB8 1111 1010 1100 xxxx 1111 xxxx 0110 xxxx */ | ||
756 | DECODE_OR (0xff80f080, 0xfa80f000), | ||
757 | |||
758 | /* SXTAH 1111 1010 0000 xxxx 1111 xxxx 1xxx xxxx */ | ||
759 | /* UXTAH 1111 1010 0001 xxxx 1111 xxxx 1xxx xxxx */ | ||
760 | /* SXTAB16 1111 1010 0010 xxxx 1111 xxxx 1xxx xxxx */ | ||
761 | /* UXTAB16 1111 1010 0011 xxxx 1111 xxxx 1xxx xxxx */ | ||
762 | /* SXTAB 1111 1010 0100 xxxx 1111 xxxx 1xxx xxxx */ | ||
763 | /* UXTAB 1111 1010 0101 xxxx 1111 xxxx 1xxx xxxx */ | ||
764 | DECODE_OR (0xff80f080, 0xfa00f080), | ||
765 | |||
766 | /* QADD 1111 1010 1000 xxxx 1111 xxxx 1000 xxxx */ | ||
767 | /* QDADD 1111 1010 1000 xxxx 1111 xxxx 1001 xxxx */ | ||
768 | /* QSUB 1111 1010 1000 xxxx 1111 xxxx 1010 xxxx */ | ||
769 | /* QDSUB 1111 1010 1000 xxxx 1111 xxxx 1011 xxxx */ | ||
770 | DECODE_OR (0xfff0f0c0, 0xfa80f080), | ||
771 | |||
772 | /* SEL 1111 1010 1010 xxxx 1111 xxxx 1000 xxxx */ | ||
773 | DECODE_OR (0xfff0f0f0, 0xfaa0f080), | ||
774 | |||
775 | /* LSL 1111 1010 000x xxxx 1111 xxxx 0000 xxxx */ | ||
776 | /* LSR 1111 1010 001x xxxx 1111 xxxx 0000 xxxx */ | ||
777 | /* ASR 1111 1010 010x xxxx 1111 xxxx 0000 xxxx */ | ||
778 | /* ROR 1111 1010 011x xxxx 1111 xxxx 0000 xxxx */ | ||
779 | DECODE_EMULATEX (0xff80f0f0, 0xfa00f000, t32_emulate_rd8rn16rm0_rwflags, | ||
780 | REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)), | ||
781 | |||
782 | /* CLZ 1111 1010 1010 xxxx 1111 xxxx 1000 xxxx */ | ||
783 | DECODE_OR (0xfff0f0f0, 0xfab0f080), | ||
784 | |||
785 | /* REV 1111 1010 1001 xxxx 1111 xxxx 1000 xxxx */ | ||
786 | /* REV16 1111 1010 1001 xxxx 1111 xxxx 1001 xxxx */ | ||
787 | /* RBIT 1111 1010 1001 xxxx 1111 xxxx 1010 xxxx */ | ||
788 | /* REVSH 1111 1010 1001 xxxx 1111 xxxx 1011 xxxx */ | ||
789 | DECODE_EMULATEX (0xfff0f0c0, 0xfa90f080, t32_emulate_rd8rn16_noflags, | ||
790 | REGS(NOSPPC, 0, NOSPPC, 0, SAMEAS16)), | ||
791 | |||
792 | /* Other unallocated instructions... */ | ||
793 | DECODE_END | ||
794 | }; | ||
795 | |||
796 | static const union decode_item t32_table_1111_1011_0[] = { | ||
797 | /* Multiply, multiply accumulate, and absolute difference */ | ||
798 | |||
799 | /* ??? 1111 1011 0000 xxxx 1111 xxxx 0001 xxxx */ | ||
800 | DECODE_REJECT (0xfff0f0f0, 0xfb00f010), | ||
801 | /* ??? 1111 1011 0111 xxxx 1111 xxxx 0001 xxxx */ | ||
802 | DECODE_REJECT (0xfff0f0f0, 0xfb70f010), | ||
803 | |||
804 | /* SMULxy 1111 1011 0001 xxxx 1111 xxxx 00xx xxxx */ | ||
805 | DECODE_OR (0xfff0f0c0, 0xfb10f000), | ||
806 | /* MUL 1111 1011 0000 xxxx 1111 xxxx 0000 xxxx */ | ||
807 | /* SMUAD{X} 1111 1011 0010 xxxx 1111 xxxx 000x xxxx */ | ||
808 | /* SMULWy 1111 1011 0011 xxxx 1111 xxxx 000x xxxx */ | ||
809 | /* SMUSD{X} 1111 1011 0100 xxxx 1111 xxxx 000x xxxx */ | ||
810 | /* SMMUL{R} 1111 1011 0101 xxxx 1111 xxxx 000x xxxx */ | ||
811 | /* USAD8 1111 1011 0111 xxxx 1111 xxxx 0000 xxxx */ | ||
812 | DECODE_EMULATEX (0xff80f0e0, 0xfb00f000, t32_emulate_rd8rn16rm0_rwflags, | ||
813 | REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)), | ||
814 | |||
815 | /* ??? 1111 1011 0111 xxxx xxxx xxxx 0001 xxxx */ | ||
816 | DECODE_REJECT (0xfff000f0, 0xfb700010), | ||
817 | |||
818 | /* SMLAxy 1111 1011 0001 xxxx xxxx xxxx 00xx xxxx */ | ||
819 | DECODE_OR (0xfff000c0, 0xfb100000), | ||
820 | /* MLA 1111 1011 0000 xxxx xxxx xxxx 0000 xxxx */ | ||
821 | /* MLS 1111 1011 0000 xxxx xxxx xxxx 0001 xxxx */ | ||
822 | /* SMLAD{X} 1111 1011 0010 xxxx xxxx xxxx 000x xxxx */ | ||
823 | /* SMLAWy 1111 1011 0011 xxxx xxxx xxxx 000x xxxx */ | ||
824 | /* SMLSD{X} 1111 1011 0100 xxxx xxxx xxxx 000x xxxx */ | ||
825 | /* SMMLA{R} 1111 1011 0101 xxxx xxxx xxxx 000x xxxx */ | ||
826 | /* SMMLS{R} 1111 1011 0110 xxxx xxxx xxxx 000x xxxx */ | ||
827 | /* USADA8 1111 1011 0111 xxxx xxxx xxxx 0000 xxxx */ | ||
828 | DECODE_EMULATEX (0xff8000c0, 0xfb000000, t32_emulate_rd8rn16rm0ra12_noflags, | ||
829 | REGS(NOSPPC, NOSPPCX, NOSPPC, 0, NOSPPC)), | ||
830 | |||
831 | /* Other unallocated instructions... */ | ||
832 | DECODE_END | ||
833 | }; | ||
834 | |||
835 | static const union decode_item t32_table_1111_1011_1[] = { | ||
836 | /* Long multiply, long multiply accumulate, and divide */ | ||
837 | |||
838 | /* UMAAL 1111 1011 1110 xxxx xxxx xxxx 0110 xxxx */ | ||
839 | DECODE_OR (0xfff000f0, 0xfbe00060), | ||
840 | /* SMLALxy 1111 1011 1100 xxxx xxxx xxxx 10xx xxxx */ | ||
841 | DECODE_OR (0xfff000c0, 0xfbc00080), | ||
842 | /* SMLALD{X} 1111 1011 1100 xxxx xxxx xxxx 110x xxxx */ | ||
843 | /* SMLSLD{X} 1111 1011 1101 xxxx xxxx xxxx 110x xxxx */ | ||
844 | DECODE_OR (0xffe000e0, 0xfbc000c0), | ||
845 | /* SMULL 1111 1011 1000 xxxx xxxx xxxx 0000 xxxx */ | ||
846 | /* UMULL 1111 1011 1010 xxxx xxxx xxxx 0000 xxxx */ | ||
847 | /* SMLAL 1111 1011 1100 xxxx xxxx xxxx 0000 xxxx */ | ||
848 | /* UMLAL 1111 1011 1110 xxxx xxxx xxxx 0000 xxxx */ | ||
849 | DECODE_EMULATEX (0xff9000f0, 0xfb800000, t32_emulate_rdlo12rdhi8rn16rm0_noflags, | ||
850 | REGS(NOSPPC, NOSPPC, NOSPPC, 0, NOSPPC)), | ||
851 | |||
852 | /* SDIV 1111 1011 1001 xxxx xxxx xxxx 1111 xxxx */ | ||
853 | /* UDIV 1111 1011 1011 xxxx xxxx xxxx 1111 xxxx */ | ||
854 | /* Other unallocated instructions... */ | ||
855 | DECODE_END | ||
856 | }; | ||
857 | |||
858 | const union decode_item kprobe_decode_thumb32_table[] = { | ||
859 | |||
860 | /* | ||
861 | * Load/store multiple instructions | ||
862 | * 1110 100x x0xx xxxx xxxx xxxx xxxx xxxx | ||
863 | */ | ||
864 | DECODE_TABLE (0xfe400000, 0xe8000000, t32_table_1110_100x_x0xx), | ||
865 | |||
866 | /* | ||
867 | * Load/store dual, load/store exclusive, table branch | ||
868 | * 1110 100x x1xx xxxx xxxx xxxx xxxx xxxx | ||
869 | */ | ||
870 | DECODE_TABLE (0xfe400000, 0xe8400000, t32_table_1110_100x_x1xx), | ||
871 | |||
872 | /* | ||
873 | * Data-processing (shifted register) | ||
874 | * 1110 101x xxxx xxxx xxxx xxxx xxxx xxxx | ||
875 | */ | ||
876 | DECODE_TABLE (0xfe000000, 0xea000000, t32_table_1110_101x), | ||
877 | |||
878 | /* | ||
879 | * Coprocessor instructions | ||
880 | * 1110 11xx xxxx xxxx xxxx xxxx xxxx xxxx | ||
881 | */ | ||
882 | DECODE_REJECT (0xfc000000, 0xec000000), | ||
883 | |||
884 | /* | ||
885 | * Data-processing (modified immediate) | ||
886 | * 1111 0x0x xxxx xxxx 0xxx xxxx xxxx xxxx | ||
887 | */ | ||
888 | DECODE_TABLE (0xfa008000, 0xf0000000, t32_table_1111_0x0x___0), | ||
889 | |||
890 | /* | ||
891 | * Data-processing (plain binary immediate) | ||
892 | * 1111 0x1x xxxx xxxx 0xxx xxxx xxxx xxxx | ||
893 | */ | ||
894 | DECODE_TABLE (0xfa008000, 0xf2000000, t32_table_1111_0x1x___0), | ||
895 | |||
896 | /* | ||
897 | * Branches and miscellaneous control | ||
898 | * 1111 0xxx xxxx xxxx 1xxx xxxx xxxx xxxx | ||
899 | */ | ||
900 | DECODE_TABLE (0xf8008000, 0xf0008000, t32_table_1111_0xxx___1), | ||
901 | |||
902 | /* | ||
903 | * Advanced SIMD element or structure load/store instructions | ||
904 | * 1111 1001 xxx0 xxxx xxxx xxxx xxxx xxxx | ||
905 | */ | ||
906 | DECODE_REJECT (0xff100000, 0xf9000000), | ||
907 | |||
908 | /* | ||
909 | * Memory hints | ||
910 | * 1111 100x x0x1 xxxx 1111 xxxx xxxx xxxx | ||
911 | */ | ||
912 | DECODE_TABLE (0xfe50f000, 0xf810f000, t32_table_1111_100x_x0x1__1111), | ||
913 | |||
914 | /* | ||
915 | * Store single data item | ||
916 | * 1111 1000 xxx0 xxxx xxxx xxxx xxxx xxxx | ||
917 | * Load single data items | ||
918 | * 1111 100x xxx1 xxxx xxxx xxxx xxxx xxxx | ||
919 | */ | ||
920 | DECODE_TABLE (0xfe000000, 0xf8000000, t32_table_1111_100x), | ||
921 | |||
922 | /* | ||
923 | * Data-processing (register) | ||
924 | * 1111 1010 xxxx xxxx 1111 xxxx xxxx xxxx | ||
925 | */ | ||
926 | DECODE_TABLE (0xff00f000, 0xfa00f000, t32_table_1111_1010___1111), | ||
927 | |||
928 | /* | ||
929 | * Multiply, multiply accumulate, and absolute difference | ||
930 | * 1111 1011 0xxx xxxx xxxx xxxx xxxx xxxx | ||
931 | */ | ||
932 | DECODE_TABLE (0xff800000, 0xfb000000, t32_table_1111_1011_0), | ||
933 | |||
934 | /* | ||
935 | * Long multiply, long multiply accumulate, and divide | ||
936 | * 1111 1011 1xxx xxxx xxxx xxxx xxxx xxxx | ||
937 | */ | ||
938 | DECODE_TABLE (0xff800000, 0xfb800000, t32_table_1111_1011_1), | ||
939 | |||
940 | /* | ||
941 | * Coprocessor instructions | ||
942 | * 1111 11xx xxxx xxxx xxxx xxxx xxxx xxxx | ||
943 | */ | ||
944 | DECODE_END | ||
945 | }; | ||
946 | |||
947 | static void __kprobes | ||
948 | t16_simulate_bxblx(struct kprobe *p, struct pt_regs *regs) | ||
949 | { | ||
950 | kprobe_opcode_t insn = p->opcode; | ||
951 | unsigned long pc = thumb_probe_pc(p); | ||
952 | int rm = (insn >> 3) & 0xf; | ||
953 | unsigned long rmv = (rm == 15) ? pc : regs->uregs[rm]; | ||
954 | |||
955 | if (insn & (1 << 7)) /* BLX ? */ | ||
956 | regs->ARM_lr = (unsigned long)p->addr + 2; | ||
957 | |||
958 | bx_write_pc(rmv, regs); | ||
959 | } | ||
960 | |||
961 | static void __kprobes | ||
962 | t16_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs) | ||
963 | { | ||
964 | kprobe_opcode_t insn = p->opcode; | ||
965 | unsigned long* base = (unsigned long *)(thumb_probe_pc(p) & ~3); | ||
966 | long index = insn & 0xff; | ||
967 | int rt = (insn >> 8) & 0x7; | ||
968 | regs->uregs[rt] = base[index]; | ||
969 | } | ||
970 | |||
971 | static void __kprobes | ||
972 | t16_simulate_ldrstr_sp_relative(struct kprobe *p, struct pt_regs *regs) | ||
973 | { | ||
974 | kprobe_opcode_t insn = p->opcode; | ||
975 | unsigned long* base = (unsigned long *)regs->ARM_sp; | ||
976 | long index = insn & 0xff; | ||
977 | int rt = (insn >> 8) & 0x7; | ||
978 | if (insn & 0x800) /* LDR */ | ||
979 | regs->uregs[rt] = base[index]; | ||
980 | else /* STR */ | ||
981 | base[index] = regs->uregs[rt]; | ||
982 | } | ||
983 | |||
984 | static void __kprobes | ||
985 | t16_simulate_reladr(struct kprobe *p, struct pt_regs *regs) | ||
986 | { | ||
987 | kprobe_opcode_t insn = p->opcode; | ||
988 | unsigned long base = (insn & 0x800) ? regs->ARM_sp | ||
989 | : (thumb_probe_pc(p) & ~3); | ||
990 | long offset = insn & 0xff; | ||
991 | int rt = (insn >> 8) & 0x7; | ||
992 | regs->uregs[rt] = base + offset * 4; | ||
993 | } | ||
994 | |||
995 | static void __kprobes | ||
996 | t16_simulate_add_sp_imm(struct kprobe *p, struct pt_regs *regs) | ||
997 | { | ||
998 | kprobe_opcode_t insn = p->opcode; | ||
999 | long imm = insn & 0x7f; | ||
1000 | if (insn & 0x80) /* SUB */ | ||
1001 | regs->ARM_sp -= imm * 4; | ||
1002 | else /* ADD */ | ||
1003 | regs->ARM_sp += imm * 4; | ||
1004 | } | ||
1005 | |||
1006 | static void __kprobes | ||
1007 | t16_simulate_cbz(struct kprobe *p, struct pt_regs *regs) | ||
1008 | { | ||
1009 | kprobe_opcode_t insn = p->opcode; | ||
1010 | int rn = insn & 0x7; | ||
1011 | kprobe_opcode_t nonzero = regs->uregs[rn] ? insn : ~insn; | ||
1012 | if (nonzero & 0x800) { | ||
1013 | long i = insn & 0x200; | ||
1014 | long imm5 = insn & 0xf8; | ||
1015 | unsigned long pc = thumb_probe_pc(p); | ||
1016 | regs->ARM_pc = pc + (i >> 3) + (imm5 >> 2); | ||
1017 | } | ||
1018 | } | ||
1019 | |||
1020 | static void __kprobes | ||
1021 | t16_simulate_it(struct kprobe *p, struct pt_regs *regs) | ||
1022 | { | ||
1023 | /* | ||
1024 | * The 8 IT state bits are split into two parts in CPSR: | ||
1025 | * ITSTATE<1:0> are in CPSR<26:25> | ||
1026 | * ITSTATE<7:2> are in CPSR<15:10> | ||
1027 | * The new IT state is in the lower byte of insn. | ||
1028 | */ | ||
1029 | kprobe_opcode_t insn = p->opcode; | ||
1030 | unsigned long cpsr = regs->ARM_cpsr; | ||
1031 | cpsr &= ~PSR_IT_MASK; | ||
1032 | cpsr |= (insn & 0xfc) << 8; | ||
1033 | cpsr |= (insn & 0x03) << 25; | ||
1034 | regs->ARM_cpsr = cpsr; | ||
1035 | } | ||
1036 | |||
1037 | static void __kprobes | ||
1038 | t16_singlestep_it(struct kprobe *p, struct pt_regs *regs) | ||
1039 | { | ||
1040 | regs->ARM_pc += 2; | ||
1041 | t16_simulate_it(p, regs); | ||
1042 | } | ||
1043 | |||
1044 | static enum kprobe_insn __kprobes | ||
1045 | t16_decode_it(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1046 | { | ||
1047 | asi->insn_singlestep = t16_singlestep_it; | ||
1048 | return INSN_GOOD_NO_SLOT; | ||
1049 | } | ||
1050 | |||
1051 | static void __kprobes | ||
1052 | t16_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs) | ||
1053 | { | ||
1054 | kprobe_opcode_t insn = p->opcode; | ||
1055 | unsigned long pc = thumb_probe_pc(p); | ||
1056 | long offset = insn & 0x7f; | ||
1057 | offset -= insn & 0x80; /* Apply sign bit */ | ||
1058 | regs->ARM_pc = pc + (offset * 2); | ||
1059 | } | ||
1060 | |||
1061 | static enum kprobe_insn __kprobes | ||
1062 | t16_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1063 | { | ||
1064 | int cc = (insn >> 8) & 0xf; | ||
1065 | asi->insn_check_cc = kprobe_condition_checks[cc]; | ||
1066 | asi->insn_handler = t16_simulate_cond_branch; | ||
1067 | return INSN_GOOD_NO_SLOT; | ||
1068 | } | ||
1069 | |||
1070 | static void __kprobes | ||
1071 | t16_simulate_branch(struct kprobe *p, struct pt_regs *regs) | ||
1072 | { | ||
1073 | kprobe_opcode_t insn = p->opcode; | ||
1074 | unsigned long pc = thumb_probe_pc(p); | ||
1075 | long offset = insn & 0x3ff; | ||
1076 | offset -= insn & 0x400; /* Apply sign bit */ | ||
1077 | regs->ARM_pc = pc + (offset * 2); | ||
1078 | } | ||
1079 | |||
1080 | static unsigned long __kprobes | ||
1081 | t16_emulate_loregs(struct kprobe *p, struct pt_regs *regs) | ||
1082 | { | ||
1083 | unsigned long oldcpsr = regs->ARM_cpsr; | ||
1084 | unsigned long newcpsr; | ||
1085 | |||
1086 | __asm__ __volatile__ ( | ||
1087 | "msr cpsr_fs, %[oldcpsr] \n\t" | ||
1088 | "ldmia %[regs], {r0-r7} \n\t" | ||
1089 | "blx %[fn] \n\t" | ||
1090 | "stmia %[regs], {r0-r7} \n\t" | ||
1091 | "mrs %[newcpsr], cpsr \n\t" | ||
1092 | : [newcpsr] "=r" (newcpsr) | ||
1093 | : [oldcpsr] "r" (oldcpsr), [regs] "r" (regs), | ||
1094 | [fn] "r" (p->ainsn.insn_fn) | ||
1095 | : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", | ||
1096 | "lr", "memory", "cc" | ||
1097 | ); | ||
1098 | |||
1099 | return (oldcpsr & ~APSR_MASK) | (newcpsr & APSR_MASK); | ||
1100 | } | ||
1101 | |||
1102 | static void __kprobes | ||
1103 | t16_emulate_loregs_rwflags(struct kprobe *p, struct pt_regs *regs) | ||
1104 | { | ||
1105 | regs->ARM_cpsr = t16_emulate_loregs(p, regs); | ||
1106 | } | ||
1107 | |||
1108 | static void __kprobes | ||
1109 | t16_emulate_loregs_noitrwflags(struct kprobe *p, struct pt_regs *regs) | ||
1110 | { | ||
1111 | unsigned long cpsr = t16_emulate_loregs(p, regs); | ||
1112 | if (!in_it_block(cpsr)) | ||
1113 | regs->ARM_cpsr = cpsr; | ||
1114 | } | ||
1115 | |||
1116 | static void __kprobes | ||
1117 | t16_emulate_hiregs(struct kprobe *p, struct pt_regs *regs) | ||
1118 | { | ||
1119 | kprobe_opcode_t insn = p->opcode; | ||
1120 | unsigned long pc = thumb_probe_pc(p); | ||
1121 | int rdn = (insn & 0x7) | ((insn & 0x80) >> 4); | ||
1122 | int rm = (insn >> 3) & 0xf; | ||
1123 | |||
1124 | register unsigned long rdnv asm("r1"); | ||
1125 | register unsigned long rmv asm("r0"); | ||
1126 | unsigned long cpsr = regs->ARM_cpsr; | ||
1127 | |||
1128 | rdnv = (rdn == 15) ? pc : regs->uregs[rdn]; | ||
1129 | rmv = (rm == 15) ? pc : regs->uregs[rm]; | ||
1130 | |||
1131 | __asm__ __volatile__ ( | ||
1132 | "msr cpsr_fs, %[cpsr] \n\t" | ||
1133 | "blx %[fn] \n\t" | ||
1134 | "mrs %[cpsr], cpsr \n\t" | ||
1135 | : "=r" (rdnv), [cpsr] "=r" (cpsr) | ||
1136 | : "0" (rdnv), "r" (rmv), "1" (cpsr), [fn] "r" (p->ainsn.insn_fn) | ||
1137 | : "lr", "memory", "cc" | ||
1138 | ); | ||
1139 | |||
1140 | if (rdn == 15) | ||
1141 | rdnv &= ~1; | ||
1142 | |||
1143 | regs->uregs[rdn] = rdnv; | ||
1144 | regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); | ||
1145 | } | ||
1146 | |||
1147 | static enum kprobe_insn __kprobes | ||
1148 | t16_decode_hiregs(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1149 | { | ||
1150 | insn &= ~0x00ff; | ||
1151 | insn |= 0x001; /* Set Rdn = R1 and Rm = R0 */ | ||
1152 | ((u16 *)asi->insn)[0] = insn; | ||
1153 | asi->insn_handler = t16_emulate_hiregs; | ||
1154 | return INSN_GOOD; | ||
1155 | } | ||
1156 | |||
1157 | static void __kprobes | ||
1158 | t16_emulate_push(struct kprobe *p, struct pt_regs *regs) | ||
1159 | { | ||
1160 | __asm__ __volatile__ ( | ||
1161 | "ldr r9, [%[regs], #13*4] \n\t" | ||
1162 | "ldr r8, [%[regs], #14*4] \n\t" | ||
1163 | "ldmia %[regs], {r0-r7} \n\t" | ||
1164 | "blx %[fn] \n\t" | ||
1165 | "str r9, [%[regs], #13*4] \n\t" | ||
1166 | : | ||
1167 | : [regs] "r" (regs), [fn] "r" (p->ainsn.insn_fn) | ||
1168 | : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", | ||
1169 | "lr", "memory", "cc" | ||
1170 | ); | ||
1171 | } | ||
1172 | |||
1173 | static enum kprobe_insn __kprobes | ||
1174 | t16_decode_push(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1175 | { | ||
1176 | /* | ||
1177 | * To simulate a PUSH we use a Thumb-2 "STMDB R9!, {registers}" | ||
1178 | * and call it with R9=SP and LR in the register list represented | ||
1179 | * by R8. | ||
1180 | */ | ||
1181 | ((u16 *)asi->insn)[0] = 0xe929; /* 1st half STMDB R9!,{} */ | ||
1182 | ((u16 *)asi->insn)[1] = insn & 0x1ff; /* 2nd half (register list) */ | ||
1183 | asi->insn_handler = t16_emulate_push; | ||
1184 | return INSN_GOOD; | ||
1185 | } | ||
1186 | |||
1187 | static void __kprobes | ||
1188 | t16_emulate_pop_nopc(struct kprobe *p, struct pt_regs *regs) | ||
1189 | { | ||
1190 | __asm__ __volatile__ ( | ||
1191 | "ldr r9, [%[regs], #13*4] \n\t" | ||
1192 | "ldmia %[regs], {r0-r7} \n\t" | ||
1193 | "blx %[fn] \n\t" | ||
1194 | "stmia %[regs], {r0-r7} \n\t" | ||
1195 | "str r9, [%[regs], #13*4] \n\t" | ||
1196 | : | ||
1197 | : [regs] "r" (regs), [fn] "r" (p->ainsn.insn_fn) | ||
1198 | : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r9", | ||
1199 | "lr", "memory", "cc" | ||
1200 | ); | ||
1201 | } | ||
1202 | |||
1203 | static void __kprobes | ||
1204 | t16_emulate_pop_pc(struct kprobe *p, struct pt_regs *regs) | ||
1205 | { | ||
1206 | register unsigned long pc asm("r8"); | ||
1207 | |||
1208 | __asm__ __volatile__ ( | ||
1209 | "ldr r9, [%[regs], #13*4] \n\t" | ||
1210 | "ldmia %[regs], {r0-r7} \n\t" | ||
1211 | "blx %[fn] \n\t" | ||
1212 | "stmia %[regs], {r0-r7} \n\t" | ||
1213 | "str r9, [%[regs], #13*4] \n\t" | ||
1214 | : "=r" (pc) | ||
1215 | : [regs] "r" (regs), [fn] "r" (p->ainsn.insn_fn) | ||
1216 | : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r9", | ||
1217 | "lr", "memory", "cc" | ||
1218 | ); | ||
1219 | |||
1220 | bx_write_pc(pc, regs); | ||
1221 | } | ||
1222 | |||
1223 | static enum kprobe_insn __kprobes | ||
1224 | t16_decode_pop(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1225 | { | ||
1226 | /* | ||
1227 | * To simulate a POP we use a Thumb-2 "LDMDB R9!, {registers}" | ||
1228 | * and call it with R9=SP and PC in the register list represented | ||
1229 | * by R8. | ||
1230 | */ | ||
1231 | ((u16 *)asi->insn)[0] = 0xe8b9; /* 1st half LDMIA R9!,{} */ | ||
1232 | ((u16 *)asi->insn)[1] = insn & 0x1ff; /* 2nd half (register list) */ | ||
1233 | asi->insn_handler = insn & 0x100 ? t16_emulate_pop_pc | ||
1234 | : t16_emulate_pop_nopc; | ||
1235 | return INSN_GOOD; | ||
1236 | } | ||
1237 | |||
1238 | static const union decode_item t16_table_1011[] = { | ||
1239 | /* Miscellaneous 16-bit instructions */ | ||
1240 | |||
1241 | /* ADD (SP plus immediate) 1011 0000 0xxx xxxx */ | ||
1242 | /* SUB (SP minus immediate) 1011 0000 1xxx xxxx */ | ||
1243 | DECODE_SIMULATE (0xff00, 0xb000, t16_simulate_add_sp_imm), | ||
1244 | |||
1245 | /* CBZ 1011 00x1 xxxx xxxx */ | ||
1246 | /* CBNZ 1011 10x1 xxxx xxxx */ | ||
1247 | DECODE_SIMULATE (0xf500, 0xb100, t16_simulate_cbz), | ||
1248 | |||
1249 | /* SXTH 1011 0010 00xx xxxx */ | ||
1250 | /* SXTB 1011 0010 01xx xxxx */ | ||
1251 | /* UXTH 1011 0010 10xx xxxx */ | ||
1252 | /* UXTB 1011 0010 11xx xxxx */ | ||
1253 | /* REV 1011 1010 00xx xxxx */ | ||
1254 | /* REV16 1011 1010 01xx xxxx */ | ||
1255 | /* ??? 1011 1010 10xx xxxx */ | ||
1256 | /* REVSH 1011 1010 11xx xxxx */ | ||
1257 | DECODE_REJECT (0xffc0, 0xba80), | ||
1258 | DECODE_EMULATE (0xf500, 0xb000, t16_emulate_loregs_rwflags), | ||
1259 | |||
1260 | /* PUSH 1011 010x xxxx xxxx */ | ||
1261 | DECODE_CUSTOM (0xfe00, 0xb400, t16_decode_push), | ||
1262 | /* POP 1011 110x xxxx xxxx */ | ||
1263 | DECODE_CUSTOM (0xfe00, 0xbc00, t16_decode_pop), | ||
1264 | |||
1265 | /* | ||
1266 | * If-Then, and hints | ||
1267 | * 1011 1111 xxxx xxxx | ||
1268 | */ | ||
1269 | |||
1270 | /* YIELD 1011 1111 0001 0000 */ | ||
1271 | DECODE_OR (0xffff, 0xbf10), | ||
1272 | /* SEV 1011 1111 0100 0000 */ | ||
1273 | DECODE_EMULATE (0xffff, 0xbf40, kprobe_emulate_none), | ||
1274 | /* NOP 1011 1111 0000 0000 */ | ||
1275 | /* WFE 1011 1111 0010 0000 */ | ||
1276 | /* WFI 1011 1111 0011 0000 */ | ||
1277 | DECODE_SIMULATE (0xffcf, 0xbf00, kprobe_simulate_nop), | ||
1278 | /* Unassigned hints 1011 1111 xxxx 0000 */ | ||
1279 | DECODE_REJECT (0xff0f, 0xbf00), | ||
1280 | /* IT 1011 1111 xxxx xxxx */ | ||
1281 | DECODE_CUSTOM (0xff00, 0xbf00, t16_decode_it), | ||
1282 | |||
1283 | /* SETEND 1011 0110 010x xxxx */ | ||
1284 | /* CPS 1011 0110 011x xxxx */ | ||
1285 | /* BKPT 1011 1110 xxxx xxxx */ | ||
1286 | /* And unallocated instructions... */ | ||
1287 | DECODE_END | ||
1288 | }; | ||
1289 | |||
1290 | const union decode_item kprobe_decode_thumb16_table[] = { | ||
1291 | |||
1292 | /* | ||
1293 | * Shift (immediate), add, subtract, move, and compare | ||
1294 | * 00xx xxxx xxxx xxxx | ||
1295 | */ | ||
1296 | |||
1297 | /* CMP (immediate) 0010 1xxx xxxx xxxx */ | ||
1298 | DECODE_EMULATE (0xf800, 0x2800, t16_emulate_loregs_rwflags), | ||
1299 | |||
1300 | /* ADD (register) 0001 100x xxxx xxxx */ | ||
1301 | /* SUB (register) 0001 101x xxxx xxxx */ | ||
1302 | /* LSL (immediate) 0000 0xxx xxxx xxxx */ | ||
1303 | /* LSR (immediate) 0000 1xxx xxxx xxxx */ | ||
1304 | /* ASR (immediate) 0001 0xxx xxxx xxxx */ | ||
1305 | /* ADD (immediate, Thumb) 0001 110x xxxx xxxx */ | ||
1306 | /* SUB (immediate, Thumb) 0001 111x xxxx xxxx */ | ||
1307 | /* MOV (immediate) 0010 0xxx xxxx xxxx */ | ||
1308 | /* ADD (immediate, Thumb) 0011 0xxx xxxx xxxx */ | ||
1309 | /* SUB (immediate, Thumb) 0011 1xxx xxxx xxxx */ | ||
1310 | DECODE_EMULATE (0xc000, 0x0000, t16_emulate_loregs_noitrwflags), | ||
1311 | |||
1312 | /* | ||
1313 | * 16-bit Thumb data-processing instructions | ||
1314 | * 0100 00xx xxxx xxxx | ||
1315 | */ | ||
1316 | |||
1317 | /* TST (register) 0100 0010 00xx xxxx */ | ||
1318 | DECODE_EMULATE (0xffc0, 0x4200, t16_emulate_loregs_rwflags), | ||
1319 | /* CMP (register) 0100 0010 10xx xxxx */ | ||
1320 | /* CMN (register) 0100 0010 11xx xxxx */ | ||
1321 | DECODE_EMULATE (0xff80, 0x4280, t16_emulate_loregs_rwflags), | ||
1322 | /* AND (register) 0100 0000 00xx xxxx */ | ||
1323 | /* EOR (register) 0100 0000 01xx xxxx */ | ||
1324 | /* LSL (register) 0100 0000 10xx xxxx */ | ||
1325 | /* LSR (register) 0100 0000 11xx xxxx */ | ||
1326 | /* ASR (register) 0100 0001 00xx xxxx */ | ||
1327 | /* ADC (register) 0100 0001 01xx xxxx */ | ||
1328 | /* SBC (register) 0100 0001 10xx xxxx */ | ||
1329 | /* ROR (register) 0100 0001 11xx xxxx */ | ||
1330 | /* RSB (immediate) 0100 0010 01xx xxxx */ | ||
1331 | /* ORR (register) 0100 0011 00xx xxxx */ | ||
1332 | /* MUL 0100 0011 00xx xxxx */ | ||
1333 | /* BIC (register) 0100 0011 10xx xxxx */ | ||
1334 | /* MVN (register) 0100 0011 10xx xxxx */ | ||
1335 | DECODE_EMULATE (0xfc00, 0x4000, t16_emulate_loregs_noitrwflags), | ||
1336 | |||
1337 | /* | ||
1338 | * Special data instructions and branch and exchange | ||
1339 | * 0100 01xx xxxx xxxx | ||
1340 | */ | ||
1341 | |||
1342 | /* BLX pc 0100 0111 1111 1xxx */ | ||
1343 | DECODE_REJECT (0xfff8, 0x47f8), | ||
1344 | |||
1345 | /* BX (register) 0100 0111 0xxx xxxx */ | ||
1346 | /* BLX (register) 0100 0111 1xxx xxxx */ | ||
1347 | DECODE_SIMULATE (0xff00, 0x4700, t16_simulate_bxblx), | ||
1348 | |||
1349 | /* ADD pc, pc 0100 0100 1111 1111 */ | ||
1350 | DECODE_REJECT (0xffff, 0x44ff), | ||
1351 | |||
1352 | /* ADD (register) 0100 0100 xxxx xxxx */ | ||
1353 | /* CMP (register) 0100 0101 xxxx xxxx */ | ||
1354 | /* MOV (register) 0100 0110 xxxx xxxx */ | ||
1355 | DECODE_CUSTOM (0xfc00, 0x4400, t16_decode_hiregs), | ||
1356 | |||
1357 | /* | ||
1358 | * Load from Literal Pool | ||
1359 | * LDR (literal) 0100 1xxx xxxx xxxx | ||
1360 | */ | ||
1361 | DECODE_SIMULATE (0xf800, 0x4800, t16_simulate_ldr_literal), | ||
1362 | |||
1363 | /* | ||
1364 | * 16-bit Thumb Load/store instructions | ||
1365 | * 0101 xxxx xxxx xxxx | ||
1366 | * 011x xxxx xxxx xxxx | ||
1367 | * 100x xxxx xxxx xxxx | ||
1368 | */ | ||
1369 | |||
1370 | /* STR (register) 0101 000x xxxx xxxx */ | ||
1371 | /* STRH (register) 0101 001x xxxx xxxx */ | ||
1372 | /* STRB (register) 0101 010x xxxx xxxx */ | ||
1373 | /* LDRSB (register) 0101 011x xxxx xxxx */ | ||
1374 | /* LDR (register) 0101 100x xxxx xxxx */ | ||
1375 | /* LDRH (register) 0101 101x xxxx xxxx */ | ||
1376 | /* LDRB (register) 0101 110x xxxx xxxx */ | ||
1377 | /* LDRSH (register) 0101 111x xxxx xxxx */ | ||
1378 | /* STR (immediate, Thumb) 0110 0xxx xxxx xxxx */ | ||
1379 | /* LDR (immediate, Thumb) 0110 1xxx xxxx xxxx */ | ||
1380 | /* STRB (immediate, Thumb) 0111 0xxx xxxx xxxx */ | ||
1381 | /* LDRB (immediate, Thumb) 0111 1xxx xxxx xxxx */ | ||
1382 | DECODE_EMULATE (0xc000, 0x4000, t16_emulate_loregs_rwflags), | ||
1383 | /* STRH (immediate, Thumb) 1000 0xxx xxxx xxxx */ | ||
1384 | /* LDRH (immediate, Thumb) 1000 1xxx xxxx xxxx */ | ||
1385 | DECODE_EMULATE (0xf000, 0x8000, t16_emulate_loregs_rwflags), | ||
1386 | /* STR (immediate, Thumb) 1001 0xxx xxxx xxxx */ | ||
1387 | /* LDR (immediate, Thumb) 1001 1xxx xxxx xxxx */ | ||
1388 | DECODE_SIMULATE (0xf000, 0x9000, t16_simulate_ldrstr_sp_relative), | ||
1389 | |||
1390 | /* | ||
1391 | * Generate PC-/SP-relative address | ||
1392 | * ADR (literal) 1010 0xxx xxxx xxxx | ||
1393 | * ADD (SP plus immediate) 1010 1xxx xxxx xxxx | ||
1394 | */ | ||
1395 | DECODE_SIMULATE (0xf000, 0xa000, t16_simulate_reladr), | ||
1396 | |||
1397 | /* | ||
1398 | * Miscellaneous 16-bit instructions | ||
1399 | * 1011 xxxx xxxx xxxx | ||
1400 | */ | ||
1401 | DECODE_TABLE (0xf000, 0xb000, t16_table_1011), | ||
1402 | |||
1403 | /* STM 1100 0xxx xxxx xxxx */ | ||
1404 | /* LDM 1100 1xxx xxxx xxxx */ | ||
1405 | DECODE_EMULATE (0xf000, 0xc000, t16_emulate_loregs_rwflags), | ||
1406 | |||
1407 | /* | ||
1408 | * Conditional branch, and Supervisor Call | ||
1409 | */ | ||
1410 | |||
1411 | /* Permanently UNDEFINED 1101 1110 xxxx xxxx */ | ||
1412 | /* SVC 1101 1111 xxxx xxxx */ | ||
1413 | DECODE_REJECT (0xfe00, 0xde00), | ||
1414 | |||
1415 | /* Conditional branch 1101 xxxx xxxx xxxx */ | ||
1416 | DECODE_CUSTOM (0xf000, 0xd000, t16_decode_cond_branch), | ||
1417 | |||
1418 | /* | ||
1419 | * Unconditional branch | ||
1420 | * B 1110 0xxx xxxx xxxx | ||
1421 | */ | ||
1422 | DECODE_SIMULATE (0xf800, 0xe000, t16_simulate_branch), | ||
1423 | |||
1424 | DECODE_END | ||
1425 | }; | ||
1426 | |||
1427 | static unsigned long __kprobes thumb_check_cc(unsigned long cpsr) | ||
1428 | { | ||
1429 | if (unlikely(in_it_block(cpsr))) | ||
1430 | return kprobe_condition_checks[current_cond(cpsr)](cpsr); | ||
1431 | return true; | ||
1432 | } | ||
1433 | |||
1434 | static void __kprobes thumb16_singlestep(struct kprobe *p, struct pt_regs *regs) | ||
1435 | { | ||
1436 | regs->ARM_pc += 2; | ||
1437 | p->ainsn.insn_handler(p, regs); | ||
1438 | regs->ARM_cpsr = it_advance(regs->ARM_cpsr); | ||
1439 | } | ||
1440 | |||
1441 | static void __kprobes thumb32_singlestep(struct kprobe *p, struct pt_regs *regs) | ||
1442 | { | ||
1443 | regs->ARM_pc += 4; | ||
1444 | p->ainsn.insn_handler(p, regs); | ||
1445 | regs->ARM_cpsr = it_advance(regs->ARM_cpsr); | ||
1446 | } | ||
1447 | |||
1448 | enum kprobe_insn __kprobes | ||
1449 | thumb16_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1450 | { | ||
1451 | asi->insn_singlestep = thumb16_singlestep; | ||
1452 | asi->insn_check_cc = thumb_check_cc; | ||
1453 | return kprobe_decode_insn(insn, asi, kprobe_decode_thumb16_table, true); | ||
1454 | } | ||
1455 | |||
1456 | enum kprobe_insn __kprobes | ||
1457 | thumb32_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1458 | { | ||
1459 | asi->insn_singlestep = thumb32_singlestep; | ||
1460 | asi->insn_check_cc = thumb_check_cc; | ||
1461 | return kprobe_decode_insn(insn, asi, kprobe_decode_thumb32_table, true); | ||
1462 | } | ||