1 // SPDX-License-Identifier: GPL-2.0-only
3 * arch/arm/probes/kprobes/actions-arm.c
5 * Copyright (C) 2006, 2007 Motorola Inc.
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:
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.)
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.
25 * In the execution phase by an instruction's handler:
27 * *) If the PC is written to by the instruction, the
28 * instruction must be fully simulated in software.
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.
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.
40 * After call completes, copy the output registers to
41 * the original instruction's original registers.
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.
50 * TODO: ifdef out some instruction decoding based on architecture.
53 #include <linux/kernel.h>
54 #include <linux/kprobes.h>
55 #include <linux/ptrace.h>
57 #include "../decode-arm.h"
61 #if __LINUX_ARM_ARCH__ >= 6
62 #define BLX(reg) "blx "reg" \n\t"
64 #define BLX(reg) "mov lr, pc \n\t" \
69 emulate_ldrdstrd(probes_opcode_t insn
,
70 struct arch_probes_insn
*asi
, struct pt_regs
*regs
)
72 unsigned long pc
= regs
->ARM_pc
+ 4;
73 int rt
= (insn
>> 12) & 0xf;
74 int rn
= (insn
>> 16) & 0xf;
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
81 register unsigned long rmv
asm("r3") = regs
->uregs
[rm
];
83 __asm__
__volatile__ (
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"
91 regs
->uregs
[rt
] = rtv
;
92 regs
->uregs
[rt
+1] = rt2v
;
93 if (is_writeback(insn
))
94 regs
->uregs
[rn
] = rnv
;
98 emulate_ldr(probes_opcode_t insn
,
99 struct arch_probes_insn
*asi
, struct pt_regs
*regs
)
101 unsigned long pc
= regs
->ARM_pc
+ 4;
102 int rt
= (insn
>> 12) & 0xf;
103 int rn
= (insn
>> 16) & 0xf;
106 register unsigned long rtv
asm("r0");
107 register unsigned long rnv
asm("r2") = (rn
== 15) ? pc
109 register unsigned long rmv
asm("r3") = regs
->uregs
[rm
];
111 __asm__
__volatile__ (
113 : "=r" (rtv
), "=r" (rnv
)
114 : "1" (rnv
), "r" (rmv
), [fn
] "r" (asi
->insn_fn
)
115 : "lr", "memory", "cc"
119 load_write_pc(rtv
, regs
);
121 regs
->uregs
[rt
] = rtv
;
123 if (is_writeback(insn
))
124 regs
->uregs
[rn
] = rnv
;
127 static void __kprobes
128 emulate_str(probes_opcode_t insn
,
129 struct arch_probes_insn
*asi
, struct pt_regs
*regs
)
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;
137 register unsigned long rtv
asm("r0") = (rt
== 15) ? rtpc
139 register unsigned long rnv
asm("r2") = (rn
== 15) ? rnpc
141 register unsigned long rmv
asm("r3") = regs
->uregs
[rm
];
143 __asm__
__volatile__ (
146 : "r" (rtv
), "0" (rnv
), "r" (rmv
), [fn
] "r" (asi
->insn_fn
)
147 : "lr", "memory", "cc"
150 if (is_writeback(insn
))
151 regs
->uregs
[rn
] = rnv
;
154 static void __kprobes
155 emulate_rd12rn16rm0rs8_rwflags(probes_opcode_t insn
,
156 struct arch_probes_insn
*asi
, struct pt_regs
*regs
)
158 unsigned long pc
= regs
->ARM_pc
+ 4;
159 int rd
= (insn
>> 12) & 0xf;
160 int rn
= (insn
>> 16) & 0xf;
162 int rs
= (insn
>> 8) & 0xf;
164 register unsigned long rdv
asm("r0") = regs
->uregs
[rd
];
165 register unsigned long rnv
asm("r2") = (rn
== 15) ? pc
167 register unsigned long rmv
asm("r3") = (rm
== 15) ? pc
169 register unsigned long rsv
asm("r1") = regs
->uregs
[rs
];
170 unsigned long cpsr
= regs
->ARM_cpsr
;
172 __asm__
__volatile__ (
173 "msr cpsr_fs, %[cpsr] \n\t"
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"
183 alu_write_pc(rdv
, regs
);
185 regs
->uregs
[rd
] = rdv
;
186 regs
->ARM_cpsr
= (regs
->ARM_cpsr
& ~APSR_MASK
) | (cpsr
& APSR_MASK
);
189 static void __kprobes
190 emulate_rd12rn16rm0_rwflags_nopc(probes_opcode_t insn
,
191 struct arch_probes_insn
*asi
, struct pt_regs
*regs
)
193 int rd
= (insn
>> 12) & 0xf;
194 int rn
= (insn
>> 16) & 0xf;
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
;
202 __asm__
__volatile__ (
203 "msr cpsr_fs, %[cpsr] \n\t"
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"
212 regs
->uregs
[rd
] = rdv
;
213 regs
->ARM_cpsr
= (regs
->ARM_cpsr
& ~APSR_MASK
) | (cpsr
& APSR_MASK
);
216 static void __kprobes
217 emulate_rd16rn12rm0rs8_rwflags_nopc(probes_opcode_t insn
,
218 struct arch_probes_insn
*asi
,
219 struct pt_regs
*regs
)
221 int rd
= (insn
>> 16) & 0xf;
222 int rn
= (insn
>> 12) & 0xf;
224 int rs
= (insn
>> 8) & 0xf;
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
;
232 __asm__
__volatile__ (
233 "msr cpsr_fs, %[cpsr] \n\t"
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"
242 regs
->uregs
[rd
] = rdv
;
243 regs
->ARM_cpsr
= (regs
->ARM_cpsr
& ~APSR_MASK
) | (cpsr
& APSR_MASK
);
246 static void __kprobes
247 emulate_rd12rm0_noflags_nopc(probes_opcode_t insn
,
248 struct arch_probes_insn
*asi
, struct pt_regs
*regs
)
250 int rd
= (insn
>> 12) & 0xf;
253 register unsigned long rdv
asm("r0") = regs
->uregs
[rd
];
254 register unsigned long rmv
asm("r3") = regs
->uregs
[rm
];
256 __asm__
__volatile__ (
259 : "0" (rdv
), "r" (rmv
), [fn
] "r" (asi
->insn_fn
)
260 : "lr", "memory", "cc"
263 regs
->uregs
[rd
] = rdv
;
266 static void __kprobes
267 emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(probes_opcode_t insn
,
268 struct arch_probes_insn
*asi
,
269 struct pt_regs
*regs
)
271 int rdlo
= (insn
>> 12) & 0xf;
272 int rdhi
= (insn
>> 16) & 0xf;
274 int rm
= (insn
>> 8) & 0xf;
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
;
282 __asm__
__volatile__ (
283 "msr cpsr_fs, %[cpsr] \n\t"
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"
292 regs
->uregs
[rdlo
] = rdlov
;
293 regs
->uregs
[rdhi
] = rdhiv
;
294 regs
->ARM_cpsr
= (regs
->ARM_cpsr
& ~APSR_MASK
) | (cpsr
& APSR_MASK
);
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
}
336 const struct decode_checker
*kprobes_arm_checkers
[] = {arm_stack_checker
, arm_regs_checker
, NULL
};