1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * arch/arm/probes/kprobes/actions-arm.c |
4 | * |
5 | * Copyright (C) 2006, 2007 Motorola Inc. |
6 | */ |
7 | |
8 | /* |
9 | * We do not have hardware single-stepping on ARM, This |
10 | * effort is further complicated by the ARM not having a |
11 | * "next PC" register. Instructions that change the PC |
12 | * can't be safely single-stepped in a MP environment, so |
13 | * we have a lot of work to do: |
14 | * |
15 | * In the prepare phase: |
16 | * *) If it is an instruction that does anything |
17 | * with the CPU mode, we reject it for a kprobe. |
18 | * (This is out of laziness rather than need. The |
19 | * instructions could be simulated.) |
20 | * |
21 | * *) Otherwise, decode the instruction rewriting its |
22 | * registers to take fixed, ordered registers and |
23 | * setting a handler for it to run the instruction. |
24 | * |
25 | * In the execution phase by an instruction's handler: |
26 | * |
27 | * *) If the PC is written to by the instruction, the |
28 | * instruction must be fully simulated in software. |
29 | * |
30 | * *) Otherwise, a modified form of the instruction is |
31 | * directly executed. Its handler calls the |
32 | * instruction in insn[0]. In insn[1] is a |
33 | * "mov pc, lr" to return. |
34 | * |
35 | * Before calling, load up the reordered registers |
36 | * from the original instruction's registers. If one |
37 | * of the original input registers is the PC, compute |
38 | * and adjust the appropriate input register. |
39 | * |
40 | * After call completes, copy the output registers to |
41 | * the original instruction's original registers. |
42 | * |
43 | * We don't use a real breakpoint instruction since that |
44 | * would have us in the kernel go from SVC mode to SVC |
45 | * mode losing the link register. Instead we use an |
46 | * undefined instruction. To simplify processing, the |
47 | * undefined instruction used for kprobes must be reserved |
48 | * exclusively for kprobes use. |
49 | * |
50 | * TODO: ifdef out some instruction decoding based on architecture. |
51 | */ |
52 | |
53 | #include <linux/kernel.h> |
54 | #include <linux/kprobes.h> |
55 | #include <linux/ptrace.h> |
56 | |
57 | #include "../decode-arm.h" |
58 | #include "core.h" |
59 | #include "checkers.h" |
60 | |
61 | #if __LINUX_ARM_ARCH__ >= 6 |
62 | #define BLX(reg) "blx "reg" \n\t" |
63 | #else |
64 | #define BLX(reg) "mov lr, pc \n\t" \ |
65 | "mov pc, "reg" \n\t" |
66 | #endif |
67 | |
68 | static void __kprobes |
69 | emulate_ldrdstrd(probes_opcode_t insn, |
70 | struct arch_probes_insn *asi, struct pt_regs *regs) |
71 | { |
72 | unsigned long pc = regs->ARM_pc + 4; |
73 | int rt = (insn >> 12) & 0xf; |
74 | int rn = (insn >> 16) & 0xf; |
75 | int rm = insn & 0xf; |
76 | |
77 | register unsigned long rtv asm("r0" ) = regs->uregs[rt]; |
78 | register unsigned long rt2v asm("r1" ) = regs->uregs[rt+1]; |
79 | register unsigned long rnv asm("r2" ) = (rn == 15) ? pc |
80 | : regs->uregs[rn]; |
81 | register unsigned long rmv asm("r3" ) = regs->uregs[rm]; |
82 | |
83 | __asm__ __volatile__ ( |
84 | BLX("%[fn]" ) |
85 | : "=r" (rtv), "=r" (rt2v), "=r" (rnv) |
86 | : "0" (rtv), "1" (rt2v), "2" (rnv), "r" (rmv), |
87 | [fn] "r" (asi->insn_fn) |
88 | : "lr" , "memory" , "cc" |
89 | ); |
90 | |
91 | regs->uregs[rt] = rtv; |
92 | regs->uregs[rt+1] = rt2v; |
93 | if (is_writeback(insn)) |
94 | regs->uregs[rn] = rnv; |
95 | } |
96 | |
97 | static void __kprobes |
98 | emulate_ldr(probes_opcode_t insn, |
99 | struct arch_probes_insn *asi, struct pt_regs *regs) |
100 | { |
101 | unsigned long pc = regs->ARM_pc + 4; |
102 | int rt = (insn >> 12) & 0xf; |
103 | int rn = (insn >> 16) & 0xf; |
104 | int rm = insn & 0xf; |
105 | |
106 | register unsigned long rtv asm("r0" ); |
107 | register unsigned long rnv asm("r2" ) = (rn == 15) ? pc |
108 | : regs->uregs[rn]; |
109 | register unsigned long rmv asm("r3" ) = regs->uregs[rm]; |
110 | |
111 | __asm__ __volatile__ ( |
112 | BLX("%[fn]" ) |
113 | : "=r" (rtv), "=r" (rnv) |
114 | : "1" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn) |
115 | : "lr" , "memory" , "cc" |
116 | ); |
117 | |
118 | if (rt == 15) |
119 | load_write_pc(pcv: rtv, regs); |
120 | else |
121 | regs->uregs[rt] = rtv; |
122 | |
123 | if (is_writeback(insn)) |
124 | regs->uregs[rn] = rnv; |
125 | } |
126 | |
127 | static void __kprobes |
128 | emulate_str(probes_opcode_t insn, |
129 | struct arch_probes_insn *asi, struct pt_regs *regs) |
130 | { |
131 | unsigned long rtpc = regs->ARM_pc - 4 + str_pc_offset; |
132 | unsigned long rnpc = regs->ARM_pc + 4; |
133 | int rt = (insn >> 12) & 0xf; |
134 | int rn = (insn >> 16) & 0xf; |
135 | int rm = insn & 0xf; |
136 | |
137 | register unsigned long rtv asm("r0" ) = (rt == 15) ? rtpc |
138 | : regs->uregs[rt]; |
139 | register unsigned long rnv asm("r2" ) = (rn == 15) ? rnpc |
140 | : regs->uregs[rn]; |
141 | register unsigned long rmv asm("r3" ) = regs->uregs[rm]; |
142 | |
143 | __asm__ __volatile__ ( |
144 | BLX("%[fn]" ) |
145 | : "=r" (rnv) |
146 | : "r" (rtv), "0" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn) |
147 | : "lr" , "memory" , "cc" |
148 | ); |
149 | |
150 | if (is_writeback(insn)) |
151 | regs->uregs[rn] = rnv; |
152 | } |
153 | |
154 | static void __kprobes |
155 | emulate_rd12rn16rm0rs8_rwflags(probes_opcode_t insn, |
156 | struct arch_probes_insn *asi, struct pt_regs *regs) |
157 | { |
158 | unsigned long pc = regs->ARM_pc + 4; |
159 | int rd = (insn >> 12) & 0xf; |
160 | int rn = (insn >> 16) & 0xf; |
161 | int rm = insn & 0xf; |
162 | int rs = (insn >> 8) & 0xf; |
163 | |
164 | register unsigned long rdv asm("r0" ) = regs->uregs[rd]; |
165 | register unsigned long rnv asm("r2" ) = (rn == 15) ? pc |
166 | : regs->uregs[rn]; |
167 | register unsigned long rmv asm("r3" ) = (rm == 15) ? pc |
168 | : regs->uregs[rm]; |
169 | register unsigned long rsv asm("r1" ) = regs->uregs[rs]; |
170 | unsigned long cpsr = regs->ARM_cpsr; |
171 | |
172 | __asm__ __volatile__ ( |
173 | "msr cpsr_fs, %[cpsr] \n\t" |
174 | BLX("%[fn]" ) |
175 | "mrs %[cpsr], cpsr \n\t" |
176 | : "=r" (rdv), [cpsr] "=r" (cpsr) |
177 | : "0" (rdv), "r" (rnv), "r" (rmv), "r" (rsv), |
178 | "1" (cpsr), [fn] "r" (asi->insn_fn) |
179 | : "lr" , "memory" , "cc" |
180 | ); |
181 | |
182 | if (rd == 15) |
183 | alu_write_pc(pcv: rdv, regs); |
184 | else |
185 | regs->uregs[rd] = rdv; |
186 | regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); |
187 | } |
188 | |
189 | static void __kprobes |
190 | emulate_rd12rn16rm0_rwflags_nopc(probes_opcode_t insn, |
191 | struct arch_probes_insn *asi, struct pt_regs *regs) |
192 | { |
193 | int rd = (insn >> 12) & 0xf; |
194 | int rn = (insn >> 16) & 0xf; |
195 | int rm = insn & 0xf; |
196 | |
197 | register unsigned long rdv asm("r0" ) = regs->uregs[rd]; |
198 | register unsigned long rnv asm("r2" ) = regs->uregs[rn]; |
199 | register unsigned long rmv asm("r3" ) = regs->uregs[rm]; |
200 | unsigned long cpsr = regs->ARM_cpsr; |
201 | |
202 | __asm__ __volatile__ ( |
203 | "msr cpsr_fs, %[cpsr] \n\t" |
204 | BLX("%[fn]" ) |
205 | "mrs %[cpsr], cpsr \n\t" |
206 | : "=r" (rdv), [cpsr] "=r" (cpsr) |
207 | : "0" (rdv), "r" (rnv), "r" (rmv), |
208 | "1" (cpsr), [fn] "r" (asi->insn_fn) |
209 | : "lr" , "memory" , "cc" |
210 | ); |
211 | |
212 | regs->uregs[rd] = rdv; |
213 | regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); |
214 | } |
215 | |
216 | static void __kprobes |
217 | emulate_rd16rn12rm0rs8_rwflags_nopc(probes_opcode_t insn, |
218 | struct arch_probes_insn *asi, |
219 | struct pt_regs *regs) |
220 | { |
221 | int rd = (insn >> 16) & 0xf; |
222 | int rn = (insn >> 12) & 0xf; |
223 | int rm = insn & 0xf; |
224 | int rs = (insn >> 8) & 0xf; |
225 | |
226 | register unsigned long rdv asm("r2" ) = regs->uregs[rd]; |
227 | register unsigned long rnv asm("r0" ) = regs->uregs[rn]; |
228 | register unsigned long rmv asm("r3" ) = regs->uregs[rm]; |
229 | register unsigned long rsv asm("r1" ) = regs->uregs[rs]; |
230 | unsigned long cpsr = regs->ARM_cpsr; |
231 | |
232 | __asm__ __volatile__ ( |
233 | "msr cpsr_fs, %[cpsr] \n\t" |
234 | BLX("%[fn]" ) |
235 | "mrs %[cpsr], cpsr \n\t" |
236 | : "=r" (rdv), [cpsr] "=r" (cpsr) |
237 | : "0" (rdv), "r" (rnv), "r" (rmv), "r" (rsv), |
238 | "1" (cpsr), [fn] "r" (asi->insn_fn) |
239 | : "lr" , "memory" , "cc" |
240 | ); |
241 | |
242 | regs->uregs[rd] = rdv; |
243 | regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); |
244 | } |
245 | |
246 | static void __kprobes |
247 | emulate_rd12rm0_noflags_nopc(probes_opcode_t insn, |
248 | struct arch_probes_insn *asi, struct pt_regs *regs) |
249 | { |
250 | int rd = (insn >> 12) & 0xf; |
251 | int rm = insn & 0xf; |
252 | |
253 | register unsigned long rdv asm("r0" ) = regs->uregs[rd]; |
254 | register unsigned long rmv asm("r3" ) = regs->uregs[rm]; |
255 | |
256 | __asm__ __volatile__ ( |
257 | BLX("%[fn]" ) |
258 | : "=r" (rdv) |
259 | : "0" (rdv), "r" (rmv), [fn] "r" (asi->insn_fn) |
260 | : "lr" , "memory" , "cc" |
261 | ); |
262 | |
263 | regs->uregs[rd] = rdv; |
264 | } |
265 | |
266 | static void __kprobes |
267 | emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(probes_opcode_t insn, |
268 | struct arch_probes_insn *asi, |
269 | struct pt_regs *regs) |
270 | { |
271 | int rdlo = (insn >> 12) & 0xf; |
272 | int rdhi = (insn >> 16) & 0xf; |
273 | int rn = insn & 0xf; |
274 | int rm = (insn >> 8) & 0xf; |
275 | |
276 | register unsigned long rdlov asm("r0" ) = regs->uregs[rdlo]; |
277 | register unsigned long rdhiv asm("r2" ) = regs->uregs[rdhi]; |
278 | register unsigned long rnv asm("r3" ) = regs->uregs[rn]; |
279 | register unsigned long rmv asm("r1" ) = regs->uregs[rm]; |
280 | unsigned long cpsr = regs->ARM_cpsr; |
281 | |
282 | __asm__ __volatile__ ( |
283 | "msr cpsr_fs, %[cpsr] \n\t" |
284 | BLX("%[fn]" ) |
285 | "mrs %[cpsr], cpsr \n\t" |
286 | : "=r" (rdlov), "=r" (rdhiv), [cpsr] "=r" (cpsr) |
287 | : "0" (rdlov), "1" (rdhiv), "r" (rnv), "r" (rmv), |
288 | "2" (cpsr), [fn] "r" (asi->insn_fn) |
289 | : "lr" , "memory" , "cc" |
290 | ); |
291 | |
292 | regs->uregs[rdlo] = rdlov; |
293 | regs->uregs[rdhi] = rdhiv; |
294 | regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); |
295 | } |
296 | |
297 | const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = { |
298 | [PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop}, |
299 | [PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop}, |
300 | [PROBES_BRANCH_IMM] = {.handler = simulate_blx1}, |
301 | [PROBES_MRS] = {.handler = simulate_mrs}, |
302 | [PROBES_BRANCH_REG] = {.handler = simulate_blx2bx}, |
303 | [PROBES_CLZ] = {.handler = emulate_rd12rm0_noflags_nopc}, |
304 | [PROBES_SATURATING_ARITHMETIC] = { |
305 | .handler = emulate_rd12rn16rm0_rwflags_nopc}, |
306 | [PROBES_MUL1] = {.handler = emulate_rdlo12rdhi16rn0rm8_rwflags_nopc}, |
307 | [PROBES_MUL2] = {.handler = emulate_rd16rn12rm0rs8_rwflags_nopc}, |
308 | [PROBES_SWP] = {.handler = emulate_rd12rn16rm0_rwflags_nopc}, |
309 | [PROBES_LDRSTRD] = {.handler = emulate_ldrdstrd}, |
310 | [PROBES_LOAD_EXTRA] = {.handler = emulate_ldr}, |
311 | [PROBES_LOAD] = {.handler = emulate_ldr}, |
312 | [PROBES_STORE_EXTRA] = {.handler = emulate_str}, |
313 | [PROBES_STORE] = {.handler = emulate_str}, |
314 | [PROBES_MOV_IP_SP] = {.handler = simulate_mov_ipsp}, |
315 | [PROBES_DATA_PROCESSING_REG] = { |
316 | .handler = emulate_rd12rn16rm0rs8_rwflags}, |
317 | [PROBES_DATA_PROCESSING_IMM] = { |
318 | .handler = emulate_rd12rn16rm0rs8_rwflags}, |
319 | [PROBES_MOV_HALFWORD] = {.handler = emulate_rd12rm0_noflags_nopc}, |
320 | [PROBES_SEV] = {.handler = probes_emulate_none}, |
321 | [PROBES_WFE] = {.handler = probes_simulate_nop}, |
322 | [PROBES_SATURATE] = {.handler = emulate_rd12rn16rm0_rwflags_nopc}, |
323 | [PROBES_REV] = {.handler = emulate_rd12rm0_noflags_nopc}, |
324 | [PROBES_MMI] = {.handler = emulate_rd12rn16rm0_rwflags_nopc}, |
325 | [PROBES_PACK] = {.handler = emulate_rd12rn16rm0_rwflags_nopc}, |
326 | [PROBES_EXTEND] = {.handler = emulate_rd12rm0_noflags_nopc}, |
327 | [PROBES_EXTEND_ADD] = {.handler = emulate_rd12rn16rm0_rwflags_nopc}, |
328 | [PROBES_MUL_ADD_LONG] = { |
329 | .handler = emulate_rdlo12rdhi16rn0rm8_rwflags_nopc}, |
330 | [PROBES_MUL_ADD] = {.handler = emulate_rd16rn12rm0rs8_rwflags_nopc}, |
331 | [PROBES_BITFIELD] = {.handler = emulate_rd12rm0_noflags_nopc}, |
332 | [PROBES_BRANCH] = {.handler = simulate_bbl}, |
333 | [PROBES_LDMSTM] = {.decoder = kprobe_decode_ldmstm} |
334 | }; |
335 | |
336 | const struct decode_checker *kprobes_arm_checkers[] = {arm_stack_checker, arm_regs_checker, NULL}; |
337 | |