Branch data Line data Source code
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 : 0 : emulate_ldrdstrd(probes_opcode_t insn,
70 : : struct arch_probes_insn *asi, struct pt_regs *regs)
71 : : {
72 : 0 : unsigned long pc = regs->ARM_pc + 4;
73 : 0 : int rt = (insn >> 12) & 0xf;
74 : 0 : int rn = (insn >> 16) & 0xf;
75 : 0 : int rm = insn & 0xf;
76 : :
77 : 0 : register unsigned long rtv asm("r0") = regs->uregs[rt];
78 : 0 : register unsigned long rt2v asm("r1") = regs->uregs[rt+1];
79 : 0 : register unsigned long rnv asm("r2") = (rn == 15) ? pc
80 : 0 : : regs->uregs[rn];
81 : 0 : register unsigned long rmv asm("r3") = regs->uregs[rm];
82 : :
83 : 0 : __asm__ __volatile__ (
84 : : BLX("%[fn]")
85 : : : "=r" (rtv), "=r" (rt2v), "=r" (rnv)
86 : : : "0" (rtv), "1" (rt2v), "2" (rnv), "r" (rmv),
87 : 0 : [fn] "r" (asi->insn_fn)
88 : : : "lr", "memory", "cc"
89 : : );
90 : :
91 : 0 : regs->uregs[rt] = rtv;
92 : 0 : regs->uregs[rt+1] = rt2v;
93 : 0 : if (is_writeback(insn))
94 : 0 : regs->uregs[rn] = rnv;
95 : 0 : }
96 : :
97 : : static void __kprobes
98 : 0 : emulate_ldr(probes_opcode_t insn,
99 : : struct arch_probes_insn *asi, struct pt_regs *regs)
100 : : {
101 : 0 : unsigned long pc = regs->ARM_pc + 4;
102 : 0 : int rt = (insn >> 12) & 0xf;
103 : 0 : int rn = (insn >> 16) & 0xf;
104 : 0 : int rm = insn & 0xf;
105 : :
106 : : register unsigned long rtv asm("r0");
107 : 0 : register unsigned long rnv asm("r2") = (rn == 15) ? pc
108 : 0 : : regs->uregs[rn];
109 : 0 : register unsigned long rmv asm("r3") = regs->uregs[rm];
110 : :
111 : 0 : __asm__ __volatile__ (
112 : : BLX("%[fn]")
113 : : : "=r" (rtv), "=r" (rnv)
114 : 0 : : "1" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn)
115 : : : "lr", "memory", "cc"
116 : : );
117 : :
118 : 0 : if (rt == 15)
119 : 0 : load_write_pc(rtv, regs);
120 : : else
121 : 0 : regs->uregs[rt] = rtv;
122 : :
123 : 0 : if (is_writeback(insn))
124 : 0 : regs->uregs[rn] = rnv;
125 : 0 : }
126 : :
127 : : static void __kprobes
128 : 0 : emulate_str(probes_opcode_t insn,
129 : : struct arch_probes_insn *asi, struct pt_regs *regs)
130 : : {
131 : 0 : unsigned long rtpc = regs->ARM_pc - 4 + str_pc_offset;
132 : : unsigned long rnpc = regs->ARM_pc + 4;
133 : 0 : int rt = (insn >> 12) & 0xf;
134 : 0 : int rn = (insn >> 16) & 0xf;
135 : 0 : int rm = insn & 0xf;
136 : :
137 : 0 : register unsigned long rtv asm("r0") = (rt == 15) ? rtpc
138 : 0 : : regs->uregs[rt];
139 : 0 : register unsigned long rnv asm("r2") = (rn == 15) ? rnpc
140 : 0 : : regs->uregs[rn];
141 : 0 : register unsigned long rmv asm("r3") = regs->uregs[rm];
142 : :
143 : 0 : __asm__ __volatile__ (
144 : : BLX("%[fn]")
145 : : : "=r" (rnv)
146 : 0 : : "r" (rtv), "0" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn)
147 : : : "lr", "memory", "cc"
148 : : );
149 : :
150 : 0 : if (is_writeback(insn))
151 : 0 : regs->uregs[rn] = rnv;
152 : 0 : }
153 : :
154 : : static void __kprobes
155 : 0 : emulate_rd12rn16rm0rs8_rwflags(probes_opcode_t insn,
156 : : struct arch_probes_insn *asi, struct pt_regs *regs)
157 : : {
158 : 0 : unsigned long pc = regs->ARM_pc + 4;
159 : 0 : int rd = (insn >> 12) & 0xf;
160 : 0 : int rn = (insn >> 16) & 0xf;
161 : 0 : int rm = insn & 0xf;
162 : 0 : int rs = (insn >> 8) & 0xf;
163 : :
164 : 0 : register unsigned long rdv asm("r0") = regs->uregs[rd];
165 : 0 : register unsigned long rnv asm("r2") = (rn == 15) ? pc
166 : 0 : : regs->uregs[rn];
167 : 0 : register unsigned long rmv asm("r3") = (rm == 15) ? pc
168 : 0 : : regs->uregs[rm];
169 : 0 : register unsigned long rsv asm("r1") = regs->uregs[rs];
170 : 0 : unsigned long cpsr = regs->ARM_cpsr;
171 : :
172 : 0 : __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 : 0 : "1" (cpsr), [fn] "r" (asi->insn_fn)
179 : : : "lr", "memory", "cc"
180 : : );
181 : :
182 : 0 : if (rd == 15)
183 : 0 : alu_write_pc(rdv, regs);
184 : : else
185 : 0 : regs->uregs[rd] = rdv;
186 : 0 : regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
187 : 0 : }
188 : :
189 : : static void __kprobes
190 : 0 : emulate_rd12rn16rm0_rwflags_nopc(probes_opcode_t insn,
191 : : struct arch_probes_insn *asi, struct pt_regs *regs)
192 : : {
193 : 0 : int rd = (insn >> 12) & 0xf;
194 : 0 : int rn = (insn >> 16) & 0xf;
195 : 0 : int rm = insn & 0xf;
196 : :
197 : 0 : register unsigned long rdv asm("r0") = regs->uregs[rd];
198 : 0 : register unsigned long rnv asm("r2") = regs->uregs[rn];
199 : 0 : register unsigned long rmv asm("r3") = regs->uregs[rm];
200 : 0 : unsigned long cpsr = regs->ARM_cpsr;
201 : :
202 : 0 : __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 : 0 : "1" (cpsr), [fn] "r" (asi->insn_fn)
209 : : : "lr", "memory", "cc"
210 : : );
211 : :
212 : 0 : regs->uregs[rd] = rdv;
213 : 0 : regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
214 : 0 : }
215 : :
216 : : static void __kprobes
217 : 0 : emulate_rd16rn12rm0rs8_rwflags_nopc(probes_opcode_t insn,
218 : : struct arch_probes_insn *asi,
219 : : struct pt_regs *regs)
220 : : {
221 : 0 : int rd = (insn >> 16) & 0xf;
222 : 0 : int rn = (insn >> 12) & 0xf;
223 : 0 : int rm = insn & 0xf;
224 : 0 : int rs = (insn >> 8) & 0xf;
225 : :
226 : 0 : register unsigned long rdv asm("r2") = regs->uregs[rd];
227 : 0 : register unsigned long rnv asm("r0") = regs->uregs[rn];
228 : 0 : register unsigned long rmv asm("r3") = regs->uregs[rm];
229 : 0 : register unsigned long rsv asm("r1") = regs->uregs[rs];
230 : 0 : unsigned long cpsr = regs->ARM_cpsr;
231 : :
232 : 0 : __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 : 0 : "1" (cpsr), [fn] "r" (asi->insn_fn)
239 : : : "lr", "memory", "cc"
240 : : );
241 : :
242 : 0 : regs->uregs[rd] = rdv;
243 : 0 : regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
244 : 0 : }
245 : :
246 : : static void __kprobes
247 : 0 : emulate_rd12rm0_noflags_nopc(probes_opcode_t insn,
248 : : struct arch_probes_insn *asi, struct pt_regs *regs)
249 : : {
250 : 0 : int rd = (insn >> 12) & 0xf;
251 : 0 : int rm = insn & 0xf;
252 : :
253 : 0 : register unsigned long rdv asm("r0") = regs->uregs[rd];
254 : 0 : register unsigned long rmv asm("r3") = regs->uregs[rm];
255 : :
256 : 0 : __asm__ __volatile__ (
257 : : BLX("%[fn]")
258 : : : "=r" (rdv)
259 : 0 : : "0" (rdv), "r" (rmv), [fn] "r" (asi->insn_fn)
260 : : : "lr", "memory", "cc"
261 : : );
262 : :
263 : 0 : regs->uregs[rd] = rdv;
264 : 0 : }
265 : :
266 : : static void __kprobes
267 : 0 : emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(probes_opcode_t insn,
268 : : struct arch_probes_insn *asi,
269 : : struct pt_regs *regs)
270 : : {
271 : 0 : int rdlo = (insn >> 12) & 0xf;
272 : 0 : int rdhi = (insn >> 16) & 0xf;
273 : 0 : int rn = insn & 0xf;
274 : 0 : int rm = (insn >> 8) & 0xf;
275 : :
276 : 0 : register unsigned long rdlov asm("r0") = regs->uregs[rdlo];
277 : 0 : register unsigned long rdhiv asm("r2") = regs->uregs[rdhi];
278 : 0 : register unsigned long rnv asm("r3") = regs->uregs[rn];
279 : 0 : register unsigned long rmv asm("r1") = regs->uregs[rm];
280 : 0 : unsigned long cpsr = regs->ARM_cpsr;
281 : :
282 : 0 : __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 : 0 : "2" (cpsr), [fn] "r" (asi->insn_fn)
289 : : : "lr", "memory", "cc"
290 : : );
291 : :
292 : 0 : regs->uregs[rdlo] = rdlov;
293 : 0 : regs->uregs[rdhi] = rdhiv;
294 : 0 : regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
295 : 0 : }
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};
|