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> | |
13 | ||
14 | #include "kprobes.h" | |
15 | ||
eaf4f33f JM |
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 | ||
a9c3c29e JM |
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 | ||
dd212bd3 JM |
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 | ||
ce715c77 | 52 | if (insn & 0x10) /* TBH */ |
dd212bd3 | 53 | halfwords = ((u16 *)rnv)[rmv]; |
ce715c77 | 54 | else /* TBB */ |
dd212bd3 JM |
55 | halfwords = ((u8 *)rnv)[rmv]; |
56 | ||
57 | regs->ARM_pc = pc + 2 * halfwords; | |
58 | } | |
59 | ||
b06f3ee3 JM |
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 | ||
ce715c77 JM |
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 | ||
eaf1d065 JM |
121 | static enum kprobe_insn __kprobes |
122 | t32_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |
123 | { | |
124 | enum kprobe_insn ret = kprobe_decode_ldmstm(insn, asi); | |
125 | ||
126 | /* Fixup modified instruction to have halfwords in correct order...*/ | |
127 | insn = asi->insn[0]; | |
128 | ((u16 *)asi->insn)[0] = insn >> 16; | |
129 | ((u16 *)asi->insn)[1] = insn & 0xffff; | |
130 | ||
131 | return ret; | |
132 | } | |
133 | ||
b48354d3 JM |
134 | static void __kprobes |
135 | t32_emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) | |
136 | { | |
137 | kprobe_opcode_t insn = p->opcode; | |
138 | unsigned long pc = thumb_probe_pc(p) & ~3; | |
139 | int rt1 = (insn >> 12) & 0xf; | |
140 | int rt2 = (insn >> 8) & 0xf; | |
141 | int rn = (insn >> 16) & 0xf; | |
142 | ||
143 | register unsigned long rt1v asm("r0") = regs->uregs[rt1]; | |
144 | register unsigned long rt2v asm("r1") = regs->uregs[rt2]; | |
145 | register unsigned long rnv asm("r2") = (rn == 15) ? pc | |
146 | : regs->uregs[rn]; | |
147 | ||
148 | __asm__ __volatile__ ( | |
149 | "blx %[fn]" | |
150 | : "=r" (rt1v), "=r" (rt2v), "=r" (rnv) | |
151 | : "0" (rt1v), "1" (rt2v), "2" (rnv), [fn] "r" (p->ainsn.insn_fn) | |
152 | : "lr", "memory", "cc" | |
153 | ); | |
154 | ||
155 | if (rn != 15) | |
156 | regs->uregs[rn] = rnv; /* Writeback base register */ | |
157 | regs->uregs[rt1] = rt1v; | |
158 | regs->uregs[rt2] = rt2v; | |
159 | } | |
160 | ||
080e0013 JM |
161 | static void __kprobes |
162 | t32_emulate_rd8rn16rm0_rwflags(struct kprobe *p, struct pt_regs *regs) | |
163 | { | |
164 | kprobe_opcode_t insn = p->opcode; | |
165 | int rd = (insn >> 8) & 0xf; | |
166 | int rn = (insn >> 16) & 0xf; | |
167 | int rm = insn & 0xf; | |
168 | ||
169 | register unsigned long rdv asm("r1") = regs->uregs[rd]; | |
170 | register unsigned long rnv asm("r2") = regs->uregs[rn]; | |
171 | register unsigned long rmv asm("r3") = regs->uregs[rm]; | |
172 | unsigned long cpsr = regs->ARM_cpsr; | |
173 | ||
174 | __asm__ __volatile__ ( | |
175 | "msr cpsr_fs, %[cpsr] \n\t" | |
176 | "blx %[fn] \n\t" | |
177 | "mrs %[cpsr], cpsr \n\t" | |
178 | : "=r" (rdv), [cpsr] "=r" (cpsr) | |
179 | : "0" (rdv), "r" (rnv), "r" (rmv), | |
180 | "1" (cpsr), [fn] "r" (p->ainsn.insn_fn) | |
181 | : "lr", "memory", "cc" | |
182 | ); | |
183 | ||
184 | regs->uregs[rd] = rdv; | |
185 | regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); | |
186 | } | |
187 | ||
7848786a JM |
188 | static void __kprobes |
189 | t32_emulate_rd8pc16_noflags(struct kprobe *p, struct pt_regs *regs) | |
190 | { | |
191 | kprobe_opcode_t insn = p->opcode; | |
192 | unsigned long pc = thumb_probe_pc(p); | |
193 | int rd = (insn >> 8) & 0xf; | |
194 | ||
195 | register unsigned long rdv asm("r1") = regs->uregs[rd]; | |
196 | register unsigned long rnv asm("r2") = pc & ~3; | |
197 | ||
198 | __asm__ __volatile__ ( | |
199 | "blx %[fn]" | |
200 | : "=r" (rdv) | |
201 | : "0" (rdv), "r" (rnv), [fn] "r" (p->ainsn.insn_fn) | |
202 | : "lr", "memory", "cc" | |
203 | ); | |
204 | ||
205 | regs->uregs[rd] = rdv; | |
206 | } | |
207 | ||
208 | static void __kprobes | |
209 | t32_emulate_rd8rn16_noflags(struct kprobe *p, struct pt_regs *regs) | |
210 | { | |
211 | kprobe_opcode_t insn = p->opcode; | |
212 | int rd = (insn >> 8) & 0xf; | |
213 | int rn = (insn >> 16) & 0xf; | |
214 | ||
215 | register unsigned long rdv asm("r1") = regs->uregs[rd]; | |
216 | register unsigned long rnv asm("r2") = regs->uregs[rn]; | |
217 | ||
218 | __asm__ __volatile__ ( | |
219 | "blx %[fn]" | |
220 | : "=r" (rdv) | |
221 | : "0" (rdv), "r" (rnv), [fn] "r" (p->ainsn.insn_fn) | |
222 | : "lr", "memory", "cc" | |
223 | ); | |
224 | ||
225 | regs->uregs[rd] = rdv; | |
226 | } | |
227 | ||
eaf1d065 JM |
228 | static const union decode_item t32_table_1110_100x_x0xx[] = { |
229 | /* Load/store multiple instructions */ | |
230 | ||
231 | /* Rn is PC 1110 100x x0xx 1111 xxxx xxxx xxxx xxxx */ | |
232 | DECODE_REJECT (0xfe4f0000, 0xe80f0000), | |
233 | ||
234 | /* SRS 1110 1000 00x0 xxxx xxxx xxxx xxxx xxxx */ | |
235 | /* RFE 1110 1000 00x1 xxxx xxxx xxxx xxxx xxxx */ | |
236 | DECODE_REJECT (0xffc00000, 0xe8000000), | |
237 | /* SRS 1110 1001 10x0 xxxx xxxx xxxx xxxx xxxx */ | |
238 | /* RFE 1110 1001 10x1 xxxx xxxx xxxx xxxx xxxx */ | |
239 | DECODE_REJECT (0xffc00000, 0xe9800000), | |
240 | ||
241 | /* STM Rn, {...pc} 1110 100x x0x0 xxxx 1xxx xxxx xxxx xxxx */ | |
242 | DECODE_REJECT (0xfe508000, 0xe8008000), | |
243 | /* LDM Rn, {...lr,pc} 1110 100x x0x1 xxxx 11xx xxxx xxxx xxxx */ | |
244 | DECODE_REJECT (0xfe50c000, 0xe810c000), | |
245 | /* LDM/STM Rn, {...sp} 1110 100x x0xx xxxx xx1x xxxx xxxx xxxx */ | |
246 | DECODE_REJECT (0xfe402000, 0xe8002000), | |
247 | ||
248 | /* STMIA 1110 1000 10x0 xxxx xxxx xxxx xxxx xxxx */ | |
249 | /* LDMIA 1110 1000 10x1 xxxx xxxx xxxx xxxx xxxx */ | |
250 | /* STMDB 1110 1001 00x0 xxxx xxxx xxxx xxxx xxxx */ | |
251 | /* LDMDB 1110 1001 00x1 xxxx xxxx xxxx xxxx xxxx */ | |
252 | DECODE_CUSTOM (0xfe400000, 0xe8000000, t32_decode_ldmstm), | |
253 | ||
254 | DECODE_END | |
255 | }; | |
256 | ||
b48354d3 JM |
257 | static const union decode_item t32_table_1110_100x_x1xx[] = { |
258 | /* Load/store dual, load/store exclusive, table branch */ | |
259 | ||
260 | /* STRD (immediate) 1110 1000 x110 xxxx xxxx xxxx xxxx xxxx */ | |
261 | /* LDRD (immediate) 1110 1000 x111 xxxx xxxx xxxx xxxx xxxx */ | |
262 | DECODE_OR (0xff600000, 0xe8600000), | |
263 | /* STRD (immediate) 1110 1001 x1x0 xxxx xxxx xxxx xxxx xxxx */ | |
264 | /* LDRD (immediate) 1110 1001 x1x1 xxxx xxxx xxxx xxxx xxxx */ | |
265 | DECODE_EMULATEX (0xff400000, 0xe9400000, t32_emulate_ldrdstrd, | |
266 | REGS(NOPCWB, NOSPPC, NOSPPC, 0, 0)), | |
267 | ||
dd212bd3 JM |
268 | /* TBB 1110 1000 1101 xxxx xxxx xxxx 0000 xxxx */ |
269 | /* TBH 1110 1000 1101 xxxx xxxx xxxx 0001 xxxx */ | |
270 | DECODE_SIMULATEX(0xfff000e0, 0xe8d00000, t32_simulate_table_branch, | |
271 | REGS(NOSP, 0, 0, 0, NOSPPC)), | |
272 | ||
b48354d3 JM |
273 | /* STREX 1110 1000 0100 xxxx xxxx xxxx xxxx xxxx */ |
274 | /* LDREX 1110 1000 0101 xxxx xxxx xxxx xxxx xxxx */ | |
275 | /* STREXB 1110 1000 1100 xxxx xxxx xxxx 0100 xxxx */ | |
276 | /* STREXH 1110 1000 1100 xxxx xxxx xxxx 0101 xxxx */ | |
277 | /* STREXD 1110 1000 1100 xxxx xxxx xxxx 0111 xxxx */ | |
278 | /* LDREXB 1110 1000 1101 xxxx xxxx xxxx 0100 xxxx */ | |
279 | /* LDREXH 1110 1000 1101 xxxx xxxx xxxx 0101 xxxx */ | |
280 | /* LDREXD 1110 1000 1101 xxxx xxxx xxxx 0111 xxxx */ | |
281 | /* And unallocated instructions... */ | |
282 | DECODE_END | |
283 | }; | |
284 | ||
080e0013 JM |
285 | static const union decode_item t32_table_1110_101x[] = { |
286 | /* Data-processing (shifted register) */ | |
287 | ||
288 | /* TST 1110 1010 0001 xxxx xxxx 1111 xxxx xxxx */ | |
289 | /* TEQ 1110 1010 1001 xxxx xxxx 1111 xxxx xxxx */ | |
290 | DECODE_EMULATEX (0xff700f00, 0xea100f00, t32_emulate_rd8rn16rm0_rwflags, | |
291 | REGS(NOSPPC, 0, 0, 0, NOSPPC)), | |
292 | ||
293 | /* CMN 1110 1011 0001 xxxx xxxx 1111 xxxx xxxx */ | |
294 | DECODE_OR (0xfff00f00, 0xeb100f00), | |
295 | /* CMP 1110 1011 1011 xxxx xxxx 1111 xxxx xxxx */ | |
296 | DECODE_EMULATEX (0xfff00f00, 0xebb00f00, t32_emulate_rd8rn16rm0_rwflags, | |
297 | REGS(NOPC, 0, 0, 0, NOSPPC)), | |
298 | ||
299 | /* MOV 1110 1010 010x 1111 xxxx xxxx xxxx xxxx */ | |
300 | /* MVN 1110 1010 011x 1111 xxxx xxxx xxxx xxxx */ | |
301 | DECODE_EMULATEX (0xffcf0000, 0xea4f0000, t32_emulate_rd8rn16rm0_rwflags, | |
302 | REGS(0, 0, NOSPPC, 0, NOSPPC)), | |
303 | ||
304 | /* ??? 1110 1010 101x xxxx xxxx xxxx xxxx xxxx */ | |
305 | /* ??? 1110 1010 111x xxxx xxxx xxxx xxxx xxxx */ | |
306 | DECODE_REJECT (0xffa00000, 0xeaa00000), | |
307 | /* ??? 1110 1011 001x xxxx xxxx xxxx xxxx xxxx */ | |
308 | DECODE_REJECT (0xffe00000, 0xeb200000), | |
309 | /* ??? 1110 1011 100x xxxx xxxx xxxx xxxx xxxx */ | |
310 | DECODE_REJECT (0xffe00000, 0xeb800000), | |
311 | /* ??? 1110 1011 111x xxxx xxxx xxxx xxxx xxxx */ | |
312 | DECODE_REJECT (0xffe00000, 0xebe00000), | |
313 | ||
314 | /* ADD/SUB SP, SP, Rm, LSL #0..3 */ | |
315 | /* 1110 1011 x0xx 1101 x000 1101 xx00 xxxx */ | |
316 | DECODE_EMULATEX (0xff4f7f30, 0xeb0d0d00, t32_emulate_rd8rn16rm0_rwflags, | |
317 | REGS(SP, 0, SP, 0, NOSPPC)), | |
318 | ||
319 | /* ADD/SUB SP, SP, Rm, shift */ | |
320 | /* 1110 1011 x0xx 1101 xxxx 1101 xxxx xxxx */ | |
321 | DECODE_REJECT (0xff4f0f00, 0xeb0d0d00), | |
322 | ||
323 | /* ADD/SUB Rd, SP, Rm, shift */ | |
324 | /* 1110 1011 x0xx 1101 xxxx xxxx xxxx xxxx */ | |
325 | DECODE_EMULATEX (0xff4f0000, 0xeb0d0000, t32_emulate_rd8rn16rm0_rwflags, | |
326 | REGS(SP, 0, NOPC, 0, NOSPPC)), | |
327 | ||
328 | /* AND 1110 1010 000x xxxx xxxx xxxx xxxx xxxx */ | |
329 | /* BIC 1110 1010 001x xxxx xxxx xxxx xxxx xxxx */ | |
330 | /* ORR 1110 1010 010x xxxx xxxx xxxx xxxx xxxx */ | |
331 | /* ORN 1110 1010 011x xxxx xxxx xxxx xxxx xxxx */ | |
332 | /* EOR 1110 1010 100x xxxx xxxx xxxx xxxx xxxx */ | |
333 | /* PKH 1110 1010 110x xxxx xxxx xxxx xxxx xxxx */ | |
334 | /* ADD 1110 1011 000x xxxx xxxx xxxx xxxx xxxx */ | |
335 | /* ADC 1110 1011 010x xxxx xxxx xxxx xxxx xxxx */ | |
336 | /* SBC 1110 1011 011x xxxx xxxx xxxx xxxx xxxx */ | |
337 | /* SUB 1110 1011 101x xxxx xxxx xxxx xxxx xxxx */ | |
338 | /* RSB 1110 1011 110x xxxx xxxx xxxx xxxx xxxx */ | |
339 | DECODE_EMULATEX (0xfe000000, 0xea000000, t32_emulate_rd8rn16rm0_rwflags, | |
340 | REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)), | |
341 | ||
342 | DECODE_END | |
343 | }; | |
344 | ||
2fcaf7e7 JM |
345 | static const union decode_item t32_table_1111_0x0x___0[] = { |
346 | /* Data-processing (modified immediate) */ | |
347 | ||
348 | /* TST 1111 0x00 0001 xxxx 0xxx 1111 xxxx xxxx */ | |
349 | /* TEQ 1111 0x00 1001 xxxx 0xxx 1111 xxxx xxxx */ | |
350 | DECODE_EMULATEX (0xfb708f00, 0xf0100f00, t32_emulate_rd8rn16rm0_rwflags, | |
351 | REGS(NOSPPC, 0, 0, 0, 0)), | |
352 | ||
353 | /* CMN 1111 0x01 0001 xxxx 0xxx 1111 xxxx xxxx */ | |
354 | DECODE_OR (0xfbf08f00, 0xf1100f00), | |
355 | /* CMP 1111 0x01 1011 xxxx 0xxx 1111 xxxx xxxx */ | |
356 | DECODE_EMULATEX (0xfbf08f00, 0xf1b00f00, t32_emulate_rd8rn16rm0_rwflags, | |
357 | REGS(NOPC, 0, 0, 0, 0)), | |
358 | ||
359 | /* MOV 1111 0x00 010x 1111 0xxx xxxx xxxx xxxx */ | |
360 | /* MVN 1111 0x00 011x 1111 0xxx xxxx xxxx xxxx */ | |
361 | DECODE_EMULATEX (0xfbcf8000, 0xf04f0000, t32_emulate_rd8rn16rm0_rwflags, | |
362 | REGS(0, 0, NOSPPC, 0, 0)), | |
363 | ||
364 | /* ??? 1111 0x00 101x xxxx 0xxx xxxx xxxx xxxx */ | |
365 | DECODE_REJECT (0xfbe08000, 0xf0a00000), | |
366 | /* ??? 1111 0x00 110x xxxx 0xxx xxxx xxxx xxxx */ | |
367 | /* ??? 1111 0x00 111x xxxx 0xxx xxxx xxxx xxxx */ | |
368 | DECODE_REJECT (0xfbc08000, 0xf0c00000), | |
369 | /* ??? 1111 0x01 001x xxxx 0xxx xxxx xxxx xxxx */ | |
370 | DECODE_REJECT (0xfbe08000, 0xf1200000), | |
371 | /* ??? 1111 0x01 100x xxxx 0xxx xxxx xxxx xxxx */ | |
372 | DECODE_REJECT (0xfbe08000, 0xf1800000), | |
373 | /* ??? 1111 0x01 111x xxxx 0xxx xxxx xxxx xxxx */ | |
374 | DECODE_REJECT (0xfbe08000, 0xf1e00000), | |
375 | ||
376 | /* ADD Rd, SP, #imm 1111 0x01 000x 1101 0xxx xxxx xxxx xxxx */ | |
377 | /* SUB Rd, SP, #imm 1111 0x01 101x 1101 0xxx xxxx xxxx xxxx */ | |
378 | DECODE_EMULATEX (0xfb4f8000, 0xf10d0000, t32_emulate_rd8rn16rm0_rwflags, | |
379 | REGS(SP, 0, NOPC, 0, 0)), | |
380 | ||
381 | /* AND 1111 0x00 000x xxxx 0xxx xxxx xxxx xxxx */ | |
382 | /* BIC 1111 0x00 001x xxxx 0xxx xxxx xxxx xxxx */ | |
383 | /* ORR 1111 0x00 010x xxxx 0xxx xxxx xxxx xxxx */ | |
384 | /* ORN 1111 0x00 011x xxxx 0xxx xxxx xxxx xxxx */ | |
385 | /* EOR 1111 0x00 100x xxxx 0xxx xxxx xxxx xxxx */ | |
386 | /* ADD 1111 0x01 000x xxxx 0xxx xxxx xxxx xxxx */ | |
387 | /* ADC 1111 0x01 010x xxxx 0xxx xxxx xxxx xxxx */ | |
388 | /* SBC 1111 0x01 011x xxxx 0xxx xxxx xxxx xxxx */ | |
389 | /* SUB 1111 0x01 101x xxxx 0xxx xxxx xxxx xxxx */ | |
390 | /* RSB 1111 0x01 110x xxxx 0xxx xxxx xxxx xxxx */ | |
391 | DECODE_EMULATEX (0xfa008000, 0xf0000000, t32_emulate_rd8rn16rm0_rwflags, | |
392 | REGS(NOSPPC, 0, NOSPPC, 0, 0)), | |
393 | ||
394 | DECODE_END | |
395 | }; | |
396 | ||
7848786a JM |
397 | static const union decode_item t32_table_1111_0x1x___0[] = { |
398 | /* Data-processing (plain binary immediate) */ | |
399 | ||
400 | /* ADDW Rd, PC, #imm 1111 0x10 0000 1111 0xxx xxxx xxxx xxxx */ | |
401 | DECODE_OR (0xfbff8000, 0xf20f0000), | |
402 | /* SUBW Rd, PC, #imm 1111 0x10 1010 1111 0xxx xxxx xxxx xxxx */ | |
403 | DECODE_EMULATEX (0xfbff8000, 0xf2af0000, t32_emulate_rd8pc16_noflags, | |
404 | REGS(PC, 0, NOSPPC, 0, 0)), | |
405 | ||
406 | /* ADDW SP, SP, #imm 1111 0x10 0000 1101 0xxx 1101 xxxx xxxx */ | |
407 | DECODE_OR (0xfbff8f00, 0xf20d0d00), | |
408 | /* SUBW SP, SP, #imm 1111 0x10 1010 1101 0xxx 1101 xxxx xxxx */ | |
409 | DECODE_EMULATEX (0xfbff8f00, 0xf2ad0d00, t32_emulate_rd8rn16_noflags, | |
410 | REGS(SP, 0, SP, 0, 0)), | |
411 | ||
412 | /* ADDW 1111 0x10 0000 xxxx 0xxx xxxx xxxx xxxx */ | |
413 | DECODE_OR (0xfbf08000, 0xf2000000), | |
414 | /* SUBW 1111 0x10 1010 xxxx 0xxx xxxx xxxx xxxx */ | |
415 | DECODE_EMULATEX (0xfbf08000, 0xf2a00000, t32_emulate_rd8rn16_noflags, | |
416 | REGS(NOPCX, 0, NOSPPC, 0, 0)), | |
417 | ||
418 | /* MOVW 1111 0x10 0100 xxxx 0xxx xxxx xxxx xxxx */ | |
419 | /* MOVT 1111 0x10 1100 xxxx 0xxx xxxx xxxx xxxx */ | |
420 | DECODE_EMULATEX (0xfb708000, 0xf2400000, t32_emulate_rd8rn16_noflags, | |
421 | REGS(0, 0, NOSPPC, 0, 0)), | |
422 | ||
423 | /* SSAT16 1111 0x11 0010 xxxx 0000 xxxx 00xx xxxx */ | |
424 | /* SSAT 1111 0x11 00x0 xxxx 0xxx xxxx xxxx xxxx */ | |
425 | /* USAT16 1111 0x11 1010 xxxx 0000 xxxx 00xx xxxx */ | |
426 | /* USAT 1111 0x11 10x0 xxxx 0xxx xxxx xxxx xxxx */ | |
427 | DECODE_EMULATEX (0xfb508000, 0xf3000000, t32_emulate_rd8rn16rm0_rwflags, | |
428 | REGS(NOSPPC, 0, NOSPPC, 0, 0)), | |
429 | ||
430 | /* SFBX 1111 0x11 0100 xxxx 0xxx xxxx xxxx xxxx */ | |
431 | /* UFBX 1111 0x11 1100 xxxx 0xxx xxxx xxxx xxxx */ | |
432 | DECODE_EMULATEX (0xfb708000, 0xf3400000, t32_emulate_rd8rn16_noflags, | |
433 | REGS(NOSPPC, 0, NOSPPC, 0, 0)), | |
434 | ||
435 | /* BFC 1111 0x11 0110 1111 0xxx xxxx xxxx xxxx */ | |
436 | DECODE_EMULATEX (0xfbff8000, 0xf36f0000, t32_emulate_rd8rn16_noflags, | |
437 | REGS(0, 0, NOSPPC, 0, 0)), | |
438 | ||
439 | /* BFI 1111 0x11 0110 xxxx 0xxx xxxx xxxx xxxx */ | |
440 | DECODE_EMULATEX (0xfbf08000, 0xf3600000, t32_emulate_rd8rn16_noflags, | |
441 | REGS(NOSPPCX, 0, NOSPPC, 0, 0)), | |
442 | ||
443 | DECODE_END | |
444 | }; | |
445 | ||
f39ca8b4 JM |
446 | static const union decode_item t32_table_1111_0xxx___1[] = { |
447 | /* Branches and miscellaneous control */ | |
448 | ||
449 | /* YIELD 1111 0011 1010 xxxx 10x0 x000 0000 0001 */ | |
450 | DECODE_OR (0xfff0d7ff, 0xf3a08001), | |
451 | /* SEV 1111 0011 1010 xxxx 10x0 x000 0000 0100 */ | |
452 | DECODE_EMULATE (0xfff0d7ff, 0xf3a08004, kprobe_emulate_none), | |
453 | /* NOP 1111 0011 1010 xxxx 10x0 x000 0000 0000 */ | |
454 | /* WFE 1111 0011 1010 xxxx 10x0 x000 0000 0010 */ | |
455 | /* WFI 1111 0011 1010 xxxx 10x0 x000 0000 0011 */ | |
456 | DECODE_SIMULATE (0xfff0d7fc, 0xf3a08000, kprobe_simulate_nop), | |
457 | ||
b06f3ee3 JM |
458 | /* MRS Rd, CPSR 1111 0011 1110 xxxx 10x0 xxxx xxxx xxxx */ |
459 | DECODE_SIMULATEX(0xfff0d000, 0xf3e08000, t32_simulate_mrs, | |
460 | REGS(0, 0, NOSPPC, 0, 0)), | |
461 | ||
462 | /* | |
463 | * Unsupported instructions | |
464 | * 1111 0x11 1xxx xxxx 10x0 xxxx xxxx xxxx | |
465 | * | |
466 | * MSR 1111 0011 100x xxxx 10x0 xxxx xxxx xxxx | |
467 | * DBG hint 1111 0011 1010 xxxx 10x0 x000 1111 xxxx | |
468 | * Unallocated hints 1111 0011 1010 xxxx 10x0 x000 xxxx xxxx | |
469 | * CPS 1111 0011 1010 xxxx 10x0 xxxx xxxx xxxx | |
470 | * CLREX/DSB/DMB/ISB 1111 0011 1011 xxxx 10x0 xxxx xxxx xxxx | |
471 | * BXJ 1111 0011 1100 xxxx 10x0 xxxx xxxx xxxx | |
472 | * SUBS PC,LR,#<imm8> 1111 0011 1101 xxxx 10x0 xxxx xxxx xxxx | |
473 | * MRS Rd, SPSR 1111 0011 1111 xxxx 10x0 xxxx xxxx xxxx | |
474 | * SMC 1111 0111 1111 xxxx 1000 xxxx xxxx xxxx | |
475 | * UNDEFINED 1111 0111 1111 xxxx 1010 xxxx xxxx xxxx | |
476 | * ??? 1111 0111 1xxx xxxx 1010 xxxx xxxx xxxx | |
477 | */ | |
478 | DECODE_REJECT (0xfb80d000, 0xf3808000), | |
479 | ||
ce715c77 JM |
480 | /* Bcc 1111 0xxx xxxx xxxx 10x0 xxxx xxxx xxxx */ |
481 | DECODE_CUSTOM (0xf800d000, 0xf0008000, t32_decode_cond_branch), | |
482 | ||
483 | /* BLX 1111 0xxx xxxx xxxx 11x0 xxxx xxxx xxx0 */ | |
484 | DECODE_OR (0xf800d001, 0xf000c000), | |
485 | /* B 1111 0xxx xxxx xxxx 10x1 xxxx xxxx xxxx */ | |
486 | /* BL 1111 0xxx xxxx xxxx 11x1 xxxx xxxx xxxx */ | |
487 | DECODE_SIMULATE (0xf8009000, 0xf0009000, t32_simulate_branch), | |
488 | ||
f39ca8b4 JM |
489 | DECODE_END |
490 | }; | |
491 | ||
46009cc5 JM |
492 | static const union decode_item t32_table_1111_100x_x0x1__1111[] = { |
493 | /* Memory hints */ | |
494 | ||
495 | /* PLD (literal) 1111 1000 x001 1111 1111 xxxx xxxx xxxx */ | |
496 | /* PLI (literal) 1111 1001 x001 1111 1111 xxxx xxxx xxxx */ | |
497 | DECODE_SIMULATE (0xfe7ff000, 0xf81ff000, kprobe_simulate_nop), | |
498 | ||
499 | /* PLD{W} (immediate) 1111 1000 10x1 xxxx 1111 xxxx xxxx xxxx */ | |
500 | DECODE_OR (0xffd0f000, 0xf890f000), | |
501 | /* PLD{W} (immediate) 1111 1000 00x1 xxxx 1111 1100 xxxx xxxx */ | |
502 | DECODE_OR (0xffd0ff00, 0xf810fc00), | |
503 | /* PLI (immediate) 1111 1001 1001 xxxx 1111 xxxx xxxx xxxx */ | |
504 | DECODE_OR (0xfff0f000, 0xf990f000), | |
505 | /* PLI (immediate) 1111 1001 0001 xxxx 1111 1100 xxxx xxxx */ | |
506 | DECODE_SIMULATEX(0xfff0ff00, 0xf910fc00, kprobe_simulate_nop, | |
507 | REGS(NOPCX, 0, 0, 0, 0)), | |
508 | ||
509 | /* PLD{W} (register) 1111 1000 00x1 xxxx 1111 0000 00xx xxxx */ | |
510 | DECODE_OR (0xffd0ffc0, 0xf810f000), | |
511 | /* PLI (register) 1111 1001 0001 xxxx 1111 0000 00xx xxxx */ | |
512 | DECODE_SIMULATEX(0xfff0ffc0, 0xf910f000, kprobe_simulate_nop, | |
513 | REGS(NOPCX, 0, 0, 0, NOSPPC)), | |
514 | ||
515 | /* Other unallocated instructions... */ | |
516 | DECODE_END | |
517 | }; | |
518 | ||
f39ca8b4 JM |
519 | const union decode_item kprobe_decode_thumb32_table[] = { |
520 | ||
eaf1d065 JM |
521 | /* |
522 | * Load/store multiple instructions | |
523 | * 1110 100x x0xx xxxx xxxx xxxx xxxx xxxx | |
524 | */ | |
525 | DECODE_TABLE (0xfe400000, 0xe8000000, t32_table_1110_100x_x0xx), | |
526 | ||
b48354d3 JM |
527 | /* |
528 | * Load/store dual, load/store exclusive, table branch | |
529 | * 1110 100x x1xx xxxx xxxx xxxx xxxx xxxx | |
530 | */ | |
531 | DECODE_TABLE (0xfe400000, 0xe8400000, t32_table_1110_100x_x1xx), | |
532 | ||
080e0013 JM |
533 | /* |
534 | * Data-processing (shifted register) | |
535 | * 1110 101x xxxx xxxx xxxx xxxx xxxx xxxx | |
536 | */ | |
537 | DECODE_TABLE (0xfe000000, 0xea000000, t32_table_1110_101x), | |
538 | ||
6a0d1a1c JM |
539 | /* |
540 | * Coprocessor instructions | |
541 | * 1110 11xx xxxx xxxx xxxx xxxx xxxx xxxx | |
542 | */ | |
543 | DECODE_REJECT (0xfc000000, 0xec000000), | |
544 | ||
2fcaf7e7 JM |
545 | /* |
546 | * Data-processing (modified immediate) | |
547 | * 1111 0x0x xxxx xxxx 0xxx xxxx xxxx xxxx | |
548 | */ | |
549 | DECODE_TABLE (0xfa008000, 0xf0000000, t32_table_1111_0x0x___0), | |
550 | ||
7848786a JM |
551 | /* |
552 | * Data-processing (plain binary immediate) | |
553 | * 1111 0x1x xxxx xxxx 0xxx xxxx xxxx xxxx | |
554 | */ | |
555 | DECODE_TABLE (0xfa008000, 0xf2000000, t32_table_1111_0x1x___0), | |
556 | ||
f39ca8b4 JM |
557 | /* |
558 | * Branches and miscellaneous control | |
559 | * 1111 0xxx xxxx xxxx 1xxx xxxx xxxx xxxx | |
560 | */ | |
561 | DECODE_TABLE (0xf8008000, 0xf0008000, t32_table_1111_0xxx___1), | |
562 | ||
6a0d1a1c JM |
563 | /* |
564 | * Advanced SIMD element or structure load/store instructions | |
565 | * 1111 1001 xxx0 xxxx xxxx xxxx xxxx xxxx | |
566 | */ | |
567 | DECODE_REJECT (0xff100000, 0xf9000000), | |
568 | ||
46009cc5 JM |
569 | /* |
570 | * Memory hints | |
571 | * 1111 100x x0x1 xxxx 1111 xxxx xxxx xxxx | |
572 | */ | |
573 | DECODE_TABLE (0xfe50f000, 0xf810f000, t32_table_1111_100x_x0x1__1111), | |
574 | ||
6a0d1a1c JM |
575 | /* |
576 | * Coprocessor instructions | |
577 | * 1111 11xx xxxx xxxx xxxx xxxx xxxx xxxx | |
578 | */ | |
f39ca8b4 JM |
579 | DECODE_END |
580 | }; | |
581 | ||
a9c3c29e JM |
582 | static void __kprobes |
583 | t16_simulate_bxblx(struct kprobe *p, struct pt_regs *regs) | |
584 | { | |
585 | kprobe_opcode_t insn = p->opcode; | |
586 | unsigned long pc = thumb_probe_pc(p); | |
587 | int rm = (insn >> 3) & 0xf; | |
588 | unsigned long rmv = (rm == 15) ? pc : regs->uregs[rm]; | |
589 | ||
590 | if (insn & (1 << 7)) /* BLX ? */ | |
591 | regs->ARM_lr = (unsigned long)p->addr + 2; | |
592 | ||
593 | bx_write_pc(rmv, regs); | |
594 | } | |
595 | ||
f8695142 JM |
596 | static void __kprobes |
597 | t16_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs) | |
598 | { | |
599 | kprobe_opcode_t insn = p->opcode; | |
600 | unsigned long* base = (unsigned long *)(thumb_probe_pc(p) & ~3); | |
601 | long index = insn & 0xff; | |
602 | int rt = (insn >> 8) & 0x7; | |
603 | regs->uregs[rt] = base[index]; | |
604 | } | |
605 | ||
606 | static void __kprobes | |
607 | t16_simulate_ldrstr_sp_relative(struct kprobe *p, struct pt_regs *regs) | |
608 | { | |
609 | kprobe_opcode_t insn = p->opcode; | |
610 | unsigned long* base = (unsigned long *)regs->ARM_sp; | |
611 | long index = insn & 0xff; | |
612 | int rt = (insn >> 8) & 0x7; | |
613 | if (insn & 0x800) /* LDR */ | |
614 | regs->uregs[rt] = base[index]; | |
615 | else /* STR */ | |
616 | base[index] = regs->uregs[rt]; | |
617 | } | |
618 | ||
2f335829 JM |
619 | static void __kprobes |
620 | t16_simulate_reladr(struct kprobe *p, struct pt_regs *regs) | |
621 | { | |
622 | kprobe_opcode_t insn = p->opcode; | |
623 | unsigned long base = (insn & 0x800) ? regs->ARM_sp | |
624 | : (thumb_probe_pc(p) & ~3); | |
625 | long offset = insn & 0xff; | |
626 | int rt = (insn >> 8) & 0x7; | |
627 | regs->uregs[rt] = base + offset * 4; | |
628 | } | |
629 | ||
630 | static void __kprobes | |
631 | t16_simulate_add_sp_imm(struct kprobe *p, struct pt_regs *regs) | |
632 | { | |
633 | kprobe_opcode_t insn = p->opcode; | |
634 | long imm = insn & 0x7f; | |
635 | if (insn & 0x80) /* SUB */ | |
636 | regs->ARM_sp -= imm * 4; | |
637 | else /* ADD */ | |
638 | regs->ARM_sp += imm * 4; | |
639 | } | |
640 | ||
32818f31 JM |
641 | static void __kprobes |
642 | t16_simulate_cbz(struct kprobe *p, struct pt_regs *regs) | |
643 | { | |
644 | kprobe_opcode_t insn = p->opcode; | |
645 | int rn = insn & 0x7; | |
646 | kprobe_opcode_t nonzero = regs->uregs[rn] ? insn : ~insn; | |
647 | if (nonzero & 0x800) { | |
648 | long i = insn & 0x200; | |
649 | long imm5 = insn & 0xf8; | |
650 | unsigned long pc = thumb_probe_pc(p); | |
651 | regs->ARM_pc = pc + (i >> 3) + (imm5 >> 2); | |
652 | } | |
653 | } | |
654 | ||
5b94faf8 JM |
655 | static void __kprobes |
656 | t16_simulate_it(struct kprobe *p, struct pt_regs *regs) | |
657 | { | |
658 | /* | |
659 | * The 8 IT state bits are split into two parts in CPSR: | |
660 | * ITSTATE<1:0> are in CPSR<26:25> | |
661 | * ITSTATE<7:2> are in CPSR<15:10> | |
662 | * The new IT state is in the lower byte of insn. | |
663 | */ | |
664 | kprobe_opcode_t insn = p->opcode; | |
665 | unsigned long cpsr = regs->ARM_cpsr; | |
666 | cpsr &= ~PSR_IT_MASK; | |
667 | cpsr |= (insn & 0xfc) << 8; | |
668 | cpsr |= (insn & 0x03) << 25; | |
669 | regs->ARM_cpsr = cpsr; | |
670 | } | |
671 | ||
672 | static void __kprobes | |
673 | t16_singlestep_it(struct kprobe *p, struct pt_regs *regs) | |
674 | { | |
675 | regs->ARM_pc += 2; | |
676 | t16_simulate_it(p, regs); | |
677 | } | |
678 | ||
679 | static enum kprobe_insn __kprobes | |
680 | t16_decode_it(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |
681 | { | |
682 | asi->insn_singlestep = t16_singlestep_it; | |
683 | return INSN_GOOD_NO_SLOT; | |
684 | } | |
685 | ||
396b41f6 JM |
686 | static void __kprobes |
687 | t16_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs) | |
688 | { | |
689 | kprobe_opcode_t insn = p->opcode; | |
690 | unsigned long pc = thumb_probe_pc(p); | |
691 | long offset = insn & 0x7f; | |
692 | offset -= insn & 0x80; /* Apply sign bit */ | |
693 | regs->ARM_pc = pc + (offset * 2); | |
694 | } | |
695 | ||
696 | static enum kprobe_insn __kprobes | |
697 | t16_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |
698 | { | |
699 | int cc = (insn >> 8) & 0xf; | |
700 | asi->insn_check_cc = kprobe_condition_checks[cc]; | |
701 | asi->insn_handler = t16_simulate_cond_branch; | |
702 | return INSN_GOOD_NO_SLOT; | |
703 | } | |
704 | ||
705 | static void __kprobes | |
706 | t16_simulate_branch(struct kprobe *p, struct pt_regs *regs) | |
707 | { | |
708 | kprobe_opcode_t insn = p->opcode; | |
709 | unsigned long pc = thumb_probe_pc(p); | |
710 | long offset = insn & 0x3ff; | |
711 | offset -= insn & 0x400; /* Apply sign bit */ | |
712 | regs->ARM_pc = pc + (offset * 2); | |
713 | } | |
714 | ||
02d194f6 JM |
715 | static unsigned long __kprobes |
716 | t16_emulate_loregs(struct kprobe *p, struct pt_regs *regs) | |
717 | { | |
718 | unsigned long oldcpsr = regs->ARM_cpsr; | |
719 | unsigned long newcpsr; | |
720 | ||
721 | __asm__ __volatile__ ( | |
722 | "msr cpsr_fs, %[oldcpsr] \n\t" | |
723 | "ldmia %[regs], {r0-r7} \n\t" | |
724 | "blx %[fn] \n\t" | |
725 | "stmia %[regs], {r0-r7} \n\t" | |
726 | "mrs %[newcpsr], cpsr \n\t" | |
727 | : [newcpsr] "=r" (newcpsr) | |
728 | : [oldcpsr] "r" (oldcpsr), [regs] "r" (regs), | |
729 | [fn] "r" (p->ainsn.insn_fn) | |
730 | : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", | |
731 | "lr", "memory", "cc" | |
732 | ); | |
733 | ||
734 | return (oldcpsr & ~APSR_MASK) | (newcpsr & APSR_MASK); | |
735 | } | |
736 | ||
737 | static void __kprobes | |
738 | t16_emulate_loregs_rwflags(struct kprobe *p, struct pt_regs *regs) | |
739 | { | |
740 | regs->ARM_cpsr = t16_emulate_loregs(p, regs); | |
741 | } | |
742 | ||
743 | static void __kprobes | |
744 | t16_emulate_loregs_noitrwflags(struct kprobe *p, struct pt_regs *regs) | |
745 | { | |
746 | unsigned long cpsr = t16_emulate_loregs(p, regs); | |
747 | if (!in_it_block(cpsr)) | |
748 | regs->ARM_cpsr = cpsr; | |
749 | } | |
750 | ||
3b5940e8 JM |
751 | static void __kprobes |
752 | t16_emulate_hiregs(struct kprobe *p, struct pt_regs *regs) | |
753 | { | |
754 | kprobe_opcode_t insn = p->opcode; | |
755 | unsigned long pc = thumb_probe_pc(p); | |
756 | int rdn = (insn & 0x7) | ((insn & 0x80) >> 4); | |
757 | int rm = (insn >> 3) & 0xf; | |
758 | ||
759 | register unsigned long rdnv asm("r1"); | |
760 | register unsigned long rmv asm("r0"); | |
761 | unsigned long cpsr = regs->ARM_cpsr; | |
762 | ||
763 | rdnv = (rdn == 15) ? pc : regs->uregs[rdn]; | |
764 | rmv = (rm == 15) ? pc : regs->uregs[rm]; | |
765 | ||
766 | __asm__ __volatile__ ( | |
767 | "msr cpsr_fs, %[cpsr] \n\t" | |
768 | "blx %[fn] \n\t" | |
769 | "mrs %[cpsr], cpsr \n\t" | |
770 | : "=r" (rdnv), [cpsr] "=r" (cpsr) | |
771 | : "0" (rdnv), "r" (rmv), "1" (cpsr), [fn] "r" (p->ainsn.insn_fn) | |
772 | : "lr", "memory", "cc" | |
773 | ); | |
774 | ||
775 | if (rdn == 15) | |
776 | rdnv &= ~1; | |
777 | ||
778 | regs->uregs[rdn] = rdnv; | |
779 | regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); | |
780 | } | |
781 | ||
782 | static enum kprobe_insn __kprobes | |
783 | t16_decode_hiregs(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |
784 | { | |
785 | insn &= ~0x00ff; | |
786 | insn |= 0x001; /* Set Rdn = R1 and Rm = R0 */ | |
787 | ((u16 *)asi->insn)[0] = insn; | |
788 | asi->insn_handler = t16_emulate_hiregs; | |
789 | return INSN_GOOD; | |
790 | } | |
791 | ||
fd0c8d8a JM |
792 | static void __kprobes |
793 | t16_emulate_push(struct kprobe *p, struct pt_regs *regs) | |
794 | { | |
795 | __asm__ __volatile__ ( | |
796 | "ldr r9, [%[regs], #13*4] \n\t" | |
797 | "ldr r8, [%[regs], #14*4] \n\t" | |
798 | "ldmia %[regs], {r0-r7} \n\t" | |
799 | "blx %[fn] \n\t" | |
800 | "str r9, [%[regs], #13*4] \n\t" | |
801 | : | |
802 | : [regs] "r" (regs), [fn] "r" (p->ainsn.insn_fn) | |
803 | : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", | |
804 | "lr", "memory", "cc" | |
805 | ); | |
806 | } | |
807 | ||
808 | static enum kprobe_insn __kprobes | |
809 | t16_decode_push(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |
810 | { | |
811 | /* | |
812 | * To simulate a PUSH we use a Thumb-2 "STMDB R9!, {registers}" | |
813 | * and call it with R9=SP and LR in the register list represented | |
814 | * by R8. | |
815 | */ | |
816 | ((u16 *)asi->insn)[0] = 0xe929; /* 1st half STMDB R9!,{} */ | |
817 | ((u16 *)asi->insn)[1] = insn & 0x1ff; /* 2nd half (register list) */ | |
818 | asi->insn_handler = t16_emulate_push; | |
819 | return INSN_GOOD; | |
820 | } | |
821 | ||
822 | static void __kprobes | |
823 | t16_emulate_pop_nopc(struct kprobe *p, struct pt_regs *regs) | |
824 | { | |
825 | __asm__ __volatile__ ( | |
826 | "ldr r9, [%[regs], #13*4] \n\t" | |
827 | "ldmia %[regs], {r0-r7} \n\t" | |
828 | "blx %[fn] \n\t" | |
829 | "stmia %[regs], {r0-r7} \n\t" | |
830 | "str r9, [%[regs], #13*4] \n\t" | |
831 | : | |
832 | : [regs] "r" (regs), [fn] "r" (p->ainsn.insn_fn) | |
833 | : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r9", | |
834 | "lr", "memory", "cc" | |
835 | ); | |
836 | } | |
837 | ||
838 | static void __kprobes | |
839 | t16_emulate_pop_pc(struct kprobe *p, struct pt_regs *regs) | |
840 | { | |
841 | register unsigned long pc asm("r8"); | |
842 | ||
843 | __asm__ __volatile__ ( | |
844 | "ldr r9, [%[regs], #13*4] \n\t" | |
845 | "ldmia %[regs], {r0-r7} \n\t" | |
846 | "blx %[fn] \n\t" | |
847 | "stmia %[regs], {r0-r7} \n\t" | |
848 | "str r9, [%[regs], #13*4] \n\t" | |
849 | : "=r" (pc) | |
850 | : [regs] "r" (regs), [fn] "r" (p->ainsn.insn_fn) | |
851 | : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r9", | |
852 | "lr", "memory", "cc" | |
853 | ); | |
854 | ||
855 | bx_write_pc(pc, regs); | |
856 | } | |
857 | ||
858 | static enum kprobe_insn __kprobes | |
859 | t16_decode_pop(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |
860 | { | |
861 | /* | |
862 | * To simulate a POP we use a Thumb-2 "LDMDB R9!, {registers}" | |
863 | * and call it with R9=SP and PC in the register list represented | |
864 | * by R8. | |
865 | */ | |
866 | ((u16 *)asi->insn)[0] = 0xe8b9; /* 1st half LDMIA R9!,{} */ | |
867 | ((u16 *)asi->insn)[1] = insn & 0x1ff; /* 2nd half (register list) */ | |
868 | asi->insn_handler = insn & 0x100 ? t16_emulate_pop_pc | |
869 | : t16_emulate_pop_nopc; | |
870 | return INSN_GOOD; | |
871 | } | |
872 | ||
3f92dfed JM |
873 | static const union decode_item t16_table_1011[] = { |
874 | /* Miscellaneous 16-bit instructions */ | |
875 | ||
2f335829 JM |
876 | /* ADD (SP plus immediate) 1011 0000 0xxx xxxx */ |
877 | /* SUB (SP minus immediate) 1011 0000 1xxx xxxx */ | |
878 | DECODE_SIMULATE (0xff00, 0xb000, t16_simulate_add_sp_imm), | |
879 | ||
32818f31 JM |
880 | /* CBZ 1011 00x1 xxxx xxxx */ |
881 | /* CBNZ 1011 10x1 xxxx xxxx */ | |
882 | DECODE_SIMULATE (0xf500, 0xb100, t16_simulate_cbz), | |
883 | ||
884 | /* SXTH 1011 0010 00xx xxxx */ | |
885 | /* SXTB 1011 0010 01xx xxxx */ | |
886 | /* UXTH 1011 0010 10xx xxxx */ | |
887 | /* UXTB 1011 0010 11xx xxxx */ | |
888 | /* REV 1011 1010 00xx xxxx */ | |
889 | /* REV16 1011 1010 01xx xxxx */ | |
890 | /* ??? 1011 1010 10xx xxxx */ | |
891 | /* REVSH 1011 1010 11xx xxxx */ | |
892 | DECODE_REJECT (0xffc0, 0xba80), | |
893 | DECODE_EMULATE (0xf500, 0xb000, t16_emulate_loregs_rwflags), | |
894 | ||
fd0c8d8a JM |
895 | /* PUSH 1011 010x xxxx xxxx */ |
896 | DECODE_CUSTOM (0xfe00, 0xb400, t16_decode_push), | |
897 | /* POP 1011 110x xxxx xxxx */ | |
898 | DECODE_CUSTOM (0xfe00, 0xbc00, t16_decode_pop), | |
899 | ||
3f92dfed JM |
900 | /* |
901 | * If-Then, and hints | |
902 | * 1011 1111 xxxx xxxx | |
903 | */ | |
904 | ||
905 | /* YIELD 1011 1111 0001 0000 */ | |
906 | DECODE_OR (0xffff, 0xbf10), | |
907 | /* SEV 1011 1111 0100 0000 */ | |
908 | DECODE_EMULATE (0xffff, 0xbf40, kprobe_emulate_none), | |
909 | /* NOP 1011 1111 0000 0000 */ | |
910 | /* WFE 1011 1111 0010 0000 */ | |
911 | /* WFI 1011 1111 0011 0000 */ | |
912 | DECODE_SIMULATE (0xffcf, 0xbf00, kprobe_simulate_nop), | |
913 | /* Unassigned hints 1011 1111 xxxx 0000 */ | |
914 | DECODE_REJECT (0xff0f, 0xbf00), | |
5b94faf8 JM |
915 | /* IT 1011 1111 xxxx xxxx */ |
916 | DECODE_CUSTOM (0xff00, 0xbf00, t16_decode_it), | |
3f92dfed | 917 | |
0a188ccb JM |
918 | /* SETEND 1011 0110 010x xxxx */ |
919 | /* CPS 1011 0110 011x xxxx */ | |
920 | /* BKPT 1011 1110 xxxx xxxx */ | |
921 | /* And unallocated instructions... */ | |
3f92dfed JM |
922 | DECODE_END |
923 | }; | |
924 | ||
925 | const union decode_item kprobe_decode_thumb16_table[] = { | |
926 | ||
02d194f6 JM |
927 | /* |
928 | * Shift (immediate), add, subtract, move, and compare | |
929 | * 00xx xxxx xxxx xxxx | |
930 | */ | |
931 | ||
932 | /* CMP (immediate) 0010 1xxx xxxx xxxx */ | |
933 | DECODE_EMULATE (0xf800, 0x2800, t16_emulate_loregs_rwflags), | |
934 | ||
935 | /* ADD (register) 0001 100x xxxx xxxx */ | |
936 | /* SUB (register) 0001 101x xxxx xxxx */ | |
937 | /* LSL (immediate) 0000 0xxx xxxx xxxx */ | |
938 | /* LSR (immediate) 0000 1xxx xxxx xxxx */ | |
939 | /* ASR (immediate) 0001 0xxx xxxx xxxx */ | |
940 | /* ADD (immediate, Thumb) 0001 110x xxxx xxxx */ | |
941 | /* SUB (immediate, Thumb) 0001 111x xxxx xxxx */ | |
942 | /* MOV (immediate) 0010 0xxx xxxx xxxx */ | |
943 | /* ADD (immediate, Thumb) 0011 0xxx xxxx xxxx */ | |
944 | /* SUB (immediate, Thumb) 0011 1xxx xxxx xxxx */ | |
945 | DECODE_EMULATE (0xc000, 0x0000, t16_emulate_loregs_noitrwflags), | |
946 | ||
947 | /* | |
948 | * 16-bit Thumb data-processing instructions | |
949 | * 0100 00xx xxxx xxxx | |
950 | */ | |
951 | ||
952 | /* TST (register) 0100 0010 00xx xxxx */ | |
953 | DECODE_EMULATE (0xffc0, 0x4200, t16_emulate_loregs_rwflags), | |
954 | /* CMP (register) 0100 0010 10xx xxxx */ | |
955 | /* CMN (register) 0100 0010 11xx xxxx */ | |
956 | DECODE_EMULATE (0xff80, 0x4280, t16_emulate_loregs_rwflags), | |
957 | /* AND (register) 0100 0000 00xx xxxx */ | |
958 | /* EOR (register) 0100 0000 01xx xxxx */ | |
959 | /* LSL (register) 0100 0000 10xx xxxx */ | |
960 | /* LSR (register) 0100 0000 11xx xxxx */ | |
961 | /* ASR (register) 0100 0001 00xx xxxx */ | |
962 | /* ADC (register) 0100 0001 01xx xxxx */ | |
963 | /* SBC (register) 0100 0001 10xx xxxx */ | |
964 | /* ROR (register) 0100 0001 11xx xxxx */ | |
965 | /* RSB (immediate) 0100 0010 01xx xxxx */ | |
966 | /* ORR (register) 0100 0011 00xx xxxx */ | |
967 | /* MUL 0100 0011 00xx xxxx */ | |
968 | /* BIC (register) 0100 0011 10xx xxxx */ | |
969 | /* MVN (register) 0100 0011 10xx xxxx */ | |
970 | DECODE_EMULATE (0xfc00, 0x4000, t16_emulate_loregs_noitrwflags), | |
971 | ||
a9c3c29e JM |
972 | /* |
973 | * Special data instructions and branch and exchange | |
974 | * 0100 01xx xxxx xxxx | |
975 | */ | |
976 | ||
977 | /* BLX pc 0100 0111 1111 1xxx */ | |
978 | DECODE_REJECT (0xfff8, 0x47f8), | |
979 | ||
980 | /* BX (register) 0100 0111 0xxx xxxx */ | |
981 | /* BLX (register) 0100 0111 1xxx xxxx */ | |
982 | DECODE_SIMULATE (0xff00, 0x4700, t16_simulate_bxblx), | |
983 | ||
3b5940e8 JM |
984 | /* ADD pc, pc 0100 0100 1111 1111 */ |
985 | DECODE_REJECT (0xffff, 0x44ff), | |
986 | ||
987 | /* ADD (register) 0100 0100 xxxx xxxx */ | |
988 | /* CMP (register) 0100 0101 xxxx xxxx */ | |
989 | /* MOV (register) 0100 0110 xxxx xxxx */ | |
990 | DECODE_CUSTOM (0xfc00, 0x4400, t16_decode_hiregs), | |
991 | ||
f8695142 JM |
992 | /* |
993 | * Load from Literal Pool | |
994 | * LDR (literal) 0100 1xxx xxxx xxxx | |
995 | */ | |
996 | DECODE_SIMULATE (0xf800, 0x4800, t16_simulate_ldr_literal), | |
997 | ||
998 | /* | |
999 | * 16-bit Thumb Load/store instructions | |
1000 | * 0101 xxxx xxxx xxxx | |
1001 | * 011x xxxx xxxx xxxx | |
1002 | * 100x xxxx xxxx xxxx | |
1003 | */ | |
1004 | ||
1005 | /* STR (register) 0101 000x xxxx xxxx */ | |
1006 | /* STRH (register) 0101 001x xxxx xxxx */ | |
1007 | /* STRB (register) 0101 010x xxxx xxxx */ | |
1008 | /* LDRSB (register) 0101 011x xxxx xxxx */ | |
1009 | /* LDR (register) 0101 100x xxxx xxxx */ | |
1010 | /* LDRH (register) 0101 101x xxxx xxxx */ | |
1011 | /* LDRB (register) 0101 110x xxxx xxxx */ | |
1012 | /* LDRSH (register) 0101 111x xxxx xxxx */ | |
1013 | /* STR (immediate, Thumb) 0110 0xxx xxxx xxxx */ | |
1014 | /* LDR (immediate, Thumb) 0110 1xxx xxxx xxxx */ | |
1015 | /* STRB (immediate, Thumb) 0111 0xxx xxxx xxxx */ | |
1016 | /* LDRB (immediate, Thumb) 0111 1xxx xxxx xxxx */ | |
1017 | DECODE_EMULATE (0xc000, 0x4000, t16_emulate_loregs_rwflags), | |
1018 | /* STRH (immediate, Thumb) 1000 0xxx xxxx xxxx */ | |
1019 | /* LDRH (immediate, Thumb) 1000 1xxx xxxx xxxx */ | |
1020 | DECODE_EMULATE (0xf000, 0x8000, t16_emulate_loregs_rwflags), | |
1021 | /* STR (immediate, Thumb) 1001 0xxx xxxx xxxx */ | |
1022 | /* LDR (immediate, Thumb) 1001 1xxx xxxx xxxx */ | |
1023 | DECODE_SIMULATE (0xf000, 0x9000, t16_simulate_ldrstr_sp_relative), | |
1024 | ||
2f335829 JM |
1025 | /* |
1026 | * Generate PC-/SP-relative address | |
1027 | * ADR (literal) 1010 0xxx xxxx xxxx | |
1028 | * ADD (SP plus immediate) 1010 1xxx xxxx xxxx | |
1029 | */ | |
1030 | DECODE_SIMULATE (0xf000, 0xa000, t16_simulate_reladr), | |
1031 | ||
3f92dfed JM |
1032 | /* |
1033 | * Miscellaneous 16-bit instructions | |
1034 | * 1011 xxxx xxxx xxxx | |
1035 | */ | |
1036 | DECODE_TABLE (0xf000, 0xb000, t16_table_1011), | |
1037 | ||
f8695142 JM |
1038 | /* STM 1100 0xxx xxxx xxxx */ |
1039 | /* LDM 1100 1xxx xxxx xxxx */ | |
1040 | DECODE_EMULATE (0xf000, 0xc000, t16_emulate_loregs_rwflags), | |
1041 | ||
44495667 JM |
1042 | /* |
1043 | * Conditional branch, and Supervisor Call | |
1044 | */ | |
1045 | ||
1046 | /* Permanently UNDEFINED 1101 1110 xxxx xxxx */ | |
1047 | /* SVC 1101 1111 xxxx xxxx */ | |
1048 | DECODE_REJECT (0xfe00, 0xde00), | |
1049 | ||
396b41f6 JM |
1050 | /* Conditional branch 1101 xxxx xxxx xxxx */ |
1051 | DECODE_CUSTOM (0xf000, 0xd000, t16_decode_cond_branch), | |
1052 | ||
1053 | /* | |
1054 | * Unconditional branch | |
1055 | * B 1110 0xxx xxxx xxxx | |
1056 | */ | |
1057 | DECODE_SIMULATE (0xf800, 0xe000, t16_simulate_branch), | |
1058 | ||
3f92dfed JM |
1059 | DECODE_END |
1060 | }; | |
1061 | ||
eaf4f33f JM |
1062 | static unsigned long __kprobes thumb_check_cc(unsigned long cpsr) |
1063 | { | |
1064 | if (unlikely(in_it_block(cpsr))) | |
1065 | return kprobe_condition_checks[current_cond(cpsr)](cpsr); | |
1066 | return true; | |
1067 | } | |
1068 | ||
c6a7d97d JM |
1069 | static void __kprobes thumb16_singlestep(struct kprobe *p, struct pt_regs *regs) |
1070 | { | |
1071 | regs->ARM_pc += 2; | |
1072 | p->ainsn.insn_handler(p, regs); | |
1073 | regs->ARM_cpsr = it_advance(regs->ARM_cpsr); | |
1074 | } | |
1075 | ||
1076 | static void __kprobes thumb32_singlestep(struct kprobe *p, struct pt_regs *regs) | |
1077 | { | |
1078 | regs->ARM_pc += 4; | |
1079 | p->ainsn.insn_handler(p, regs); | |
1080 | regs->ARM_cpsr = it_advance(regs->ARM_cpsr); | |
1081 | } | |
1082 | ||
24371707 JM |
1083 | enum kprobe_insn __kprobes |
1084 | thumb16_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |
1085 | { | |
c6a7d97d | 1086 | asi->insn_singlestep = thumb16_singlestep; |
eaf4f33f | 1087 | asi->insn_check_cc = thumb_check_cc; |
3f92dfed | 1088 | return kprobe_decode_insn(insn, asi, kprobe_decode_thumb16_table, true); |
24371707 JM |
1089 | } |
1090 | ||
1091 | enum kprobe_insn __kprobes | |
1092 | thumb32_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |
1093 | { | |
c6a7d97d | 1094 | asi->insn_singlestep = thumb32_singlestep; |
eaf4f33f | 1095 | asi->insn_check_cc = thumb_check_cc; |
f39ca8b4 | 1096 | return kprobe_decode_insn(insn, asi, kprobe_decode_thumb32_table, true); |
24371707 | 1097 | } |