162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * arch/arm/probes/kprobes/checkers-arm.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2014 Huawei Inc. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/kernel.h> 962306a36Sopenharmony_ci#include "../decode.h" 1062306a36Sopenharmony_ci#include "../decode-arm.h" 1162306a36Sopenharmony_ci#include "checkers.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_cistatic enum probes_insn __kprobes arm_check_stack(probes_opcode_t insn, 1462306a36Sopenharmony_ci struct arch_probes_insn *asi, 1562306a36Sopenharmony_ci const struct decode_header *h) 1662306a36Sopenharmony_ci{ 1762306a36Sopenharmony_ci /* 1862306a36Sopenharmony_ci * PROBES_LDRSTRD, PROBES_LDMSTM, PROBES_STORE, 1962306a36Sopenharmony_ci * PROBES_STORE_EXTRA may get here. Simply mark all normal 2062306a36Sopenharmony_ci * insns as STACK_USE_NONE. 2162306a36Sopenharmony_ci */ 2262306a36Sopenharmony_ci static const union decode_item table[] = { 2362306a36Sopenharmony_ci /* 2462306a36Sopenharmony_ci * 'STR{,D,B,H}, Rt, [Rn, Rm]' should be marked as UNKNOWN 2562306a36Sopenharmony_ci * if Rn or Rm is SP. 2662306a36Sopenharmony_ci * x 2762306a36Sopenharmony_ci * STR (register) cccc 011x x0x0 xxxx xxxx xxxx xxxx xxxx 2862306a36Sopenharmony_ci * STRB (register) cccc 011x x1x0 xxxx xxxx xxxx xxxx xxxx 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_ci DECODE_OR (0x0e10000f, 0x0600000d), 3162306a36Sopenharmony_ci DECODE_OR (0x0e1f0000, 0x060d0000), 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci /* 3462306a36Sopenharmony_ci * x 3562306a36Sopenharmony_ci * STRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx 3662306a36Sopenharmony_ci * STRH (register) cccc 000x x0x0 xxxx xxxx xxxx 1011 xxxx 3762306a36Sopenharmony_ci */ 3862306a36Sopenharmony_ci DECODE_OR (0x0e5000bf, 0x000000bd), 3962306a36Sopenharmony_ci DECODE_CUSTOM (0x0e5f00b0, 0x000d00b0, STACK_USE_UNKNOWN), 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci /* 4262306a36Sopenharmony_ci * For PROBES_LDMSTM, only stmdx sp, [...] need to examine 4362306a36Sopenharmony_ci * 4462306a36Sopenharmony_ci * Bit B/A (bit 24) encodes arithmetic operation order. 1 means 4562306a36Sopenharmony_ci * before, 0 means after. 4662306a36Sopenharmony_ci * Bit I/D (bit 23) encodes arithmetic operation. 1 means 4762306a36Sopenharmony_ci * increment, 0 means decrement. 4862306a36Sopenharmony_ci * 4962306a36Sopenharmony_ci * So: 5062306a36Sopenharmony_ci * B I 5162306a36Sopenharmony_ci * / / 5262306a36Sopenharmony_ci * A D | Rn | 5362306a36Sopenharmony_ci * STMDX SP, [...] cccc 100x 00x0 xxxx xxxx xxxx xxxx xxxx 5462306a36Sopenharmony_ci */ 5562306a36Sopenharmony_ci DECODE_CUSTOM (0x0edf0000, 0x080d0000, STACK_USE_STMDX), 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci /* P U W | Rn | Rt | imm12 |*/ 5862306a36Sopenharmony_ci /* STR (immediate) cccc 010x x0x0 1101 xxxx xxxx xxxx xxxx */ 5962306a36Sopenharmony_ci /* STRB (immediate) cccc 010x x1x0 1101 xxxx xxxx xxxx xxxx */ 6062306a36Sopenharmony_ci /* P U W | Rn | Rt |imm4| |imm4|*/ 6162306a36Sopenharmony_ci /* STRD (immediate) cccc 000x x1x0 1101 xxxx xxxx 1111 xxxx */ 6262306a36Sopenharmony_ci /* STRH (immediate) cccc 000x x1x0 1101 xxxx xxxx 1011 xxxx */ 6362306a36Sopenharmony_ci /* 6462306a36Sopenharmony_ci * index = (P == '1'); add = (U == '1'). 6562306a36Sopenharmony_ci * Above insns with: 6662306a36Sopenharmony_ci * index == 0 (str{,d,h} rx, [sp], #+/-imm) or 6762306a36Sopenharmony_ci * add == 1 (str{,d,h} rx, [sp, #+<imm>]) 6862306a36Sopenharmony_ci * should be STACK_USE_NONE. 6962306a36Sopenharmony_ci * Only str{,b,d,h} rx,[sp,#-n] (P == 1 and U == 0) are 7062306a36Sopenharmony_ci * required to be examined. 7162306a36Sopenharmony_ci */ 7262306a36Sopenharmony_ci /* STR{,B} Rt,[SP,#-n] cccc 0101 0xx0 1101 xxxx xxxx xxxx xxxx */ 7362306a36Sopenharmony_ci DECODE_CUSTOM (0x0f9f0000, 0x050d0000, STACK_USE_FIXED_XXX), 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci /* STR{D,H} Rt,[SP,#-n] cccc 0001 01x0 1101 xxxx xxxx 1x11 xxxx */ 7662306a36Sopenharmony_ci DECODE_CUSTOM (0x0fdf00b0, 0x014d00b0, STACK_USE_FIXED_X0X), 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci /* fall through */ 7962306a36Sopenharmony_ci DECODE_CUSTOM (0, 0, STACK_USE_NONE), 8062306a36Sopenharmony_ci DECODE_END 8162306a36Sopenharmony_ci }; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci return probes_decode_insn(insn, asi, table, false, false, stack_check_actions, NULL); 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ciconst struct decode_checker arm_stack_checker[NUM_PROBES_ARM_ACTIONS] = { 8762306a36Sopenharmony_ci [PROBES_LDRSTRD] = {.checker = arm_check_stack}, 8862306a36Sopenharmony_ci [PROBES_STORE_EXTRA] = {.checker = arm_check_stack}, 8962306a36Sopenharmony_ci [PROBES_STORE] = {.checker = arm_check_stack}, 9062306a36Sopenharmony_ci [PROBES_LDMSTM] = {.checker = arm_check_stack}, 9162306a36Sopenharmony_ci}; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic enum probes_insn __kprobes arm_check_regs_nouse(probes_opcode_t insn, 9462306a36Sopenharmony_ci struct arch_probes_insn *asi, 9562306a36Sopenharmony_ci const struct decode_header *h) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci asi->register_usage_flags = 0; 9862306a36Sopenharmony_ci return INSN_GOOD; 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic enum probes_insn arm_check_regs_normal(probes_opcode_t insn, 10262306a36Sopenharmony_ci struct arch_probes_insn *asi, 10362306a36Sopenharmony_ci const struct decode_header *h) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci u32 regs = h->type_regs.bits >> DECODE_TYPE_BITS; 10662306a36Sopenharmony_ci int i; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci asi->register_usage_flags = 0; 10962306a36Sopenharmony_ci for (i = 0; i < 5; regs >>= 4, insn >>= 4, i++) 11062306a36Sopenharmony_ci if (regs & 0xf) 11162306a36Sopenharmony_ci asi->register_usage_flags |= 1 << (insn & 0xf); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci return INSN_GOOD; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic enum probes_insn arm_check_regs_ldmstm(probes_opcode_t insn, 11862306a36Sopenharmony_ci struct arch_probes_insn *asi, 11962306a36Sopenharmony_ci const struct decode_header *h) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci unsigned int reglist = insn & 0xffff; 12262306a36Sopenharmony_ci unsigned int rn = (insn >> 16) & 0xf; 12362306a36Sopenharmony_ci asi->register_usage_flags = reglist | (1 << rn); 12462306a36Sopenharmony_ci return INSN_GOOD; 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic enum probes_insn arm_check_regs_mov_ip_sp(probes_opcode_t insn, 12862306a36Sopenharmony_ci struct arch_probes_insn *asi, 12962306a36Sopenharmony_ci const struct decode_header *h) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci /* Instruction is 'mov ip, sp' i.e. 'mov r12, r13' */ 13262306a36Sopenharmony_ci asi->register_usage_flags = (1 << 12) | (1<< 13); 13362306a36Sopenharmony_ci return INSN_GOOD; 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci/* 13762306a36Sopenharmony_ci * | Rn |Rt/d| | Rm | 13862306a36Sopenharmony_ci * LDRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1101 xxxx 13962306a36Sopenharmony_ci * STRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx 14062306a36Sopenharmony_ci * | Rn |Rt/d| |imm4L| 14162306a36Sopenharmony_ci * LDRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1101 xxxx 14262306a36Sopenharmony_ci * STRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1111 xxxx 14362306a36Sopenharmony_ci * 14462306a36Sopenharmony_ci * Such instructions access Rt/d and its next register, so different 14562306a36Sopenharmony_ci * from others, a specific checker is required to handle this extra 14662306a36Sopenharmony_ci * implicit register usage. 14762306a36Sopenharmony_ci */ 14862306a36Sopenharmony_cistatic enum probes_insn arm_check_regs_ldrdstrd(probes_opcode_t insn, 14962306a36Sopenharmony_ci struct arch_probes_insn *asi, 15062306a36Sopenharmony_ci const struct decode_header *h) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci int rdt = (insn >> 12) & 0xf; 15362306a36Sopenharmony_ci arm_check_regs_normal(insn, asi, h); 15462306a36Sopenharmony_ci asi->register_usage_flags |= 1 << (rdt + 1); 15562306a36Sopenharmony_ci return INSN_GOOD; 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ciconst struct decode_checker arm_regs_checker[NUM_PROBES_ARM_ACTIONS] = { 16062306a36Sopenharmony_ci [PROBES_MRS] = {.checker = arm_check_regs_normal}, 16162306a36Sopenharmony_ci [PROBES_SATURATING_ARITHMETIC] = {.checker = arm_check_regs_normal}, 16262306a36Sopenharmony_ci [PROBES_MUL1] = {.checker = arm_check_regs_normal}, 16362306a36Sopenharmony_ci [PROBES_MUL2] = {.checker = arm_check_regs_normal}, 16462306a36Sopenharmony_ci [PROBES_MUL_ADD_LONG] = {.checker = arm_check_regs_normal}, 16562306a36Sopenharmony_ci [PROBES_MUL_ADD] = {.checker = arm_check_regs_normal}, 16662306a36Sopenharmony_ci [PROBES_LOAD] = {.checker = arm_check_regs_normal}, 16762306a36Sopenharmony_ci [PROBES_LOAD_EXTRA] = {.checker = arm_check_regs_normal}, 16862306a36Sopenharmony_ci [PROBES_STORE] = {.checker = arm_check_regs_normal}, 16962306a36Sopenharmony_ci [PROBES_STORE_EXTRA] = {.checker = arm_check_regs_normal}, 17062306a36Sopenharmony_ci [PROBES_DATA_PROCESSING_REG] = {.checker = arm_check_regs_normal}, 17162306a36Sopenharmony_ci [PROBES_DATA_PROCESSING_IMM] = {.checker = arm_check_regs_normal}, 17262306a36Sopenharmony_ci [PROBES_SEV] = {.checker = arm_check_regs_nouse}, 17362306a36Sopenharmony_ci [PROBES_WFE] = {.checker = arm_check_regs_nouse}, 17462306a36Sopenharmony_ci [PROBES_SATURATE] = {.checker = arm_check_regs_normal}, 17562306a36Sopenharmony_ci [PROBES_REV] = {.checker = arm_check_regs_normal}, 17662306a36Sopenharmony_ci [PROBES_MMI] = {.checker = arm_check_regs_normal}, 17762306a36Sopenharmony_ci [PROBES_PACK] = {.checker = arm_check_regs_normal}, 17862306a36Sopenharmony_ci [PROBES_EXTEND] = {.checker = arm_check_regs_normal}, 17962306a36Sopenharmony_ci [PROBES_EXTEND_ADD] = {.checker = arm_check_regs_normal}, 18062306a36Sopenharmony_ci [PROBES_BITFIELD] = {.checker = arm_check_regs_normal}, 18162306a36Sopenharmony_ci [PROBES_LDMSTM] = {.checker = arm_check_regs_ldmstm}, 18262306a36Sopenharmony_ci [PROBES_MOV_IP_SP] = {.checker = arm_check_regs_mov_ip_sp}, 18362306a36Sopenharmony_ci [PROBES_LDRSTRD] = {.checker = arm_check_regs_ldrdstrd}, 18462306a36Sopenharmony_ci}; 185