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
68static void __kprobes
69emulate_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
97static void __kprobes
98emulate_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(rtv, regs);
120	else
121		regs->uregs[rt] = rtv;
122
123	if (is_writeback(insn))
124		regs->uregs[rn] = rnv;
125}
126
127static void __kprobes
128emulate_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
154static void __kprobes
155emulate_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(rdv, regs);
184	else
185		regs->uregs[rd] = rdv;
186	regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
187}
188
189static void __kprobes
190emulate_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
216static void __kprobes
217emulate_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
246static void __kprobes
247emulate_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
266static void __kprobes
267emulate_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
297const 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
336const struct decode_checker *kprobes_arm_checkers[] = {arm_stack_checker, arm_regs_checker, NULL};
337