1 // SPDX-License-Identifier: GPL-2.0+
3 #include <linux/bitops.h>
4 #include <linux/kernel.h>
5 #include <linux/kprobes.h>
7 #include "decode-insn.h"
8 #include "simulate-insn.h"
10 static inline bool csky_insn_reg_get_val(struct pt_regs
*regs
,
15 *ptr
= *(®s
->a0
+ index
);
17 if (index
> 15 && index
< 31)
18 *ptr
= *(®s
->exregs
[0] + index
- 16);
39 static inline bool csky_insn_reg_set_val(struct pt_regs
*regs
,
44 *(®s
->a0
+ index
) = val
;
46 if (index
> 15 && index
< 31)
47 *(®s
->exregs
[0] + index
- 16) = val
;
69 simulate_br16(u32 opcode
, long addr
, struct pt_regs
*regs
)
71 instruction_pointer_set(regs
,
72 addr
+ sign_extend32((opcode
& 0x3ff) << 1, 9));
76 simulate_br32(u32 opcode
, long addr
, struct pt_regs
*regs
)
78 instruction_pointer_set(regs
,
79 addr
+ sign_extend32((opcode
& 0xffff0000) >> 15, 15));
83 simulate_bt16(u32 opcode
, long addr
, struct pt_regs
*regs
)
86 instruction_pointer_set(regs
,
87 addr
+ sign_extend32((opcode
& 0x3ff) << 1, 9));
89 instruction_pointer_set(regs
, addr
+ 2);
93 simulate_bt32(u32 opcode
, long addr
, struct pt_regs
*regs
)
96 instruction_pointer_set(regs
,
97 addr
+ sign_extend32((opcode
& 0xffff0000) >> 15, 15));
99 instruction_pointer_set(regs
, addr
+ 4);
103 simulate_bf16(u32 opcode
, long addr
, struct pt_regs
*regs
)
106 instruction_pointer_set(regs
,
107 addr
+ sign_extend32((opcode
& 0x3ff) << 1, 9));
109 instruction_pointer_set(regs
, addr
+ 2);
113 simulate_bf32(u32 opcode
, long addr
, struct pt_regs
*regs
)
116 instruction_pointer_set(regs
,
117 addr
+ sign_extend32((opcode
& 0xffff0000) >> 15, 15));
119 instruction_pointer_set(regs
, addr
+ 4);
123 simulate_jmp16(u32 opcode
, long addr
, struct pt_regs
*regs
)
125 unsigned long tmp
= (opcode
>> 2) & 0xf;
127 csky_insn_reg_get_val(regs
, tmp
, &tmp
);
129 instruction_pointer_set(regs
, tmp
& 0xfffffffe);
133 simulate_jmp32(u32 opcode
, long addr
, struct pt_regs
*regs
)
135 unsigned long tmp
= opcode
& 0x1f;
137 csky_insn_reg_get_val(regs
, tmp
, &tmp
);
139 instruction_pointer_set(regs
, tmp
& 0xfffffffe);
143 simulate_jsr16(u32 opcode
, long addr
, struct pt_regs
*regs
)
145 unsigned long tmp
= (opcode
>> 2) & 0xf;
147 csky_insn_reg_get_val(regs
, tmp
, &tmp
);
151 instruction_pointer_set(regs
, tmp
& 0xfffffffe);
155 simulate_jsr32(u32 opcode
, long addr
, struct pt_regs
*regs
)
157 unsigned long tmp
= opcode
& 0x1f;
159 csky_insn_reg_get_val(regs
, tmp
, &tmp
);
163 instruction_pointer_set(regs
, tmp
& 0xfffffffe);
167 simulate_lrw16(u32 opcode
, long addr
, struct pt_regs
*regs
)
170 unsigned long tmp
= (opcode
& 0x300) >> 3;
171 unsigned long offset
= ((opcode
& 0x1f) | tmp
) << 2;
173 tmp
= (opcode
& 0xe0) >> 5;
175 val
= *(unsigned int *)(instruction_pointer(regs
) + offset
);
177 csky_insn_reg_set_val(regs
, tmp
, val
);
181 simulate_lrw32(u32 opcode
, long addr
, struct pt_regs
*regs
)
184 unsigned long offset
= (opcode
& 0xffff0000) >> 14;
185 unsigned long tmp
= opcode
& 0x0000001f;
187 val
= *(unsigned int *)
188 ((instruction_pointer(regs
) + offset
) & 0xfffffffc);
190 csky_insn_reg_set_val(regs
, tmp
, val
);
194 simulate_pop16(u32 opcode
, long addr
, struct pt_regs
*regs
)
196 unsigned long *tmp
= (unsigned long *)regs
->usp
;
199 for (i
= 0; i
< (opcode
& 0xf); i
++) {
200 csky_insn_reg_set_val(regs
, i
+ 4, *tmp
);
205 csky_insn_reg_set_val(regs
, 15, *tmp
);
209 regs
->usp
= (unsigned long)tmp
;
211 instruction_pointer_set(regs
, regs
->lr
);
215 simulate_pop32(u32 opcode
, long addr
, struct pt_regs
*regs
)
217 unsigned long *tmp
= (unsigned long *)regs
->usp
;
220 for (i
= 0; i
< ((opcode
& 0xf0000) >> 16); i
++) {
221 csky_insn_reg_set_val(regs
, i
+ 4, *tmp
);
225 if (opcode
& 0x100000) {
226 csky_insn_reg_set_val(regs
, 15, *tmp
);
230 for (i
= 0; i
< ((opcode
& 0xe00000) >> 21); i
++) {
231 csky_insn_reg_set_val(regs
, i
+ 16, *tmp
);
235 if (opcode
& 0x1000000) {
236 csky_insn_reg_set_val(regs
, 29, *tmp
);
240 regs
->usp
= (unsigned long)tmp
;
242 instruction_pointer_set(regs
, regs
->lr
);
246 simulate_bez32(u32 opcode
, long addr
, struct pt_regs
*regs
)
248 unsigned long tmp
= opcode
& 0x1f;
250 csky_insn_reg_get_val(regs
, tmp
, &tmp
);
253 instruction_pointer_set(regs
,
254 addr
+ sign_extend32((opcode
& 0xffff0000) >> 15, 15));
256 instruction_pointer_set(regs
, addr
+ 4);
260 simulate_bnez32(u32 opcode
, long addr
, struct pt_regs
*regs
)
262 unsigned long tmp
= opcode
& 0x1f;
264 csky_insn_reg_get_val(regs
, tmp
, &tmp
);
267 instruction_pointer_set(regs
,
268 addr
+ sign_extend32((opcode
& 0xffff0000) >> 15, 15));
270 instruction_pointer_set(regs
, addr
+ 4);
274 simulate_bnezad32(u32 opcode
, long addr
, struct pt_regs
*regs
)
276 unsigned long tmp
= opcode
& 0x1f;
279 csky_insn_reg_get_val(regs
, tmp
, (unsigned long *)&val
);
284 instruction_pointer_set(regs
,
285 addr
+ sign_extend32((opcode
& 0xffff0000) >> 15, 15));
287 instruction_pointer_set(regs
, addr
+ 4);
289 csky_insn_reg_set_val(regs
, tmp
, (unsigned long)val
);
293 simulate_bhsz32(u32 opcode
, long addr
, struct pt_regs
*regs
)
295 unsigned long tmp
= opcode
& 0x1f;
298 csky_insn_reg_get_val(regs
, tmp
, &val
);
300 if ((long) val
>= 0) {
301 instruction_pointer_set(regs
,
302 addr
+ sign_extend32((opcode
& 0xffff0000) >> 15, 15));
304 instruction_pointer_set(regs
, addr
+ 4);
308 simulate_bhz32(u32 opcode
, long addr
, struct pt_regs
*regs
)
310 unsigned long tmp
= opcode
& 0x1f;
313 csky_insn_reg_get_val(regs
, tmp
, &val
);
315 if ((long) val
> 0) {
316 instruction_pointer_set(regs
,
317 addr
+ sign_extend32((opcode
& 0xffff0000) >> 15, 15));
319 instruction_pointer_set(regs
, addr
+ 4);
323 simulate_blsz32(u32 opcode
, long addr
, struct pt_regs
*regs
)
325 unsigned long tmp
= opcode
& 0x1f;
328 csky_insn_reg_get_val(regs
, tmp
, &val
);
330 if ((long) val
<= 0) {
331 instruction_pointer_set(regs
,
332 addr
+ sign_extend32((opcode
& 0xffff0000) >> 15, 15));
334 instruction_pointer_set(regs
, addr
+ 4);
338 simulate_blz32(u32 opcode
, long addr
, struct pt_regs
*regs
)
340 unsigned long tmp
= opcode
& 0x1f;
343 csky_insn_reg_get_val(regs
, tmp
, &val
);
345 if ((long) val
< 0) {
346 instruction_pointer_set(regs
,
347 addr
+ sign_extend32((opcode
& 0xffff0000) >> 15, 15));
349 instruction_pointer_set(regs
, addr
+ 4);
353 simulate_bsr32(u32 opcode
, long addr
, struct pt_regs
*regs
)
357 tmp
= (opcode
& 0xffff) << 16;
358 tmp
|= (opcode
& 0xffff0000) >> 16;
360 instruction_pointer_set(regs
,
361 addr
+ sign_extend32((tmp
& 0x3ffffff) << 1, 15));
367 simulate_jmpi32(u32 opcode
, long addr
, struct pt_regs
*regs
)
370 unsigned long offset
= ((opcode
& 0xffff0000) >> 14);
372 val
= *(unsigned int *)
373 ((instruction_pointer(regs
) + offset
) & 0xfffffffc);
375 instruction_pointer_set(regs
, val
);
379 simulate_jsri32(u32 opcode
, long addr
, struct pt_regs
*regs
)
382 unsigned long offset
= ((opcode
& 0xffff0000) >> 14);
384 val
= *(unsigned int *)
385 ((instruction_pointer(regs
) + offset
) & 0xfffffffc);
389 instruction_pointer_set(regs
, val
);