1 // SPDX-License-Identifier: GPL-2.0-only 1 2 /* 3 * several functions that help interpret ARC i 4 * used for unaligned accesses, kprobes and kg 5 * 6 * Copyright (C) 2004, 2007-2010, 2011-2012 Sy 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 16 defined(CONFIG_KPROBES) 17 18 /* disasm_instr: Analyses instruction at addr, 19 * findings in *state 20 */ 21 void __kprobes disasm_instr(unsigned long addr 22 int userspace, struct pt_regs *regs, s 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_ 33 34 /* This fetches the upper part of the 35 * in both the cases of Little Endian 36 if (userspace) { 37 bytes_not_copied = copy_from_u 38 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) & 49 50 /* Check if the instruction is 32 bit 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 57 } else { 58 state->instr_len = 2; 59 state->words[0] = word1; 60 } 61 62 /* Read the second word in case of lim 63 word1 = *((uint16_t *)(addr + state->i 64 word0 = *((uint16_t *)(addr + state->i 65 state->words[1] = (word1 << 16) | word 66 67 switch (state->major_opcode) { 68 case op_Bcc: 69 state->is_branch = 1; 70 71 /* unconditional branch s25, c 72 fieldA = (IS_BIT(state->words[ 73 FIELD_s25(state->words 74 FIELD_s21(state->words 75 76 state->delay_slot = IS_BIT(sta 77 state->target = fieldA + (addr 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 branc 85 fieldA = (IS_BIT(state 86 (FIELD_s25(sta 87 FIELD_s21(stat 88 89 state->flow = direct_c 90 } else { 91 /*Branch On Compare */ 92 fieldA = FIELD_s9(stat 93 state->flow = direct_j 94 } 95 96 state->delay_slot = IS_BIT(sta 97 state->target = fieldA + (addr 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[ 104 if (state->di) 105 break; 106 state->x = BITS(state->words[0 107 state->zz = BITS(state->words[ 108 state->aa = BITS(state->words[ 109 state->wb_reg = FIELD_B(state- 110 if (state->wb_reg == REG_LIMM) 111 state->instr_len += 4; 112 state->aa = 0; 113 state->src1 = state->w 114 } else { 115 state->src1 = get_reg( 116 } 117 state->src2 = FIELD_s9(state-> 118 state->dest = FIELD_A(state->w 119 state->pref = (state->dest == 120 break; 121 122 case op_ST: 123 state->write = 1; 124 state->di = BITS(state->words[ 125 if (state->di) 126 break; 127 state->aa = BITS(state->words[ 128 state->zz = BITS(state->words[ 129 state->src1 = FIELD_C(state->w 130 if (state->src1 == REG_LIMM) { 131 state->instr_len += 4; 132 state->src1 = state->w 133 } else { 134 state->src1 = get_reg( 135 } 136 state->wb_reg = FIELD_B(state- 137 if (state->wb_reg == REG_LIMM) 138 state->aa = 0; 139 state->instr_len += 4; 140 state->src2 = state->w 141 } else { 142 state->src2 = get_reg( 143 } 144 state->src3 = FIELD_s9(state-> 145 break; 146 147 case op_MAJOR_4: 148 subopcode = MINOR_OPCODE(state 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 || 157 state->delay_s 158 159 if (subopcode == 34 || 160 is_linked = 1; 161 162 fieldCisReg = 0; 163 op_format = BITS(state 164 if (op_format == 0 || 165 (!IS_BIT(state 166 fieldC = FIELD 167 168 if (fieldC == 169 fieldC 170 state- 171 } else { 172 fieldC 173 } 174 } else if (op_format = 175 && (IS_BIT(sta 176 fieldC = FIELD 177 } else { 178 /* op_format = 179 fieldC = FIELD 180 } 181 182 if (!fieldCisReg) { 183 state->target 184 state->flow = 185 direct 186 } else { 187 state->target 188 state->flow = 189 indire 190 } 191 state->is_branch = 1; 192 break; 193 194 case 40: /* LPcc */ 195 if (BITS(state->words[ 196 /* Conditional 197 fieldC = FIELD 198 199 fieldC = field 200 fieldC += (add 201 state->is_bran 202 state->flow = 203 state->target 204 } 205 /* For Unconditional l 206 * which is updated */ 207 break; 208 209 case 48 ... 55: /* LD a,[b,c] 210 state->di = BITS(state 211 if (state->di) 212 break; 213 state->x = BITS(state- 214 state->zz = BITS(state 215 state->aa = BITS(state 216 state->wb_reg = FIELD_ 217 if (state->wb_reg == R 218 state->instr_l 219 state->src1 = 220 } else { 221 state->src1 = 222 223 } 224 state->src2 = FIELD_C( 225 if (state->src2 == REG 226 state->instr_l 227 state->src2 = 228 } else { 229 state->src2 = 230 cregs) 231 } 232 state->dest = FIELD_A( 233 if (state->dest == REG 234 state->pref = 235 break; 236 237 case 10: /* MOV */ 238 /* still need to check 239 /* MOV is special case 240 switch (BITS(state->wo 241 case 0: /* OP a,b,c */ 242 if (FIELD_C(st 243 state- 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 250 if ((!IS_BIT(s 251 (FIELD_C(s 252 state- 253 break; 254 } 255 break; 256 257 258 default: 259 /* Not a Load, Jump or 260 /* still need to check 261 switch (BITS(state->wo 262 case 0: /* OP a,b,c */ 263 if ((FIELD_B(s 264 (FIELD_C(s 265 state- 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 272 if ((!IS_BIT(s 273 ((FIELD_B(s 274 (FIELD_C(s 275 state- 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, 284 state->zz = BITS(state->words[ 285 state->src1 = get_reg(FIELD_S_ 286 state->src2 = get_reg(FIELD_S_ 287 state->dest = FIELD_S_A(state- 288 break; 289 290 case op_ADD_MOV_CMP: 291 /* check for limm, ignore mov_ 292 if ((BITS(state->words[0], 3, 293 (FIELD_S_H(state->words[0] 294 state->instr_len += 4; 295 break; 296 297 case op_S: 298 subopcode = BITS(state->words[ 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_re 305 306 state->delay_slot = su 307 state->flow = (subopco 308 direct_call : 309 break; 310 case 7: 311 switch (BITS(state->wo 312 case 4: /* jeq_s [blin 313 case 5: /* jne_s [blin 314 case 6: /* j_s [blink] 315 case 7: /* j_s.d [blin 316 state->delay_s 317 state->flow = 318 state->target 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_ 329 state->src2 = FIELD_S_u7(state 330 state->dest = FIELD_S_C(state- 331 break; 332 333 case op_LDB_S: 334 case op_STB_S: 335 /* no further handling require 336 * cause an unaligned access e 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_ 347 state->src2 = FIELD_S_u6(state 348 state->dest = FIELD_S_C(state- 349 break; 350 351 case op_ST_S: /* ST_S c, [b, u7] */ 352 state->write = 1; 353 state->src1 = get_reg(FIELD_S_ 354 state->src2 = get_reg(FIELD_S_ 355 state->src3 = FIELD_S_u7(state 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_ 362 state->src2 = get_reg(FIELD_S_ 363 state->src3 = FIELD_S_u6(state 364 break; 365 366 case op_SP: /* LD_S|LDB_S b,[sp,u7 367 /* note: we are ignoring possi 368 * ADD_S, SUB_S, PUSH_S, POP_S 369 * cause unaligned exception a 370 state->write = BITS(state->wor 371 state->zz = BITS(state->words[ 372 if (state->zz) 373 break; /* byte access 374 if (!state->write) { 375 state->src1 = get_reg( 376 state->src2 = FIELD_S_ 377 state->dest = FIELD_S_ 378 } else { 379 state->src1 = get_reg( 380 cregs) 381 state->src2 = get_reg( 382 state->src3 = FIELD_S_ 383 } 384 break; 385 386 case op_GP: /* LD_S|LDB_S|LDW_S r0 387 /* note: ADD_S r0, gp, s11 is 388 state->zz = BITS(state->words[ 389 state->src1 = get_reg(26, regs 390 state->src2 = state->zz ? FIEL 391 FIELD_S_s11(state->wor 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(stat 398 state->dest = FIELD_S_B(state- 399 break; 400 401 case op_BR_S: 402 state->target = FIELD_S_s8(sta 403 state->flow = direct_jump; 404 state->is_branch = 1; 405 break; 406 407 case op_B_S: 408 fieldA = (BITS(state->words[0] 409 FIELD_S_s7(state->word 410 FIELD_S_s10(state->wor 411 state->target = fieldA + (addr 412 state->flow = direct_jump; 413 state->is_branch = 1; 414 break; 415 416 case op_BL_S: 417 state->target = FIELD_S_s13(st 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->in 427 return; 428 429 fault: state->fault = 1; 430 } 431 432 long __kprobes get_reg(int reg, struct pt_regs 433 struct callee_regs *cre 434 { 435 long *p; 436 437 #if defined(CONFIG_ISA_ARCOMPACT) 438 if (reg <= 12) { 439 p = ®s->r0; 440 return p[-reg]; 441 } 442 #else /* CONFIG_ISA_ARCV2 */ 443 if (reg <= 11) { 444 p = ®s->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, stru 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 = ®s->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 = ®s->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 554 * @pc +2/4/6 (ARCompact ISA allows free inter 555 * 556 * If @pc is a branch 557 * -@tgt_if_br is set to branch target. 558 * -If branch has delay slot, @next_pc up 559 */ 560 int __kprobes disasm_next_pc(unsigned long pc, 561 struct callee_reg 562 unsigned long *ne 563 { 564 struct disasm_state instr; 565 566 disasm_instr(pc, &instr, 0, regs, creg 567 568 *next_pc = pc + instr.instr_len; 569 570 /* Instruction with possible two targe 571 if (instr.is_branch) 572 *tgt_if_br = instr.target; 573 574 /* For the instructions with delay slo 575 * instruction following the instructi 576 */ 577 if (instr.delay_slot) { 578 struct disasm_state instr_d; 579 580 disasm_instr(*next_pc, &instr_ 581 582 *next_pc += instr_d.instr_len; 583 } 584 585 /* Zero Overhead Loop - end of the lo 586 if (!(regs->status32 & STATUS32_L) && 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_UNALI 595
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.