blob: 4e464fed52ec63eb3e1071d602b851234f8dcf89 [file] [log] [blame]
Olivier Deprez157378f2022-04-04 15:47:50 +02001// SPDX-License-Identifier: GPL-2.0+
2
3#include <linux/bitops.h>
4#include <linux/kernel.h>
5#include <linux/kprobes.h>
6
7#include "decode-insn.h"
8#include "simulate-insn.h"
9
10static inline bool csky_insn_reg_get_val(struct pt_regs *regs,
11 unsigned long index,
12 unsigned long *ptr)
13{
14 if (index < 14)
15 *ptr = *(&regs->a0 + index);
16
17 if (index > 15 && index < 31)
18 *ptr = *(&regs->exregs[0] + index - 16);
19
20 switch (index) {
21 case 14:
22 *ptr = regs->usp;
23 break;
24 case 15:
25 *ptr = regs->lr;
26 break;
27 case 31:
28 *ptr = regs->tls;
29 break;
30 default:
31 goto fail;
32 }
33
34 return true;
35fail:
36 return false;
37}
38
39static inline bool csky_insn_reg_set_val(struct pt_regs *regs,
40 unsigned long index,
41 unsigned long val)
42{
43 if (index < 14)
44 *(&regs->a0 + index) = val;
45
46 if (index > 15 && index < 31)
47 *(&regs->exregs[0] + index - 16) = val;
48
49 switch (index) {
50 case 14:
51 regs->usp = val;
52 break;
53 case 15:
54 regs->lr = val;
55 break;
56 case 31:
57 regs->tls = val;
58 break;
59 default:
60 goto fail;
61 }
62
63 return true;
64fail:
65 return false;
66}
67
68void __kprobes
69simulate_br16(u32 opcode, long addr, struct pt_regs *regs)
70{
71 instruction_pointer_set(regs,
72 addr + sign_extend32((opcode & 0x3ff) << 1, 9));
73}
74
75void __kprobes
76simulate_br32(u32 opcode, long addr, struct pt_regs *regs)
77{
78 instruction_pointer_set(regs,
79 addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));
80}
81
82void __kprobes
83simulate_bt16(u32 opcode, long addr, struct pt_regs *regs)
84{
85 if (regs->sr & 1)
86 instruction_pointer_set(regs,
87 addr + sign_extend32((opcode & 0x3ff) << 1, 9));
88 else
89 instruction_pointer_set(regs, addr + 2);
90}
91
92void __kprobes
93simulate_bt32(u32 opcode, long addr, struct pt_regs *regs)
94{
95 if (regs->sr & 1)
96 instruction_pointer_set(regs,
97 addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));
98 else
99 instruction_pointer_set(regs, addr + 4);
100}
101
102void __kprobes
103simulate_bf16(u32 opcode, long addr, struct pt_regs *regs)
104{
105 if (!(regs->sr & 1))
106 instruction_pointer_set(regs,
107 addr + sign_extend32((opcode & 0x3ff) << 1, 9));
108 else
109 instruction_pointer_set(regs, addr + 2);
110}
111
112void __kprobes
113simulate_bf32(u32 opcode, long addr, struct pt_regs *regs)
114{
115 if (!(regs->sr & 1))
116 instruction_pointer_set(regs,
117 addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));
118 else
119 instruction_pointer_set(regs, addr + 4);
120}
121
122void __kprobes
123simulate_jmp16(u32 opcode, long addr, struct pt_regs *regs)
124{
125 unsigned long tmp = (opcode >> 2) & 0xf;
126
127 csky_insn_reg_get_val(regs, tmp, &tmp);
128
129 instruction_pointer_set(regs, tmp & 0xfffffffe);
130}
131
132void __kprobes
133simulate_jmp32(u32 opcode, long addr, struct pt_regs *regs)
134{
135 unsigned long tmp = opcode & 0x1f;
136
137 csky_insn_reg_get_val(regs, tmp, &tmp);
138
139 instruction_pointer_set(regs, tmp & 0xfffffffe);
140}
141
142void __kprobes
143simulate_jsr16(u32 opcode, long addr, struct pt_regs *regs)
144{
145 unsigned long tmp = (opcode >> 2) & 0xf;
146
147 csky_insn_reg_get_val(regs, tmp, &tmp);
148
149 regs->lr = addr + 2;
150
151 instruction_pointer_set(regs, tmp & 0xfffffffe);
152}
153
154void __kprobes
155simulate_jsr32(u32 opcode, long addr, struct pt_regs *regs)
156{
157 unsigned long tmp = opcode & 0x1f;
158
159 csky_insn_reg_get_val(regs, tmp, &tmp);
160
161 regs->lr = addr + 4;
162
163 instruction_pointer_set(regs, tmp & 0xfffffffe);
164}
165
166void __kprobes
167simulate_lrw16(u32 opcode, long addr, struct pt_regs *regs)
168{
169 unsigned long val;
170 unsigned long tmp = (opcode & 0x300) >> 3;
171 unsigned long offset = ((opcode & 0x1f) | tmp) << 2;
172
173 tmp = (opcode & 0xe0) >> 5;
174
175 val = *(unsigned int *)(instruction_pointer(regs) + offset);
176
177 csky_insn_reg_set_val(regs, tmp, val);
178}
179
180void __kprobes
181simulate_lrw32(u32 opcode, long addr, struct pt_regs *regs)
182{
183 unsigned long val;
184 unsigned long offset = (opcode & 0xffff0000) >> 14;
185 unsigned long tmp = opcode & 0x0000001f;
186
187 val = *(unsigned int *)
188 ((instruction_pointer(regs) + offset) & 0xfffffffc);
189
190 csky_insn_reg_set_val(regs, tmp, val);
191}
192
193void __kprobes
194simulate_pop16(u32 opcode, long addr, struct pt_regs *regs)
195{
196 unsigned long *tmp = (unsigned long *)regs->usp;
197 int i;
198
199 for (i = 0; i < (opcode & 0xf); i++) {
200 csky_insn_reg_set_val(regs, i + 4, *tmp);
201 tmp += 1;
202 }
203
204 if (opcode & 0x10) {
205 csky_insn_reg_set_val(regs, 15, *tmp);
206 tmp += 1;
207 }
208
209 regs->usp = (unsigned long)tmp;
210
211 instruction_pointer_set(regs, regs->lr);
212}
213
214void __kprobes
215simulate_pop32(u32 opcode, long addr, struct pt_regs *regs)
216{
217 unsigned long *tmp = (unsigned long *)regs->usp;
218 int i;
219
220 for (i = 0; i < ((opcode & 0xf0000) >> 16); i++) {
221 csky_insn_reg_set_val(regs, i + 4, *tmp);
222 tmp += 1;
223 }
224
225 if (opcode & 0x100000) {
226 csky_insn_reg_set_val(regs, 15, *tmp);
227 tmp += 1;
228 }
229
230 for (i = 0; i < ((opcode & 0xe00000) >> 21); i++) {
231 csky_insn_reg_set_val(regs, i + 16, *tmp);
232 tmp += 1;
233 }
234
235 if (opcode & 0x1000000) {
236 csky_insn_reg_set_val(regs, 29, *tmp);
237 tmp += 1;
238 }
239
240 regs->usp = (unsigned long)tmp;
241
242 instruction_pointer_set(regs, regs->lr);
243}
244
245void __kprobes
246simulate_bez32(u32 opcode, long addr, struct pt_regs *regs)
247{
248 unsigned long tmp = opcode & 0x1f;
249
250 csky_insn_reg_get_val(regs, tmp, &tmp);
251
252 if (tmp == 0) {
253 instruction_pointer_set(regs,
254 addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));
255 } else
256 instruction_pointer_set(regs, addr + 4);
257}
258
259void __kprobes
260simulate_bnez32(u32 opcode, long addr, struct pt_regs *regs)
261{
262 unsigned long tmp = opcode & 0x1f;
263
264 csky_insn_reg_get_val(regs, tmp, &tmp);
265
266 if (tmp != 0) {
267 instruction_pointer_set(regs,
268 addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));
269 } else
270 instruction_pointer_set(regs, addr + 4);
271}
272
273void __kprobes
274simulate_bnezad32(u32 opcode, long addr, struct pt_regs *regs)
275{
276 unsigned long tmp = opcode & 0x1f;
277 unsigned long val;
278
279 csky_insn_reg_get_val(regs, tmp, &val);
280
281 val -= 1;
282
283 if (val > 0) {
284 instruction_pointer_set(regs,
285 addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));
286 } else
287 instruction_pointer_set(regs, addr + 4);
288
289 csky_insn_reg_set_val(regs, tmp, val);
290}
291
292void __kprobes
293simulate_bhsz32(u32 opcode, long addr, struct pt_regs *regs)
294{
295 unsigned long tmp = opcode & 0x1f;
296 unsigned long val;
297
298 csky_insn_reg_get_val(regs, tmp, &val);
299
300 if (val >= 0) {
301 instruction_pointer_set(regs,
302 addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));
303 } else
304 instruction_pointer_set(regs, addr + 4);
305
306 csky_insn_reg_set_val(regs, tmp, val);
307}
308
309void __kprobes
310simulate_bhz32(u32 opcode, long addr, struct pt_regs *regs)
311{
312 unsigned long tmp = opcode & 0x1f;
313 unsigned long val;
314
315 csky_insn_reg_get_val(regs, tmp, &val);
316
317 if (val > 0) {
318 instruction_pointer_set(regs,
319 addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));
320 } else
321 instruction_pointer_set(regs, addr + 4);
322
323 csky_insn_reg_set_val(regs, tmp, val);
324}
325
326void __kprobes
327simulate_blsz32(u32 opcode, long addr, struct pt_regs *regs)
328{
329 unsigned long tmp = opcode & 0x1f;
330 unsigned long val;
331
332 csky_insn_reg_get_val(regs, tmp, &val);
333
334 if (val <= 0) {
335 instruction_pointer_set(regs,
336 addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));
337 } else
338 instruction_pointer_set(regs, addr + 4);
339
340 csky_insn_reg_set_val(regs, tmp, val);
341}
342
343void __kprobes
344simulate_blz32(u32 opcode, long addr, struct pt_regs *regs)
345{
346 unsigned long tmp = opcode & 0x1f;
347 unsigned long val;
348
349 csky_insn_reg_get_val(regs, tmp, &val);
350
351 if (val < 0) {
352 instruction_pointer_set(regs,
353 addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));
354 } else
355 instruction_pointer_set(regs, addr + 4);
356
357 csky_insn_reg_set_val(regs, tmp, val);
358}
359
360void __kprobes
361simulate_bsr32(u32 opcode, long addr, struct pt_regs *regs)
362{
363 unsigned long tmp;
364
365 tmp = (opcode & 0xffff) << 16;
366 tmp |= (opcode & 0xffff0000) >> 16;
367
368 instruction_pointer_set(regs,
369 addr + sign_extend32((tmp & 0x3ffffff) << 1, 15));
370
371 regs->lr = addr + 4;
372}
373
374void __kprobes
375simulate_jmpi32(u32 opcode, long addr, struct pt_regs *regs)
376{
377 unsigned long val;
378 unsigned long offset = ((opcode & 0xffff0000) >> 14);
379
380 val = *(unsigned int *)
381 ((instruction_pointer(regs) + offset) & 0xfffffffc);
382
383 instruction_pointer_set(regs, val);
384}
385
386void __kprobes
387simulate_jsri32(u32 opcode, long addr, struct pt_regs *regs)
388{
389 unsigned long val;
390 unsigned long offset = ((opcode & 0xffff0000) >> 14);
391
392 val = *(unsigned int *)
393 ((instruction_pointer(regs) + offset) & 0xfffffffc);
394
395 regs->lr = addr + 4;
396
397 instruction_pointer_set(regs, val);
398}