Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/arc/kernel/disasm.c
26439 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* several functions that help interpret ARC instructions
4
* used for unaligned accesses, kprobes and kgdb
5
*
6
* Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
7
*/
8
9
#include <linux/types.h>
10
#include <linux/kprobes.h>
11
#include <linux/slab.h>
12
#include <linux/uaccess.h>
13
#include <asm/disasm.h>
14
15
#if defined(CONFIG_KGDB) || defined(CONFIG_ARC_EMUL_UNALIGNED) || \
16
defined(CONFIG_KPROBES)
17
18
/* disasm_instr: Analyses instruction at addr, stores
19
* findings in *state
20
*/
21
void __kprobes disasm_instr(unsigned long addr, struct disasm_state *state,
22
int userspace, struct pt_regs *regs, struct callee_regs *cregs)
23
{
24
int fieldA = 0;
25
int fieldC = 0, fieldCisReg = 0;
26
uint16_t word1 = 0, word0 = 0;
27
int subopcode, is_linked, op_format;
28
uint16_t *ins_ptr;
29
uint16_t ins_buf[4];
30
int bytes_not_copied = 0;
31
32
memset(state, 0, sizeof(struct disasm_state));
33
34
/* This fetches the upper part of the 32 bit instruction
35
* in both the cases of Little Endian or Big Endian configurations. */
36
if (userspace) {
37
bytes_not_copied = copy_from_user(ins_buf,
38
(const void __user *) addr, 8);
39
if (bytes_not_copied > 6)
40
goto fault;
41
ins_ptr = ins_buf;
42
} else {
43
ins_ptr = (uint16_t *) addr;
44
}
45
46
word1 = *((uint16_t *)addr);
47
48
state->major_opcode = (word1 >> 11) & 0x1F;
49
50
/* Check if the instruction is 32 bit or 16 bit instruction */
51
if (state->major_opcode < 0x0B) {
52
if (bytes_not_copied > 4)
53
goto fault;
54
state->instr_len = 4;
55
word0 = *((uint16_t *)(addr+2));
56
state->words[0] = (word1 << 16) | word0;
57
} else {
58
state->instr_len = 2;
59
state->words[0] = word1;
60
}
61
62
/* Read the second word in case of limm */
63
word1 = *((uint16_t *)(addr + state->instr_len));
64
word0 = *((uint16_t *)(addr + state->instr_len + 2));
65
state->words[1] = (word1 << 16) | word0;
66
67
switch (state->major_opcode) {
68
case op_Bcc:
69
state->is_branch = 1;
70
71
/* unconditional branch s25, conditional branch s21 */
72
fieldA = (IS_BIT(state->words[0], 16)) ?
73
FIELD_s25(state->words[0]) :
74
FIELD_s21(state->words[0]);
75
76
state->delay_slot = IS_BIT(state->words[0], 5);
77
state->target = fieldA + (addr & ~0x3);
78
state->flow = direct_jump;
79
break;
80
81
case op_BLcc:
82
if (IS_BIT(state->words[0], 16)) {
83
/* Branch and Link*/
84
/* unconditional branch s25, conditional branch s21 */
85
fieldA = (IS_BIT(state->words[0], 17)) ?
86
(FIELD_s25(state->words[0]) & ~0x3) :
87
FIELD_s21(state->words[0]);
88
89
state->flow = direct_call;
90
} else {
91
/*Branch On Compare */
92
fieldA = FIELD_s9(state->words[0]) & ~0x3;
93
state->flow = direct_jump;
94
}
95
96
state->delay_slot = IS_BIT(state->words[0], 5);
97
state->target = fieldA + (addr & ~0x3);
98
state->is_branch = 1;
99
break;
100
101
case op_LD: /* LD<zz> a,[b,s9] */
102
state->write = 0;
103
state->di = BITS(state->words[0], 11, 11);
104
if (state->di)
105
break;
106
state->x = BITS(state->words[0], 6, 6);
107
state->zz = BITS(state->words[0], 7, 8);
108
state->aa = BITS(state->words[0], 9, 10);
109
state->wb_reg = FIELD_B(state->words[0]);
110
if (state->wb_reg == REG_LIMM) {
111
state->instr_len += 4;
112
state->aa = 0;
113
state->src1 = state->words[1];
114
} else {
115
state->src1 = get_reg(state->wb_reg, regs, cregs);
116
}
117
state->src2 = FIELD_s9(state->words[0]);
118
state->dest = FIELD_A(state->words[0]);
119
state->pref = (state->dest == REG_LIMM);
120
break;
121
122
case op_ST:
123
state->write = 1;
124
state->di = BITS(state->words[0], 5, 5);
125
if (state->di)
126
break;
127
state->aa = BITS(state->words[0], 3, 4);
128
state->zz = BITS(state->words[0], 1, 2);
129
state->src1 = FIELD_C(state->words[0]);
130
if (state->src1 == REG_LIMM) {
131
state->instr_len += 4;
132
state->src1 = state->words[1];
133
} else {
134
state->src1 = get_reg(state->src1, regs, cregs);
135
}
136
state->wb_reg = FIELD_B(state->words[0]);
137
if (state->wb_reg == REG_LIMM) {
138
state->aa = 0;
139
state->instr_len += 4;
140
state->src2 = state->words[1];
141
} else {
142
state->src2 = get_reg(state->wb_reg, regs, cregs);
143
}
144
state->src3 = FIELD_s9(state->words[0]);
145
break;
146
147
case op_MAJOR_4:
148
subopcode = MINOR_OPCODE(state->words[0]);
149
switch (subopcode) {
150
case 32: /* Jcc */
151
case 33: /* Jcc.D */
152
case 34: /* JLcc */
153
case 35: /* JLcc.D */
154
is_linked = 0;
155
156
if (subopcode == 33 || subopcode == 35)
157
state->delay_slot = 1;
158
159
if (subopcode == 34 || subopcode == 35)
160
is_linked = 1;
161
162
fieldCisReg = 0;
163
op_format = BITS(state->words[0], 22, 23);
164
if (op_format == 0 || ((op_format == 3) &&
165
(!IS_BIT(state->words[0], 5)))) {
166
fieldC = FIELD_C(state->words[0]);
167
168
if (fieldC == REG_LIMM) {
169
fieldC = state->words[1];
170
state->instr_len += 4;
171
} else {
172
fieldCisReg = 1;
173
}
174
} else if (op_format == 1 || ((op_format == 3)
175
&& (IS_BIT(state->words[0], 5)))) {
176
fieldC = FIELD_C(state->words[0]);
177
} else {
178
/* op_format == 2 */
179
fieldC = FIELD_s12(state->words[0]);
180
}
181
182
if (!fieldCisReg) {
183
state->target = fieldC;
184
state->flow = is_linked ?
185
direct_call : direct_jump;
186
} else {
187
state->target = get_reg(fieldC, regs, cregs);
188
state->flow = is_linked ?
189
indirect_call : indirect_jump;
190
}
191
state->is_branch = 1;
192
break;
193
194
case 40: /* LPcc */
195
if (BITS(state->words[0], 22, 23) == 3) {
196
/* Conditional LPcc u7 */
197
fieldC = FIELD_C(state->words[0]);
198
199
fieldC = fieldC << 1;
200
fieldC += (addr & ~0x03);
201
state->is_branch = 1;
202
state->flow = direct_jump;
203
state->target = fieldC;
204
}
205
/* For Unconditional lp, next pc is the fall through
206
* which is updated */
207
break;
208
209
case 48 ... 55: /* LD a,[b,c] */
210
state->di = BITS(state->words[0], 15, 15);
211
if (state->di)
212
break;
213
state->x = BITS(state->words[0], 16, 16);
214
state->zz = BITS(state->words[0], 17, 18);
215
state->aa = BITS(state->words[0], 22, 23);
216
state->wb_reg = FIELD_B(state->words[0]);
217
if (state->wb_reg == REG_LIMM) {
218
state->instr_len += 4;
219
state->src1 = state->words[1];
220
} else {
221
state->src1 = get_reg(state->wb_reg, regs,
222
cregs);
223
}
224
state->src2 = FIELD_C(state->words[0]);
225
if (state->src2 == REG_LIMM) {
226
state->instr_len += 4;
227
state->src2 = state->words[1];
228
} else {
229
state->src2 = get_reg(state->src2, regs,
230
cregs);
231
}
232
state->dest = FIELD_A(state->words[0]);
233
if (state->dest == REG_LIMM)
234
state->pref = 1;
235
break;
236
237
case 10: /* MOV */
238
/* still need to check for limm to extract instr len */
239
/* MOV is special case because it only takes 2 args */
240
switch (BITS(state->words[0], 22, 23)) {
241
case 0: /* OP a,b,c */
242
if (FIELD_C(state->words[0]) == REG_LIMM)
243
state->instr_len += 4;
244
break;
245
case 1: /* OP a,b,u6 */
246
break;
247
case 2: /* OP b,b,s12 */
248
break;
249
case 3: /* OP.cc b,b,c/u6 */
250
if ((!IS_BIT(state->words[0], 5)) &&
251
(FIELD_C(state->words[0]) == REG_LIMM))
252
state->instr_len += 4;
253
break;
254
}
255
break;
256
257
258
default:
259
/* Not a Load, Jump or Loop instruction */
260
/* still need to check for limm to extract instr len */
261
switch (BITS(state->words[0], 22, 23)) {
262
case 0: /* OP a,b,c */
263
if ((FIELD_B(state->words[0]) == REG_LIMM) ||
264
(FIELD_C(state->words[0]) == REG_LIMM))
265
state->instr_len += 4;
266
break;
267
case 1: /* OP a,b,u6 */
268
break;
269
case 2: /* OP b,b,s12 */
270
break;
271
case 3: /* OP.cc b,b,c/u6 */
272
if ((!IS_BIT(state->words[0], 5)) &&
273
((FIELD_B(state->words[0]) == REG_LIMM) ||
274
(FIELD_C(state->words[0]) == REG_LIMM)))
275
state->instr_len += 4;
276
break;
277
}
278
break;
279
}
280
break;
281
282
/* 16 Bit Instructions */
283
case op_LD_ADD: /* LD_S|LDB_S|LDW_S a,[b,c] */
284
state->zz = BITS(state->words[0], 3, 4);
285
state->src1 = get_reg(FIELD_S_B(state->words[0]), regs, cregs);
286
state->src2 = get_reg(FIELD_S_C(state->words[0]), regs, cregs);
287
state->dest = FIELD_S_A(state->words[0]);
288
break;
289
290
case op_ADD_MOV_CMP:
291
/* check for limm, ignore mov_s h,b (== mov_s 0,b) */
292
if ((BITS(state->words[0], 3, 4) < 3) &&
293
(FIELD_S_H(state->words[0]) == REG_LIMM))
294
state->instr_len += 4;
295
break;
296
297
case op_S:
298
subopcode = BITS(state->words[0], 5, 7);
299
switch (subopcode) {
300
case 0: /* j_s */
301
case 1: /* j_s.d */
302
case 2: /* jl_s */
303
case 3: /* jl_s.d */
304
state->target = get_reg(FIELD_S_B(state->words[0]),
305
regs, cregs);
306
state->delay_slot = subopcode & 1;
307
state->flow = (subopcode >= 2) ?
308
direct_call : indirect_jump;
309
break;
310
case 7:
311
switch (BITS(state->words[0], 8, 10)) {
312
case 4: /* jeq_s [blink] */
313
case 5: /* jne_s [blink] */
314
case 6: /* j_s [blink] */
315
case 7: /* j_s.d [blink] */
316
state->delay_slot = (subopcode == 7);
317
state->flow = indirect_jump;
318
state->target = get_reg(31, regs, cregs);
319
default:
320
break;
321
}
322
default:
323
break;
324
}
325
break;
326
327
case op_LD_S: /* LD_S c, [b, u7] */
328
state->src1 = get_reg(FIELD_S_B(state->words[0]), regs, cregs);
329
state->src2 = FIELD_S_u7(state->words[0]);
330
state->dest = FIELD_S_C(state->words[0]);
331
break;
332
333
case op_LDB_S:
334
case op_STB_S:
335
/* no further handling required as byte accesses should not
336
* cause an unaligned access exception */
337
state->zz = 1;
338
break;
339
340
case op_LDWX_S: /* LDWX_S c, [b, u6] */
341
state->x = 1;
342
fallthrough;
343
344
case op_LDW_S: /* LDW_S c, [b, u6] */
345
state->zz = 2;
346
state->src1 = get_reg(FIELD_S_B(state->words[0]), regs, cregs);
347
state->src2 = FIELD_S_u6(state->words[0]);
348
state->dest = FIELD_S_C(state->words[0]);
349
break;
350
351
case op_ST_S: /* ST_S c, [b, u7] */
352
state->write = 1;
353
state->src1 = get_reg(FIELD_S_C(state->words[0]), regs, cregs);
354
state->src2 = get_reg(FIELD_S_B(state->words[0]), regs, cregs);
355
state->src3 = FIELD_S_u7(state->words[0]);
356
break;
357
358
case op_STW_S: /* STW_S c,[b,u6] */
359
state->write = 1;
360
state->zz = 2;
361
state->src1 = get_reg(FIELD_S_C(state->words[0]), regs, cregs);
362
state->src2 = get_reg(FIELD_S_B(state->words[0]), regs, cregs);
363
state->src3 = FIELD_S_u6(state->words[0]);
364
break;
365
366
case op_SP: /* LD_S|LDB_S b,[sp,u7], ST_S|STB_S b,[sp,u7] */
367
/* note: we are ignoring possibility of:
368
* ADD_S, SUB_S, PUSH_S, POP_S as these should not
369
* cause unaligned exception anyway */
370
state->write = BITS(state->words[0], 6, 6);
371
state->zz = BITS(state->words[0], 5, 5);
372
if (state->zz)
373
break; /* byte accesses should not come here */
374
if (!state->write) {
375
state->src1 = get_reg(28, regs, cregs);
376
state->src2 = FIELD_S_u7(state->words[0]);
377
state->dest = FIELD_S_B(state->words[0]);
378
} else {
379
state->src1 = get_reg(FIELD_S_B(state->words[0]), regs,
380
cregs);
381
state->src2 = get_reg(28, regs, cregs);
382
state->src3 = FIELD_S_u7(state->words[0]);
383
}
384
break;
385
386
case op_GP: /* LD_S|LDB_S|LDW_S r0,[gp,s11/s9/s10] */
387
/* note: ADD_S r0, gp, s11 is ignored */
388
state->zz = BITS(state->words[0], 9, 10);
389
state->src1 = get_reg(26, regs, cregs);
390
state->src2 = state->zz ? FIELD_S_s10(state->words[0]) :
391
FIELD_S_s11(state->words[0]);
392
state->dest = 0;
393
break;
394
395
case op_Pcl: /* LD_S b,[pcl,u10] */
396
state->src1 = regs->ret & ~3;
397
state->src2 = FIELD_S_u10(state->words[0]);
398
state->dest = FIELD_S_B(state->words[0]);
399
break;
400
401
case op_BR_S:
402
state->target = FIELD_S_s8(state->words[0]) + (addr & ~0x03);
403
state->flow = direct_jump;
404
state->is_branch = 1;
405
break;
406
407
case op_B_S:
408
fieldA = (BITS(state->words[0], 9, 10) == 3) ?
409
FIELD_S_s7(state->words[0]) :
410
FIELD_S_s10(state->words[0]);
411
state->target = fieldA + (addr & ~0x03);
412
state->flow = direct_jump;
413
state->is_branch = 1;
414
break;
415
416
case op_BL_S:
417
state->target = FIELD_S_s13(state->words[0]) + (addr & ~0x03);
418
state->flow = direct_call;
419
state->is_branch = 1;
420
break;
421
422
default:
423
break;
424
}
425
426
if (bytes_not_copied <= (8 - state->instr_len))
427
return;
428
429
fault: state->fault = 1;
430
}
431
432
long __kprobes get_reg(int reg, struct pt_regs *regs,
433
struct callee_regs *cregs)
434
{
435
long *p;
436
437
#if defined(CONFIG_ISA_ARCOMPACT)
438
if (reg <= 12) {
439
p = &regs->r0;
440
return p[-reg];
441
}
442
#else /* CONFIG_ISA_ARCV2 */
443
if (reg <= 11) {
444
p = &regs->r0;
445
return p[reg];
446
}
447
448
if (reg == 12)
449
return regs->r12;
450
if (reg == 30)
451
return regs->r30;
452
#ifdef CONFIG_ARC_HAS_ACCL_REGS
453
if (reg == 58)
454
return regs->r58;
455
if (reg == 59)
456
return regs->r59;
457
#endif
458
#endif
459
if (cregs && (reg <= 25)) {
460
p = &cregs->r13;
461
return p[13 - reg];
462
}
463
464
if (reg == 26)
465
return regs->r26;
466
if (reg == 27)
467
return regs->fp;
468
if (reg == 28)
469
return regs->sp;
470
if (reg == 31)
471
return regs->blink;
472
473
return 0;
474
}
475
476
void __kprobes set_reg(int reg, long val, struct pt_regs *regs,
477
struct callee_regs *cregs)
478
{
479
long *p;
480
481
#if defined(CONFIG_ISA_ARCOMPACT)
482
switch (reg) {
483
case 0 ... 12:
484
p = &regs->r0;
485
p[-reg] = val;
486
break;
487
case 13 ... 25:
488
if (cregs) {
489
p = &cregs->r13;
490
p[13 - reg] = val;
491
}
492
break;
493
case 26:
494
regs->r26 = val;
495
break;
496
case 27:
497
regs->fp = val;
498
break;
499
case 28:
500
regs->sp = val;
501
break;
502
case 31:
503
regs->blink = val;
504
break;
505
default:
506
break;
507
}
508
#else /* CONFIG_ISA_ARCV2 */
509
switch (reg) {
510
case 0 ... 11:
511
p = &regs->r0;
512
p[reg] = val;
513
break;
514
case 12:
515
regs->r12 = val;
516
break;
517
case 13 ... 25:
518
if (cregs) {
519
p = &cregs->r13;
520
p[13 - reg] = val;
521
}
522
break;
523
case 26:
524
regs->r26 = val;
525
break;
526
case 27:
527
regs->fp = val;
528
break;
529
case 28:
530
regs->sp = val;
531
break;
532
case 30:
533
regs->r30 = val;
534
break;
535
case 31:
536
regs->blink = val;
537
break;
538
#ifdef CONFIG_ARC_HAS_ACCL_REGS
539
case 58:
540
regs->r58 = val;
541
break;
542
case 59:
543
regs->r59 = val;
544
break;
545
#endif
546
default:
547
break;
548
}
549
#endif
550
}
551
552
/*
553
* Disassembles the insn at @pc and sets @next_pc to next PC (which could be
554
* @pc +2/4/6 (ARCompact ISA allows free intermixing of 16/32 bit insns).
555
*
556
* If @pc is a branch
557
* -@tgt_if_br is set to branch target.
558
* -If branch has delay slot, @next_pc updated with actual next PC.
559
*/
560
int __kprobes disasm_next_pc(unsigned long pc, struct pt_regs *regs,
561
struct callee_regs *cregs,
562
unsigned long *next_pc, unsigned long *tgt_if_br)
563
{
564
struct disasm_state instr;
565
566
disasm_instr(pc, &instr, 0, regs, cregs);
567
568
*next_pc = pc + instr.instr_len;
569
570
/* Instruction with possible two targets branch, jump and loop */
571
if (instr.is_branch)
572
*tgt_if_br = instr.target;
573
574
/* For the instructions with delay slots, the fall through is the
575
* instruction following the instruction in delay slot.
576
*/
577
if (instr.delay_slot) {
578
struct disasm_state instr_d;
579
580
disasm_instr(*next_pc, &instr_d, 0, regs, cregs);
581
582
*next_pc += instr_d.instr_len;
583
}
584
585
/* Zero Overhead Loop - end of the loop */
586
if (!(regs->status32 & STATUS32_L) && (*next_pc == regs->lp_end)
587
&& (regs->lp_count > 1)) {
588
*next_pc = regs->lp_start;
589
}
590
591
return instr.is_branch;
592
}
593
594
#endif /* CONFIG_KGDB || CONFIG_ARC_EMUL_UNALIGNED || CONFIG_KPROBES */
595
596