162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * arch/arm/probes/decode.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Some contents moved here from arch/arm/include/asm/kprobes-arm.c which is 862306a36Sopenharmony_ci * Copyright (C) 2006, 2007 Motorola Inc. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/types.h> 1362306a36Sopenharmony_ci#include <asm/system_info.h> 1462306a36Sopenharmony_ci#include <asm/ptrace.h> 1562306a36Sopenharmony_ci#include <linux/bug.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "decode.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#ifndef find_str_pc_offset 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* 2362306a36Sopenharmony_ci * For STR and STM instructions, an ARM core may choose to use either 2462306a36Sopenharmony_ci * a +8 or a +12 displacement from the current instruction's address. 2562306a36Sopenharmony_ci * Whichever value is chosen for a given core, it must be the same for 2662306a36Sopenharmony_ci * both instructions and may not change. This function measures it. 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ciint str_pc_offset; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_civoid __init find_str_pc_offset(void) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci int addr, scratch, ret; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci __asm__ ( 3662306a36Sopenharmony_ci "sub %[ret], pc, #4 \n\t" 3762306a36Sopenharmony_ci "str pc, %[addr] \n\t" 3862306a36Sopenharmony_ci "ldr %[scr], %[addr] \n\t" 3962306a36Sopenharmony_ci "sub %[ret], %[scr], %[ret] \n\t" 4062306a36Sopenharmony_ci : [ret] "=r" (ret), [scr] "=r" (scratch), [addr] "+m" (addr)); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci str_pc_offset = ret; 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#endif /* !find_str_pc_offset */ 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#ifndef test_load_write_pc_interworking 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cibool load_write_pc_interworks; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_civoid __init test_load_write_pc_interworking(void) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci int arch = cpu_architecture(); 5562306a36Sopenharmony_ci BUG_ON(arch == CPU_ARCH_UNKNOWN); 5662306a36Sopenharmony_ci load_write_pc_interworks = arch >= CPU_ARCH_ARMv5T; 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci#endif /* !test_load_write_pc_interworking */ 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci#ifndef test_alu_write_pc_interworking 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cibool alu_write_pc_interworks; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_civoid __init test_alu_write_pc_interworking(void) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci int arch = cpu_architecture(); 6962306a36Sopenharmony_ci BUG_ON(arch == CPU_ARCH_UNKNOWN); 7062306a36Sopenharmony_ci alu_write_pc_interworks = arch >= CPU_ARCH_ARMv7; 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci#endif /* !test_alu_write_pc_interworking */ 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_civoid __init arm_probes_decode_init(void) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci find_str_pc_offset(); 7962306a36Sopenharmony_ci test_load_write_pc_interworking(); 8062306a36Sopenharmony_ci test_alu_write_pc_interworking(); 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic unsigned long __kprobes __check_eq(unsigned long cpsr) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci return cpsr & PSR_Z_BIT; 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic unsigned long __kprobes __check_ne(unsigned long cpsr) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci return (~cpsr) & PSR_Z_BIT; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic unsigned long __kprobes __check_cs(unsigned long cpsr) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci return cpsr & PSR_C_BIT; 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic unsigned long __kprobes __check_cc(unsigned long cpsr) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci return (~cpsr) & PSR_C_BIT; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic unsigned long __kprobes __check_mi(unsigned long cpsr) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci return cpsr & PSR_N_BIT; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic unsigned long __kprobes __check_pl(unsigned long cpsr) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci return (~cpsr) & PSR_N_BIT; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic unsigned long __kprobes __check_vs(unsigned long cpsr) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci return cpsr & PSR_V_BIT; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic unsigned long __kprobes __check_vc(unsigned long cpsr) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci return (~cpsr) & PSR_V_BIT; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic unsigned long __kprobes __check_hi(unsigned long cpsr) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */ 12762306a36Sopenharmony_ci return cpsr & PSR_C_BIT; 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic unsigned long __kprobes __check_ls(unsigned long cpsr) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */ 13362306a36Sopenharmony_ci return (~cpsr) & PSR_C_BIT; 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic unsigned long __kprobes __check_ge(unsigned long cpsr) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ 13962306a36Sopenharmony_ci return (~cpsr) & PSR_N_BIT; 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic unsigned long __kprobes __check_lt(unsigned long cpsr) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ 14562306a36Sopenharmony_ci return cpsr & PSR_N_BIT; 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic unsigned long __kprobes __check_gt(unsigned long cpsr) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ 15162306a36Sopenharmony_ci temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */ 15262306a36Sopenharmony_ci return (~temp) & PSR_N_BIT; 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic unsigned long __kprobes __check_le(unsigned long cpsr) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ 15862306a36Sopenharmony_ci temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */ 15962306a36Sopenharmony_ci return temp & PSR_N_BIT; 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic unsigned long __kprobes __check_al(unsigned long cpsr) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci return true; 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ciprobes_check_cc * const probes_condition_checks[16] = { 16862306a36Sopenharmony_ci &__check_eq, &__check_ne, &__check_cs, &__check_cc, 16962306a36Sopenharmony_ci &__check_mi, &__check_pl, &__check_vs, &__check_vc, 17062306a36Sopenharmony_ci &__check_hi, &__check_ls, &__check_ge, &__check_lt, 17162306a36Sopenharmony_ci &__check_gt, &__check_le, &__check_al, &__check_al 17262306a36Sopenharmony_ci}; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_civoid __kprobes probes_simulate_nop(probes_opcode_t opcode, 17662306a36Sopenharmony_ci struct arch_probes_insn *asi, 17762306a36Sopenharmony_ci struct pt_regs *regs) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_civoid __kprobes probes_emulate_none(probes_opcode_t opcode, 18262306a36Sopenharmony_ci struct arch_probes_insn *asi, 18362306a36Sopenharmony_ci struct pt_regs *regs) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci asi->insn_fn(); 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci/* 18962306a36Sopenharmony_ci * Prepare an instruction slot to receive an instruction for emulating. 19062306a36Sopenharmony_ci * This is done by placing a subroutine return after the location where the 19162306a36Sopenharmony_ci * instruction will be placed. We also modify ARM instructions to be 19262306a36Sopenharmony_ci * unconditional as the condition code will already be checked before any 19362306a36Sopenharmony_ci * emulation handler is called. 19462306a36Sopenharmony_ci */ 19562306a36Sopenharmony_cistatic probes_opcode_t __kprobes 19662306a36Sopenharmony_ciprepare_emulated_insn(probes_opcode_t insn, struct arch_probes_insn *asi, 19762306a36Sopenharmony_ci bool thumb) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci#ifdef CONFIG_THUMB2_KERNEL 20062306a36Sopenharmony_ci if (thumb) { 20162306a36Sopenharmony_ci u16 *thumb_insn = (u16 *)asi->insn; 20262306a36Sopenharmony_ci /* Thumb bx lr */ 20362306a36Sopenharmony_ci thumb_insn[1] = __opcode_to_mem_thumb16(0x4770); 20462306a36Sopenharmony_ci thumb_insn[2] = __opcode_to_mem_thumb16(0x4770); 20562306a36Sopenharmony_ci return insn; 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci asi->insn[1] = __opcode_to_mem_arm(0xe12fff1e); /* ARM bx lr */ 20862306a36Sopenharmony_ci#else 20962306a36Sopenharmony_ci asi->insn[1] = __opcode_to_mem_arm(0xe1a0f00e); /* mov pc, lr */ 21062306a36Sopenharmony_ci#endif 21162306a36Sopenharmony_ci /* Make an ARM instruction unconditional */ 21262306a36Sopenharmony_ci if (insn < 0xe0000000) 21362306a36Sopenharmony_ci insn = (insn | 0xe0000000) & ~0x10000000; 21462306a36Sopenharmony_ci return insn; 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci/* 21862306a36Sopenharmony_ci * Write a (probably modified) instruction into the slot previously prepared by 21962306a36Sopenharmony_ci * prepare_emulated_insn 22062306a36Sopenharmony_ci */ 22162306a36Sopenharmony_cistatic void __kprobes 22262306a36Sopenharmony_ciset_emulated_insn(probes_opcode_t insn, struct arch_probes_insn *asi, 22362306a36Sopenharmony_ci bool thumb) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci#ifdef CONFIG_THUMB2_KERNEL 22662306a36Sopenharmony_ci if (thumb) { 22762306a36Sopenharmony_ci u16 *ip = (u16 *)asi->insn; 22862306a36Sopenharmony_ci if (is_wide_instruction(insn)) 22962306a36Sopenharmony_ci *ip++ = __opcode_to_mem_thumb16(insn >> 16); 23062306a36Sopenharmony_ci *ip++ = __opcode_to_mem_thumb16(insn); 23162306a36Sopenharmony_ci return; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci#endif 23462306a36Sopenharmony_ci asi->insn[0] = __opcode_to_mem_arm(insn); 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci/* 23862306a36Sopenharmony_ci * When we modify the register numbers encoded in an instruction to be emulated, 23962306a36Sopenharmony_ci * the new values come from this define. For ARM and 32-bit Thumb instructions 24062306a36Sopenharmony_ci * this gives... 24162306a36Sopenharmony_ci * 24262306a36Sopenharmony_ci * bit position 16 12 8 4 0 24362306a36Sopenharmony_ci * ---------------+---+---+---+---+---+ 24462306a36Sopenharmony_ci * register r2 r0 r1 -- r3 24562306a36Sopenharmony_ci */ 24662306a36Sopenharmony_ci#define INSN_NEW_BITS 0x00020103 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci/* Each nibble has same value as that at INSN_NEW_BITS bit 16 */ 24962306a36Sopenharmony_ci#define INSN_SAMEAS16_BITS 0x22222222 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci/* 25262306a36Sopenharmony_ci * Validate and modify each of the registers encoded in an instruction. 25362306a36Sopenharmony_ci * 25462306a36Sopenharmony_ci * Each nibble in regs contains a value from enum decode_reg_type. For each 25562306a36Sopenharmony_ci * non-zero value, the corresponding nibble in pinsn is validated and modified 25662306a36Sopenharmony_ci * according to the type. 25762306a36Sopenharmony_ci */ 25862306a36Sopenharmony_cistatic bool __kprobes decode_regs(probes_opcode_t *pinsn, u32 regs, bool modify) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci probes_opcode_t insn = *pinsn; 26162306a36Sopenharmony_ci probes_opcode_t mask = 0xf; /* Start at least significant nibble */ 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci for (; regs != 0; regs >>= 4, mask <<= 4) { 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci probes_opcode_t new_bits = INSN_NEW_BITS; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci switch (regs & 0xf) { 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci case REG_TYPE_NONE: 27062306a36Sopenharmony_ci /* Nibble not a register, skip to next */ 27162306a36Sopenharmony_ci continue; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci case REG_TYPE_ANY: 27462306a36Sopenharmony_ci /* Any register is allowed */ 27562306a36Sopenharmony_ci break; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci case REG_TYPE_SAMEAS16: 27862306a36Sopenharmony_ci /* Replace register with same as at bit position 16 */ 27962306a36Sopenharmony_ci new_bits = INSN_SAMEAS16_BITS; 28062306a36Sopenharmony_ci break; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci case REG_TYPE_SP: 28362306a36Sopenharmony_ci /* Only allow SP (R13) */ 28462306a36Sopenharmony_ci if ((insn ^ 0xdddddddd) & mask) 28562306a36Sopenharmony_ci goto reject; 28662306a36Sopenharmony_ci break; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci case REG_TYPE_PC: 28962306a36Sopenharmony_ci /* Only allow PC (R15) */ 29062306a36Sopenharmony_ci if ((insn ^ 0xffffffff) & mask) 29162306a36Sopenharmony_ci goto reject; 29262306a36Sopenharmony_ci break; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci case REG_TYPE_NOSP: 29562306a36Sopenharmony_ci /* Reject SP (R13) */ 29662306a36Sopenharmony_ci if (((insn ^ 0xdddddddd) & mask) == 0) 29762306a36Sopenharmony_ci goto reject; 29862306a36Sopenharmony_ci break; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci case REG_TYPE_NOSPPC: 30162306a36Sopenharmony_ci case REG_TYPE_NOSPPCX: 30262306a36Sopenharmony_ci /* Reject SP and PC (R13 and R15) */ 30362306a36Sopenharmony_ci if (((insn ^ 0xdddddddd) & 0xdddddddd & mask) == 0) 30462306a36Sopenharmony_ci goto reject; 30562306a36Sopenharmony_ci break; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci case REG_TYPE_NOPCWB: 30862306a36Sopenharmony_ci if (!is_writeback(insn)) 30962306a36Sopenharmony_ci break; /* No writeback, so any register is OK */ 31062306a36Sopenharmony_ci fallthrough; 31162306a36Sopenharmony_ci case REG_TYPE_NOPC: 31262306a36Sopenharmony_ci case REG_TYPE_NOPCX: 31362306a36Sopenharmony_ci /* Reject PC (R15) */ 31462306a36Sopenharmony_ci if (((insn ^ 0xffffffff) & mask) == 0) 31562306a36Sopenharmony_ci goto reject; 31662306a36Sopenharmony_ci break; 31762306a36Sopenharmony_ci } 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* Replace value of nibble with new register number... */ 32062306a36Sopenharmony_ci insn &= ~mask; 32162306a36Sopenharmony_ci insn |= new_bits & mask; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci if (modify) 32562306a36Sopenharmony_ci *pinsn = insn; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci return true; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cireject: 33062306a36Sopenharmony_ci return false; 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic const int decode_struct_sizes[NUM_DECODE_TYPES] = { 33462306a36Sopenharmony_ci [DECODE_TYPE_TABLE] = sizeof(struct decode_table), 33562306a36Sopenharmony_ci [DECODE_TYPE_CUSTOM] = sizeof(struct decode_custom), 33662306a36Sopenharmony_ci [DECODE_TYPE_SIMULATE] = sizeof(struct decode_simulate), 33762306a36Sopenharmony_ci [DECODE_TYPE_EMULATE] = sizeof(struct decode_emulate), 33862306a36Sopenharmony_ci [DECODE_TYPE_OR] = sizeof(struct decode_or), 33962306a36Sopenharmony_ci [DECODE_TYPE_REJECT] = sizeof(struct decode_reject) 34062306a36Sopenharmony_ci}; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic int run_checkers(const struct decode_checker *checkers[], 34362306a36Sopenharmony_ci int action, probes_opcode_t insn, 34462306a36Sopenharmony_ci struct arch_probes_insn *asi, 34562306a36Sopenharmony_ci const struct decode_header *h) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci const struct decode_checker **p; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci if (!checkers) 35062306a36Sopenharmony_ci return INSN_GOOD; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci p = checkers; 35362306a36Sopenharmony_ci while (*p != NULL) { 35462306a36Sopenharmony_ci int retval; 35562306a36Sopenharmony_ci probes_check_t *checker_func = (*p)[action].checker; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci retval = INSN_GOOD; 35862306a36Sopenharmony_ci if (checker_func) 35962306a36Sopenharmony_ci retval = checker_func(insn, asi, h); 36062306a36Sopenharmony_ci if (retval == INSN_REJECTED) 36162306a36Sopenharmony_ci return retval; 36262306a36Sopenharmony_ci p++; 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci return INSN_GOOD; 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci/* 36862306a36Sopenharmony_ci * probes_decode_insn operates on data tables in order to decode an ARM 36962306a36Sopenharmony_ci * architecture instruction onto which a kprobe has been placed. 37062306a36Sopenharmony_ci * 37162306a36Sopenharmony_ci * These instruction decoding tables are a concatenation of entries each 37262306a36Sopenharmony_ci * of which consist of one of the following structs: 37362306a36Sopenharmony_ci * 37462306a36Sopenharmony_ci * decode_table 37562306a36Sopenharmony_ci * decode_custom 37662306a36Sopenharmony_ci * decode_simulate 37762306a36Sopenharmony_ci * decode_emulate 37862306a36Sopenharmony_ci * decode_or 37962306a36Sopenharmony_ci * decode_reject 38062306a36Sopenharmony_ci * 38162306a36Sopenharmony_ci * Each of these starts with a struct decode_header which has the following 38262306a36Sopenharmony_ci * fields: 38362306a36Sopenharmony_ci * 38462306a36Sopenharmony_ci * type_regs 38562306a36Sopenharmony_ci * mask 38662306a36Sopenharmony_ci * value 38762306a36Sopenharmony_ci * 38862306a36Sopenharmony_ci * The least significant DECODE_TYPE_BITS of type_regs contains a value 38962306a36Sopenharmony_ci * from enum decode_type, this indicates which of the decode_* structs 39062306a36Sopenharmony_ci * the entry contains. The value DECODE_TYPE_END indicates the end of the 39162306a36Sopenharmony_ci * table. 39262306a36Sopenharmony_ci * 39362306a36Sopenharmony_ci * When the table is parsed, each entry is checked in turn to see if it 39462306a36Sopenharmony_ci * matches the instruction to be decoded using the test: 39562306a36Sopenharmony_ci * 39662306a36Sopenharmony_ci * (insn & mask) == value 39762306a36Sopenharmony_ci * 39862306a36Sopenharmony_ci * If no match is found before the end of the table is reached then decoding 39962306a36Sopenharmony_ci * fails with INSN_REJECTED. 40062306a36Sopenharmony_ci * 40162306a36Sopenharmony_ci * When a match is found, decode_regs() is called to validate and modify each 40262306a36Sopenharmony_ci * of the registers encoded in the instruction; the data it uses to do this 40362306a36Sopenharmony_ci * is (type_regs >> DECODE_TYPE_BITS). A validation failure will cause decoding 40462306a36Sopenharmony_ci * to fail with INSN_REJECTED. 40562306a36Sopenharmony_ci * 40662306a36Sopenharmony_ci * Once the instruction has passed the above tests, further processing 40762306a36Sopenharmony_ci * depends on the type of the table entry's decode struct. 40862306a36Sopenharmony_ci * 40962306a36Sopenharmony_ci */ 41062306a36Sopenharmony_ciint __kprobes 41162306a36Sopenharmony_ciprobes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, 41262306a36Sopenharmony_ci const union decode_item *table, bool thumb, 41362306a36Sopenharmony_ci bool emulate, const union decode_action *actions, 41462306a36Sopenharmony_ci const struct decode_checker *checkers[]) 41562306a36Sopenharmony_ci{ 41662306a36Sopenharmony_ci const struct decode_header *h = (struct decode_header *)table; 41762306a36Sopenharmony_ci const struct decode_header *next; 41862306a36Sopenharmony_ci bool matched = false; 41962306a36Sopenharmony_ci /* 42062306a36Sopenharmony_ci * @insn can be modified by decode_regs. Save its original 42162306a36Sopenharmony_ci * value for checkers. 42262306a36Sopenharmony_ci */ 42362306a36Sopenharmony_ci probes_opcode_t origin_insn = insn; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci /* 42662306a36Sopenharmony_ci * stack_space is initialized to 0 here. Checker functions 42762306a36Sopenharmony_ci * should update is value if they find this is a stack store 42862306a36Sopenharmony_ci * instruction: positive value means bytes of stack usage, 42962306a36Sopenharmony_ci * negitive value means unable to determine stack usage 43062306a36Sopenharmony_ci * statically. For instruction doesn't store to stack, checker 43162306a36Sopenharmony_ci * do nothing with it. 43262306a36Sopenharmony_ci */ 43362306a36Sopenharmony_ci asi->stack_space = 0; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci /* 43662306a36Sopenharmony_ci * Similarly to stack_space, register_usage_flags is filled by 43762306a36Sopenharmony_ci * checkers. Its default value is set to ~0, which is 'all 43862306a36Sopenharmony_ci * registers are used', to prevent any potential optimization. 43962306a36Sopenharmony_ci */ 44062306a36Sopenharmony_ci asi->register_usage_flags = ~0UL; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (emulate) 44362306a36Sopenharmony_ci insn = prepare_emulated_insn(insn, asi, thumb); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci for (;; h = next) { 44662306a36Sopenharmony_ci enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK; 44762306a36Sopenharmony_ci u32 regs = h->type_regs.bits >> DECODE_TYPE_BITS; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci if (type == DECODE_TYPE_END) 45062306a36Sopenharmony_ci return INSN_REJECTED; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci next = (struct decode_header *) 45362306a36Sopenharmony_ci ((uintptr_t)h + decode_struct_sizes[type]); 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci if (!matched && (insn & h->mask.bits) != h->value.bits) 45662306a36Sopenharmony_ci continue; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci if (!decode_regs(&insn, regs, emulate)) 45962306a36Sopenharmony_ci return INSN_REJECTED; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci switch (type) { 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci case DECODE_TYPE_TABLE: { 46462306a36Sopenharmony_ci struct decode_table *d = (struct decode_table *)h; 46562306a36Sopenharmony_ci next = (struct decode_header *)d->table.table; 46662306a36Sopenharmony_ci break; 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci case DECODE_TYPE_CUSTOM: { 47062306a36Sopenharmony_ci int err; 47162306a36Sopenharmony_ci struct decode_custom *d = (struct decode_custom *)h; 47262306a36Sopenharmony_ci int action = d->decoder.action; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci err = run_checkers(checkers, action, origin_insn, asi, h); 47562306a36Sopenharmony_ci if (err == INSN_REJECTED) 47662306a36Sopenharmony_ci return INSN_REJECTED; 47762306a36Sopenharmony_ci return actions[action].decoder(insn, asi, h); 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci case DECODE_TYPE_SIMULATE: { 48162306a36Sopenharmony_ci int err; 48262306a36Sopenharmony_ci struct decode_simulate *d = (struct decode_simulate *)h; 48362306a36Sopenharmony_ci int action = d->handler.action; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci err = run_checkers(checkers, action, origin_insn, asi, h); 48662306a36Sopenharmony_ci if (err == INSN_REJECTED) 48762306a36Sopenharmony_ci return INSN_REJECTED; 48862306a36Sopenharmony_ci asi->insn_handler = actions[action].handler; 48962306a36Sopenharmony_ci return INSN_GOOD_NO_SLOT; 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci case DECODE_TYPE_EMULATE: { 49362306a36Sopenharmony_ci int err; 49462306a36Sopenharmony_ci struct decode_emulate *d = (struct decode_emulate *)h; 49562306a36Sopenharmony_ci int action = d->handler.action; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci err = run_checkers(checkers, action, origin_insn, asi, h); 49862306a36Sopenharmony_ci if (err == INSN_REJECTED) 49962306a36Sopenharmony_ci return INSN_REJECTED; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci if (!emulate) 50262306a36Sopenharmony_ci return actions[action].decoder(insn, asi, h); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci asi->insn_handler = actions[action].handler; 50562306a36Sopenharmony_ci set_emulated_insn(insn, asi, thumb); 50662306a36Sopenharmony_ci return INSN_GOOD; 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci case DECODE_TYPE_OR: 51062306a36Sopenharmony_ci matched = true; 51162306a36Sopenharmony_ci break; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci case DECODE_TYPE_REJECT: 51462306a36Sopenharmony_ci default: 51562306a36Sopenharmony_ci return INSN_REJECTED; 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci} 519