18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * arch/arm/probes/kprobes/checkers-arm.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2014 Huawei Inc. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/kernel.h> 98c2ecf20Sopenharmony_ci#include "../decode.h" 108c2ecf20Sopenharmony_ci#include "../decode-arm.h" 118c2ecf20Sopenharmony_ci#include "checkers.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_cistatic enum probes_insn __kprobes arm_check_stack(probes_opcode_t insn, 148c2ecf20Sopenharmony_ci struct arch_probes_insn *asi, 158c2ecf20Sopenharmony_ci const struct decode_header *h) 168c2ecf20Sopenharmony_ci{ 178c2ecf20Sopenharmony_ci /* 188c2ecf20Sopenharmony_ci * PROBES_LDRSTRD, PROBES_LDMSTM, PROBES_STORE, 198c2ecf20Sopenharmony_ci * PROBES_STORE_EXTRA may get here. Simply mark all normal 208c2ecf20Sopenharmony_ci * insns as STACK_USE_NONE. 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_ci static const union decode_item table[] = { 238c2ecf20Sopenharmony_ci /* 248c2ecf20Sopenharmony_ci * 'STR{,D,B,H}, Rt, [Rn, Rm]' should be marked as UNKNOWN 258c2ecf20Sopenharmony_ci * if Rn or Rm is SP. 268c2ecf20Sopenharmony_ci * x 278c2ecf20Sopenharmony_ci * STR (register) cccc 011x x0x0 xxxx xxxx xxxx xxxx xxxx 288c2ecf20Sopenharmony_ci * STRB (register) cccc 011x x1x0 xxxx xxxx xxxx xxxx xxxx 298c2ecf20Sopenharmony_ci */ 308c2ecf20Sopenharmony_ci DECODE_OR (0x0e10000f, 0x0600000d), 318c2ecf20Sopenharmony_ci DECODE_OR (0x0e1f0000, 0x060d0000), 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci /* 348c2ecf20Sopenharmony_ci * x 358c2ecf20Sopenharmony_ci * STRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx 368c2ecf20Sopenharmony_ci * STRH (register) cccc 000x x0x0 xxxx xxxx xxxx 1011 xxxx 378c2ecf20Sopenharmony_ci */ 388c2ecf20Sopenharmony_ci DECODE_OR (0x0e5000bf, 0x000000bd), 398c2ecf20Sopenharmony_ci DECODE_CUSTOM (0x0e5f00b0, 0x000d00b0, STACK_USE_UNKNOWN), 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci /* 428c2ecf20Sopenharmony_ci * For PROBES_LDMSTM, only stmdx sp, [...] need to examine 438c2ecf20Sopenharmony_ci * 448c2ecf20Sopenharmony_ci * Bit B/A (bit 24) encodes arithmetic operation order. 1 means 458c2ecf20Sopenharmony_ci * before, 0 means after. 468c2ecf20Sopenharmony_ci * Bit I/D (bit 23) encodes arithmetic operation. 1 means 478c2ecf20Sopenharmony_ci * increment, 0 means decrement. 488c2ecf20Sopenharmony_ci * 498c2ecf20Sopenharmony_ci * So: 508c2ecf20Sopenharmony_ci * B I 518c2ecf20Sopenharmony_ci * / / 528c2ecf20Sopenharmony_ci * A D | Rn | 538c2ecf20Sopenharmony_ci * STMDX SP, [...] cccc 100x 00x0 xxxx xxxx xxxx xxxx xxxx 548c2ecf20Sopenharmony_ci */ 558c2ecf20Sopenharmony_ci DECODE_CUSTOM (0x0edf0000, 0x080d0000, STACK_USE_STMDX), 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci /* P U W | Rn | Rt | imm12 |*/ 588c2ecf20Sopenharmony_ci /* STR (immediate) cccc 010x x0x0 1101 xxxx xxxx xxxx xxxx */ 598c2ecf20Sopenharmony_ci /* STRB (immediate) cccc 010x x1x0 1101 xxxx xxxx xxxx xxxx */ 608c2ecf20Sopenharmony_ci /* P U W | Rn | Rt |imm4| |imm4|*/ 618c2ecf20Sopenharmony_ci /* STRD (immediate) cccc 000x x1x0 1101 xxxx xxxx 1111 xxxx */ 628c2ecf20Sopenharmony_ci /* STRH (immediate) cccc 000x x1x0 1101 xxxx xxxx 1011 xxxx */ 638c2ecf20Sopenharmony_ci /* 648c2ecf20Sopenharmony_ci * index = (P == '1'); add = (U == '1'). 658c2ecf20Sopenharmony_ci * Above insns with: 668c2ecf20Sopenharmony_ci * index == 0 (str{,d,h} rx, [sp], #+/-imm) or 678c2ecf20Sopenharmony_ci * add == 1 (str{,d,h} rx, [sp, #+<imm>]) 688c2ecf20Sopenharmony_ci * should be STACK_USE_NONE. 698c2ecf20Sopenharmony_ci * Only str{,b,d,h} rx,[sp,#-n] (P == 1 and U == 0) are 708c2ecf20Sopenharmony_ci * required to be examined. 718c2ecf20Sopenharmony_ci */ 728c2ecf20Sopenharmony_ci /* STR{,B} Rt,[SP,#-n] cccc 0101 0xx0 1101 xxxx xxxx xxxx xxxx */ 738c2ecf20Sopenharmony_ci DECODE_CUSTOM (0x0f9f0000, 0x050d0000, STACK_USE_FIXED_XXX), 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci /* STR{D,H} Rt,[SP,#-n] cccc 0001 01x0 1101 xxxx xxxx 1x11 xxxx */ 768c2ecf20Sopenharmony_ci DECODE_CUSTOM (0x0fdf00b0, 0x014d00b0, STACK_USE_FIXED_X0X), 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci /* fall through */ 798c2ecf20Sopenharmony_ci DECODE_CUSTOM (0, 0, STACK_USE_NONE), 808c2ecf20Sopenharmony_ci DECODE_END 818c2ecf20Sopenharmony_ci }; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci return probes_decode_insn(insn, asi, table, false, false, stack_check_actions, NULL); 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ciconst struct decode_checker arm_stack_checker[NUM_PROBES_ARM_ACTIONS] = { 878c2ecf20Sopenharmony_ci [PROBES_LDRSTRD] = {.checker = arm_check_stack}, 888c2ecf20Sopenharmony_ci [PROBES_STORE_EXTRA] = {.checker = arm_check_stack}, 898c2ecf20Sopenharmony_ci [PROBES_STORE] = {.checker = arm_check_stack}, 908c2ecf20Sopenharmony_ci [PROBES_LDMSTM] = {.checker = arm_check_stack}, 918c2ecf20Sopenharmony_ci}; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic enum probes_insn __kprobes arm_check_regs_nouse(probes_opcode_t insn, 948c2ecf20Sopenharmony_ci struct arch_probes_insn *asi, 958c2ecf20Sopenharmony_ci const struct decode_header *h) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci asi->register_usage_flags = 0; 988c2ecf20Sopenharmony_ci return INSN_GOOD; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic enum probes_insn arm_check_regs_normal(probes_opcode_t insn, 1028c2ecf20Sopenharmony_ci struct arch_probes_insn *asi, 1038c2ecf20Sopenharmony_ci const struct decode_header *h) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci u32 regs = h->type_regs.bits >> DECODE_TYPE_BITS; 1068c2ecf20Sopenharmony_ci int i; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci asi->register_usage_flags = 0; 1098c2ecf20Sopenharmony_ci for (i = 0; i < 5; regs >>= 4, insn >>= 4, i++) 1108c2ecf20Sopenharmony_ci if (regs & 0xf) 1118c2ecf20Sopenharmony_ci asi->register_usage_flags |= 1 << (insn & 0xf); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci return INSN_GOOD; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic enum probes_insn arm_check_regs_ldmstm(probes_opcode_t insn, 1188c2ecf20Sopenharmony_ci struct arch_probes_insn *asi, 1198c2ecf20Sopenharmony_ci const struct decode_header *h) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci unsigned int reglist = insn & 0xffff; 1228c2ecf20Sopenharmony_ci unsigned int rn = (insn >> 16) & 0xf; 1238c2ecf20Sopenharmony_ci asi->register_usage_flags = reglist | (1 << rn); 1248c2ecf20Sopenharmony_ci return INSN_GOOD; 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic enum probes_insn arm_check_regs_mov_ip_sp(probes_opcode_t insn, 1288c2ecf20Sopenharmony_ci struct arch_probes_insn *asi, 1298c2ecf20Sopenharmony_ci const struct decode_header *h) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci /* Instruction is 'mov ip, sp' i.e. 'mov r12, r13' */ 1328c2ecf20Sopenharmony_ci asi->register_usage_flags = (1 << 12) | (1<< 13); 1338c2ecf20Sopenharmony_ci return INSN_GOOD; 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci/* 1378c2ecf20Sopenharmony_ci * | Rn |Rt/d| | Rm | 1388c2ecf20Sopenharmony_ci * LDRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1101 xxxx 1398c2ecf20Sopenharmony_ci * STRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx 1408c2ecf20Sopenharmony_ci * | Rn |Rt/d| |imm4L| 1418c2ecf20Sopenharmony_ci * LDRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1101 xxxx 1428c2ecf20Sopenharmony_ci * STRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1111 xxxx 1438c2ecf20Sopenharmony_ci * 1448c2ecf20Sopenharmony_ci * Such instructions access Rt/d and its next register, so different 1458c2ecf20Sopenharmony_ci * from others, a specific checker is required to handle this extra 1468c2ecf20Sopenharmony_ci * implicit register usage. 1478c2ecf20Sopenharmony_ci */ 1488c2ecf20Sopenharmony_cistatic enum probes_insn arm_check_regs_ldrdstrd(probes_opcode_t insn, 1498c2ecf20Sopenharmony_ci struct arch_probes_insn *asi, 1508c2ecf20Sopenharmony_ci const struct decode_header *h) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci int rdt = (insn >> 12) & 0xf; 1538c2ecf20Sopenharmony_ci arm_check_regs_normal(insn, asi, h); 1548c2ecf20Sopenharmony_ci asi->register_usage_flags |= 1 << (rdt + 1); 1558c2ecf20Sopenharmony_ci return INSN_GOOD; 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ciconst struct decode_checker arm_regs_checker[NUM_PROBES_ARM_ACTIONS] = { 1608c2ecf20Sopenharmony_ci [PROBES_MRS] = {.checker = arm_check_regs_normal}, 1618c2ecf20Sopenharmony_ci [PROBES_SATURATING_ARITHMETIC] = {.checker = arm_check_regs_normal}, 1628c2ecf20Sopenharmony_ci [PROBES_MUL1] = {.checker = arm_check_regs_normal}, 1638c2ecf20Sopenharmony_ci [PROBES_MUL2] = {.checker = arm_check_regs_normal}, 1648c2ecf20Sopenharmony_ci [PROBES_MUL_ADD_LONG] = {.checker = arm_check_regs_normal}, 1658c2ecf20Sopenharmony_ci [PROBES_MUL_ADD] = {.checker = arm_check_regs_normal}, 1668c2ecf20Sopenharmony_ci [PROBES_LOAD] = {.checker = arm_check_regs_normal}, 1678c2ecf20Sopenharmony_ci [PROBES_LOAD_EXTRA] = {.checker = arm_check_regs_normal}, 1688c2ecf20Sopenharmony_ci [PROBES_STORE] = {.checker = arm_check_regs_normal}, 1698c2ecf20Sopenharmony_ci [PROBES_STORE_EXTRA] = {.checker = arm_check_regs_normal}, 1708c2ecf20Sopenharmony_ci [PROBES_DATA_PROCESSING_REG] = {.checker = arm_check_regs_normal}, 1718c2ecf20Sopenharmony_ci [PROBES_DATA_PROCESSING_IMM] = {.checker = arm_check_regs_normal}, 1728c2ecf20Sopenharmony_ci [PROBES_SEV] = {.checker = arm_check_regs_nouse}, 1738c2ecf20Sopenharmony_ci [PROBES_WFE] = {.checker = arm_check_regs_nouse}, 1748c2ecf20Sopenharmony_ci [PROBES_SATURATE] = {.checker = arm_check_regs_normal}, 1758c2ecf20Sopenharmony_ci [PROBES_REV] = {.checker = arm_check_regs_normal}, 1768c2ecf20Sopenharmony_ci [PROBES_MMI] = {.checker = arm_check_regs_normal}, 1778c2ecf20Sopenharmony_ci [PROBES_PACK] = {.checker = arm_check_regs_normal}, 1788c2ecf20Sopenharmony_ci [PROBES_EXTEND] = {.checker = arm_check_regs_normal}, 1798c2ecf20Sopenharmony_ci [PROBES_EXTEND_ADD] = {.checker = arm_check_regs_normal}, 1808c2ecf20Sopenharmony_ci [PROBES_BITFIELD] = {.checker = arm_check_regs_normal}, 1818c2ecf20Sopenharmony_ci [PROBES_LDMSTM] = {.checker = arm_check_regs_ldmstm}, 1828c2ecf20Sopenharmony_ci [PROBES_MOV_IP_SP] = {.checker = arm_check_regs_mov_ip_sp}, 1838c2ecf20Sopenharmony_ci [PROBES_LDRSTRD] = {.checker = arm_check_regs_ldrdstrd}, 1848c2ecf20Sopenharmony_ci}; 185