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