Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/csky/kernel/probes/simulate-insn.c
26489 views
1
// 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
10
static 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;
35
fail:
36
return false;
37
}
38
39
static 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;
64
fail:
65
return false;
66
}
67
68
void __kprobes
69
simulate_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
75
void __kprobes
76
simulate_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
82
void __kprobes
83
simulate_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
92
void __kprobes
93
simulate_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
102
void __kprobes
103
simulate_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
112
void __kprobes
113
simulate_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
122
void __kprobes
123
simulate_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
132
void __kprobes
133
simulate_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
142
void __kprobes
143
simulate_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
154
void __kprobes
155
simulate_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
166
void __kprobes
167
simulate_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
180
void __kprobes
181
simulate_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
193
void __kprobes
194
simulate_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
214
void __kprobes
215
simulate_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
245
void __kprobes
246
simulate_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
259
void __kprobes
260
simulate_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
273
void __kprobes
274
simulate_bnezad32(u32 opcode, long addr, struct pt_regs *regs)
275
{
276
unsigned long tmp = opcode & 0x1f;
277
long val;
278
279
csky_insn_reg_get_val(regs, tmp, (unsigned long *)&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, (unsigned long)val);
290
}
291
292
void __kprobes
293
simulate_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 ((long) 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
307
void __kprobes
308
simulate_bhz32(u32 opcode, long addr, struct pt_regs *regs)
309
{
310
unsigned long tmp = opcode & 0x1f;
311
unsigned long val;
312
313
csky_insn_reg_get_val(regs, tmp, &val);
314
315
if ((long) val > 0) {
316
instruction_pointer_set(regs,
317
addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));
318
} else
319
instruction_pointer_set(regs, addr + 4);
320
}
321
322
void __kprobes
323
simulate_blsz32(u32 opcode, long addr, struct pt_regs *regs)
324
{
325
unsigned long tmp = opcode & 0x1f;
326
unsigned long val;
327
328
csky_insn_reg_get_val(regs, tmp, &val);
329
330
if ((long) val <= 0) {
331
instruction_pointer_set(regs,
332
addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));
333
} else
334
instruction_pointer_set(regs, addr + 4);
335
}
336
337
void __kprobes
338
simulate_blz32(u32 opcode, long addr, struct pt_regs *regs)
339
{
340
unsigned long tmp = opcode & 0x1f;
341
unsigned long val;
342
343
csky_insn_reg_get_val(regs, tmp, &val);
344
345
if ((long) val < 0) {
346
instruction_pointer_set(regs,
347
addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));
348
} else
349
instruction_pointer_set(regs, addr + 4);
350
}
351
352
void __kprobes
353
simulate_bsr32(u32 opcode, long addr, struct pt_regs *regs)
354
{
355
unsigned long tmp;
356
357
tmp = (opcode & 0xffff) << 16;
358
tmp |= (opcode & 0xffff0000) >> 16;
359
360
instruction_pointer_set(regs,
361
addr + sign_extend32((tmp & 0x3ffffff) << 1, 15));
362
363
regs->lr = addr + 4;
364
}
365
366
void __kprobes
367
simulate_jmpi32(u32 opcode, long addr, struct pt_regs *regs)
368
{
369
unsigned long val;
370
unsigned long offset = ((opcode & 0xffff0000) >> 14);
371
372
val = *(unsigned int *)
373
((instruction_pointer(regs) + offset) & 0xfffffffc);
374
375
instruction_pointer_set(regs, val);
376
}
377
378
void __kprobes
379
simulate_jsri32(u32 opcode, long addr, struct pt_regs *regs)
380
{
381
unsigned long val;
382
unsigned long offset = ((opcode & 0xffff0000) >> 14);
383
384
val = *(unsigned int *)
385
((instruction_pointer(regs) + offset) & 0xfffffffc);
386
387
regs->lr = addr + 4;
388
389
instruction_pointer_set(regs, val);
390
}
391
392