// SPDX-License-Identifier: GPL-2.0-only /* * several functions that help interpret ARC instructions * used for unaligned accesses, kprobes and kgdb * * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
*/
/* disasm_instr: Analyses instruction at addr, stores * findings in *state
*/ void __kprobes disasm_instr(unsignedlong addr, struct disasm_state *state, int userspace, struct pt_regs *regs, struct callee_regs *cregs)
{ int fieldA = 0; int fieldC = 0, fieldCisReg = 0;
uint16_t word1 = 0, word0 = 0; int subopcode, is_linked, op_format;
uint16_t *ins_ptr;
uint16_t ins_buf[4]; int bytes_not_copied = 0;
memset(state, 0, sizeof(struct disasm_state));
/* This fetches the upper part of the 32 bit instruction
* in both the cases of Little Endian or Big Endian configurations. */ if (userspace) {
bytes_not_copied = copy_from_user(ins_buf,
(constvoid __user *) addr, 8); if (bytes_not_copied > 6) goto fault;
ins_ptr = ins_buf;
} else {
ins_ptr = (uint16_t *) addr;
}
word1 = *((uint16_t *)addr);
state->major_opcode = (word1 >> 11) & 0x1F;
/* Check if the instruction is 32 bit or 16 bit instruction */ if (state->major_opcode < 0x0B) { if (bytes_not_copied > 4) goto fault;
state->instr_len = 4;
word0 = *((uint16_t *)(addr+2));
state->words[0] = (word1 << 16) | word0;
} else {
state->instr_len = 2;
state->words[0] = word1;
}
/* Read the second word in case of limm */
word1 = *((uint16_t *)(addr + state->instr_len));
word0 = *((uint16_t *)(addr + state->instr_len + 2));
state->words[1] = (word1 << 16) | word0;
switch (state->major_opcode) { case op_Bcc:
state->is_branch = 1;
case 40: /* LPcc */ if (BITS(state->words[0], 22, 23) == 3) { /* Conditional LPcc u7 */
fieldC = FIELD_C(state->words[0]);
fieldC = fieldC << 1;
fieldC += (addr & ~0x03);
state->is_branch = 1;
state->flow = direct_jump;
state->target = fieldC;
} /* For Unconditional lp, next pc is the fall through
* which is updated */ break;
case 10: /* MOV */ /* still need to check for limm to extract instr len */ /* MOV is special case because it only takes 2 args */ switch (BITS(state->words[0], 22, 23)) { case 0: /* OP a,b,c */ if (FIELD_C(state->words[0]) == REG_LIMM)
state->instr_len += 4; break; case 1: /* OP a,b,u6 */ break; case 2: /* OP b,b,s12 */ break; case 3: /* OP.cc b,b,c/u6 */ if ((!IS_BIT(state->words[0], 5)) &&
(FIELD_C(state->words[0]) == REG_LIMM))
state->instr_len += 4; break;
} break;
default: /* Not a Load, Jump or Loop instruction */ /* still need to check for limm to extract instr len */ switch (BITS(state->words[0], 22, 23)) { case 0: /* OP a,b,c */ if ((FIELD_B(state->words[0]) == REG_LIMM) ||
(FIELD_C(state->words[0]) == REG_LIMM))
state->instr_len += 4; break; case 1: /* OP a,b,u6 */ break; case 2: /* OP b,b,s12 */ break; case 3: /* OP.cc b,b,c/u6 */ if ((!IS_BIT(state->words[0], 5)) &&
((FIELD_B(state->words[0]) == REG_LIMM) ||
(FIELD_C(state->words[0]) == REG_LIMM)))
state->instr_len += 4; break;
} break;
} break;
case op_LDB_S: case op_STB_S: /* no further handling required as byte accesses should not
* cause an unaligned access exception */
state->zz = 1; break;
if (bytes_not_copied <= (8 - state->instr_len)) return;
fault: state->fault = 1;
}
long __kprobes get_reg(int reg, struct pt_regs *regs, struct callee_regs *cregs)
{ long *p;
#ifdefined(CONFIG_ISA_ARCOMPACT) if (reg <= 12) {
p = ®s->r0; return p[-reg];
} #else/* CONFIG_ISA_ARCV2 */ if (reg <= 11) {
p = ®s->r0; return p[reg];
}
if (reg == 12) return regs->r12; if (reg == 30) return regs->r30; #ifdef CONFIG_ARC_HAS_ACCL_REGS if (reg == 58) return regs->r58; if (reg == 59) return regs->r59; #endif #endif if (cregs && (reg <= 25)) {
p = &cregs->r13; return p[13 - reg];
}
if (reg == 26) return regs->r26; if (reg == 27) return regs->fp; if (reg == 28) return regs->sp; if (reg == 31) return regs->blink;
return 0;
}
void __kprobes set_reg(int reg, long val, struct pt_regs *regs, struct callee_regs *cregs)
{ long *p;
#ifdefined(CONFIG_ISA_ARCOMPACT) switch (reg) { case 0 ... 12:
p = ®s->r0;
p[-reg] = val; break; case 13 ... 25: if (cregs) {
p = &cregs->r13;
p[13 - reg] = val;
} break; case 26:
regs->r26 = val; break; case 27:
regs->fp = val; break; case 28:
regs->sp = val; break; case 31:
regs->blink = val; break; default: break;
} #else/* CONFIG_ISA_ARCV2 */ switch (reg) { case 0 ... 11:
p = ®s->r0;
p[reg] = val; break; case 12:
regs->r12 = val; break; case 13 ... 25: if (cregs) {
p = &cregs->r13;
p[13 - reg] = val;
} break; case 26:
regs->r26 = val; break; case 27:
regs->fp = val; break; case 28:
regs->sp = val; break; case 30:
regs->r30 = val; break; case 31:
regs->blink = val; break; #ifdef CONFIG_ARC_HAS_ACCL_REGS case 58:
regs->r58 = val; break; case 59:
regs->r59 = val; break; #endif default: break;
} #endif
}
/* * Disassembles the insn at @pc and sets @next_pc to next PC (which could be * @pc +2/4/6 (ARCompact ISA allows free intermixing of 16/32 bit insns). * * If @pc is a branch * -@tgt_if_br is set to branch target. * -If branch has delay slot, @next_pc updated with actual next PC.
*/ int __kprobes disasm_next_pc(unsignedlong pc, struct pt_regs *regs, struct callee_regs *cregs, unsignedlong *next_pc, unsignedlong *tgt_if_br)
{ struct disasm_state instr;
disasm_instr(pc, &instr, 0, regs, cregs);
*next_pc = pc + instr.instr_len;
/* Instruction with possible two targets branch, jump and loop */ if (instr.is_branch)
*tgt_if_br = instr.target;
/* For the instructions with delay slots, the fall through is the * instruction following the instruction in delay slot.
*/ if (instr.delay_slot) { struct disasm_state instr_d;
disasm_instr(*next_pc, &instr_d, 0, regs, cregs);
*next_pc += instr_d.instr_len;
}
/* Zero Overhead Loop - end of the loop */ if (!(regs->status32 & STATUS32_L) && (*next_pc == regs->lp_end)
&& (regs->lp_count > 1)) {
*next_pc = regs->lp_start;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.