1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) 2012 Rabin Vincent <rabin at rab.in> |
4 | */ |
5 | |
6 | #include <linux/kernel.h> |
7 | #include <linux/types.h> |
8 | #include <linux/stddef.h> |
9 | #include <linux/wait.h> |
10 | #include <linux/uprobes.h> |
11 | #include <linux/module.h> |
12 | |
13 | #include "../decode.h" |
14 | #include "../decode-arm.h" |
15 | #include "core.h" |
16 | |
17 | static int uprobes_substitute_pc(unsigned long *pinsn, u32 oregs) |
18 | { |
19 | probes_opcode_t insn = __mem_to_opcode_arm(*pinsn); |
20 | probes_opcode_t temp; |
21 | probes_opcode_t mask; |
22 | int freereg; |
23 | u32 free = 0xffff; |
24 | u32 regs; |
25 | |
26 | for (regs = oregs; regs; regs >>= 4, insn >>= 4) { |
27 | if ((regs & 0xf) == REG_TYPE_NONE) |
28 | continue; |
29 | |
30 | free &= ~(1 << (insn & 0xf)); |
31 | } |
32 | |
33 | /* No PC, no problem */ |
34 | if (free & (1 << 15)) |
35 | return 15; |
36 | |
37 | if (!free) |
38 | return -1; |
39 | |
40 | /* |
41 | * fls instead of ffs ensures that for "ldrd r0, r1, [pc]" we would |
42 | * pick LR instead of R1. |
43 | */ |
44 | freereg = free = fls(x: free) - 1; |
45 | |
46 | temp = __mem_to_opcode_arm(*pinsn); |
47 | insn = temp; |
48 | regs = oregs; |
49 | mask = 0xf; |
50 | |
51 | for (; regs; regs >>= 4, mask <<= 4, free <<= 4, temp >>= 4) { |
52 | if ((regs & 0xf) == REG_TYPE_NONE) |
53 | continue; |
54 | |
55 | if ((temp & 0xf) != 15) |
56 | continue; |
57 | |
58 | insn &= ~mask; |
59 | insn |= free & mask; |
60 | } |
61 | |
62 | *pinsn = __opcode_to_mem_arm(insn); |
63 | return freereg; |
64 | } |
65 | |
66 | static void uprobe_set_pc(struct arch_uprobe *auprobe, |
67 | struct arch_uprobe_task *autask, |
68 | struct pt_regs *regs) |
69 | { |
70 | u32 pcreg = auprobe->pcreg; |
71 | |
72 | autask->backup = regs->uregs[pcreg]; |
73 | regs->uregs[pcreg] = regs->ARM_pc + 8; |
74 | } |
75 | |
76 | static void uprobe_unset_pc(struct arch_uprobe *auprobe, |
77 | struct arch_uprobe_task *autask, |
78 | struct pt_regs *regs) |
79 | { |
80 | /* PC will be taken care of by common code */ |
81 | regs->uregs[auprobe->pcreg] = autask->backup; |
82 | } |
83 | |
84 | static void uprobe_aluwrite_pc(struct arch_uprobe *auprobe, |
85 | struct arch_uprobe_task *autask, |
86 | struct pt_regs *regs) |
87 | { |
88 | u32 pcreg = auprobe->pcreg; |
89 | |
90 | alu_write_pc(pcv: regs->uregs[pcreg], regs); |
91 | regs->uregs[pcreg] = autask->backup; |
92 | } |
93 | |
94 | static void uprobe_write_pc(struct arch_uprobe *auprobe, |
95 | struct arch_uprobe_task *autask, |
96 | struct pt_regs *regs) |
97 | { |
98 | u32 pcreg = auprobe->pcreg; |
99 | |
100 | load_write_pc(pcv: regs->uregs[pcreg], regs); |
101 | regs->uregs[pcreg] = autask->backup; |
102 | } |
103 | |
104 | enum probes_insn |
105 | decode_pc_ro(probes_opcode_t insn, struct arch_probes_insn *asi, |
106 | const struct decode_header *d) |
107 | { |
108 | struct arch_uprobe *auprobe = container_of(asi, struct arch_uprobe, |
109 | asi); |
110 | struct decode_emulate *decode = (struct decode_emulate *) d; |
111 | u32 regs = decode->header.type_regs.bits >> DECODE_TYPE_BITS; |
112 | int reg; |
113 | |
114 | reg = uprobes_substitute_pc(pinsn: &auprobe->ixol[0], oregs: regs); |
115 | if (reg == 15) |
116 | return INSN_GOOD; |
117 | |
118 | if (reg == -1) |
119 | return INSN_REJECTED; |
120 | |
121 | auprobe->pcreg = reg; |
122 | auprobe->prehandler = uprobe_set_pc; |
123 | auprobe->posthandler = uprobe_unset_pc; |
124 | |
125 | return INSN_GOOD; |
126 | } |
127 | |
128 | enum probes_insn |
129 | decode_wb_pc(probes_opcode_t insn, struct arch_probes_insn *asi, |
130 | const struct decode_header *d, bool alu) |
131 | { |
132 | struct arch_uprobe *auprobe = container_of(asi, struct arch_uprobe, |
133 | asi); |
134 | enum probes_insn ret = decode_pc_ro(insn, asi, d); |
135 | |
136 | if (((insn >> 12) & 0xf) == 15) |
137 | auprobe->posthandler = alu ? uprobe_aluwrite_pc |
138 | : uprobe_write_pc; |
139 | |
140 | return ret; |
141 | } |
142 | |
143 | enum probes_insn |
144 | decode_rd12rn16rm0rs8_rwflags(probes_opcode_t insn, |
145 | struct arch_probes_insn *asi, |
146 | const struct decode_header *d) |
147 | { |
148 | return decode_wb_pc(insn, asi, d, true); |
149 | } |
150 | |
151 | enum probes_insn |
152 | decode_ldr(probes_opcode_t insn, struct arch_probes_insn *asi, |
153 | const struct decode_header *d) |
154 | { |
155 | return decode_wb_pc(insn, asi, d, false); |
156 | } |
157 | |
158 | enum probes_insn |
159 | uprobe_decode_ldmstm(probes_opcode_t insn, |
160 | struct arch_probes_insn *asi, |
161 | const struct decode_header *d) |
162 | { |
163 | struct arch_uprobe *auprobe = container_of(asi, struct arch_uprobe, |
164 | asi); |
165 | unsigned reglist = insn & 0xffff; |
166 | int rn = (insn >> 16) & 0xf; |
167 | int lbit = insn & (1 << 20); |
168 | unsigned used = reglist | (1 << rn); |
169 | |
170 | if (rn == 15) |
171 | return INSN_REJECTED; |
172 | |
173 | if (!(used & (1 << 15))) |
174 | return INSN_GOOD; |
175 | |
176 | if (used & (1 << 14)) |
177 | return INSN_REJECTED; |
178 | |
179 | /* Use LR instead of PC */ |
180 | insn ^= 0xc000; |
181 | |
182 | auprobe->pcreg = 14; |
183 | auprobe->ixol[0] = __opcode_to_mem_arm(insn); |
184 | |
185 | auprobe->prehandler = uprobe_set_pc; |
186 | if (lbit) |
187 | auprobe->posthandler = uprobe_write_pc; |
188 | else |
189 | auprobe->posthandler = uprobe_unset_pc; |
190 | |
191 | return INSN_GOOD; |
192 | } |
193 | |
194 | const union decode_action uprobes_probes_actions[] = { |
195 | [PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop}, |
196 | [PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop}, |
197 | [PROBES_BRANCH_IMM] = {.handler = simulate_blx1}, |
198 | [PROBES_MRS] = {.handler = simulate_mrs}, |
199 | [PROBES_BRANCH_REG] = {.handler = simulate_blx2bx}, |
200 | [PROBES_CLZ] = {.handler = probes_simulate_nop}, |
201 | [PROBES_SATURATING_ARITHMETIC] = {.handler = probes_simulate_nop}, |
202 | [PROBES_MUL1] = {.handler = probes_simulate_nop}, |
203 | [PROBES_MUL2] = {.handler = probes_simulate_nop}, |
204 | [PROBES_SWP] = {.handler = probes_simulate_nop}, |
205 | [PROBES_LDRSTRD] = {.decoder = decode_pc_ro}, |
206 | [PROBES_LOAD_EXTRA] = {.decoder = decode_pc_ro}, |
207 | [PROBES_LOAD] = {.decoder = decode_ldr}, |
208 | [PROBES_STORE_EXTRA] = {.decoder = decode_pc_ro}, |
209 | [PROBES_STORE] = {.decoder = decode_pc_ro}, |
210 | [PROBES_MOV_IP_SP] = {.handler = simulate_mov_ipsp}, |
211 | [PROBES_DATA_PROCESSING_REG] = { |
212 | .decoder = decode_rd12rn16rm0rs8_rwflags}, |
213 | [PROBES_DATA_PROCESSING_IMM] = { |
214 | .decoder = decode_rd12rn16rm0rs8_rwflags}, |
215 | [PROBES_MOV_HALFWORD] = {.handler = probes_simulate_nop}, |
216 | [PROBES_SEV] = {.handler = probes_simulate_nop}, |
217 | [PROBES_WFE] = {.handler = probes_simulate_nop}, |
218 | [PROBES_SATURATE] = {.handler = probes_simulate_nop}, |
219 | [PROBES_REV] = {.handler = probes_simulate_nop}, |
220 | [PROBES_MMI] = {.handler = probes_simulate_nop}, |
221 | [PROBES_PACK] = {.handler = probes_simulate_nop}, |
222 | [PROBES_EXTEND] = {.handler = probes_simulate_nop}, |
223 | [PROBES_EXTEND_ADD] = {.handler = probes_simulate_nop}, |
224 | [PROBES_MUL_ADD_LONG] = {.handler = probes_simulate_nop}, |
225 | [PROBES_MUL_ADD] = {.handler = probes_simulate_nop}, |
226 | [PROBES_BITFIELD] = {.handler = probes_simulate_nop}, |
227 | [PROBES_BRANCH] = {.handler = simulate_bbl}, |
228 | [PROBES_LDMSTM] = {.decoder = uprobe_decode_ldmstm} |
229 | }; |
230 | |