1*d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2fca08f32SWang Nan /* 3fca08f32SWang Nan * Copyright (C) 2012 Rabin Vincent <rabin at rab.in> 4fca08f32SWang Nan */ 5fca08f32SWang Nan 6fca08f32SWang Nan #include <linux/kernel.h> 7fca08f32SWang Nan #include <linux/types.h> 8fca08f32SWang Nan #include <linux/stddef.h> 9fca08f32SWang Nan #include <linux/wait.h> 10fca08f32SWang Nan #include <linux/uprobes.h> 11fca08f32SWang Nan #include <linux/module.h> 12fca08f32SWang Nan 13fca08f32SWang Nan #include "../decode.h" 14fca08f32SWang Nan #include "../decode-arm.h" 15fca08f32SWang Nan #include "core.h" 16fca08f32SWang Nan 17fca08f32SWang Nan static int uprobes_substitute_pc(unsigned long *pinsn, u32 oregs) 18fca08f32SWang Nan { 19fca08f32SWang Nan probes_opcode_t insn = __mem_to_opcode_arm(*pinsn); 20fca08f32SWang Nan probes_opcode_t temp; 21fca08f32SWang Nan probes_opcode_t mask; 22fca08f32SWang Nan int freereg; 23fca08f32SWang Nan u32 free = 0xffff; 24fca08f32SWang Nan u32 regs; 25fca08f32SWang Nan 26fca08f32SWang Nan for (regs = oregs; regs; regs >>= 4, insn >>= 4) { 27fca08f32SWang Nan if ((regs & 0xf) == REG_TYPE_NONE) 28fca08f32SWang Nan continue; 29fca08f32SWang Nan 30fca08f32SWang Nan free &= ~(1 << (insn & 0xf)); 31fca08f32SWang Nan } 32fca08f32SWang Nan 33fca08f32SWang Nan /* No PC, no problem */ 34fca08f32SWang Nan if (free & (1 << 15)) 35fca08f32SWang Nan return 15; 36fca08f32SWang Nan 37fca08f32SWang Nan if (!free) 38fca08f32SWang Nan return -1; 39fca08f32SWang Nan 40fca08f32SWang Nan /* 41fca08f32SWang Nan * fls instead of ffs ensures that for "ldrd r0, r1, [pc]" we would 42fca08f32SWang Nan * pick LR instead of R1. 43fca08f32SWang Nan */ 44fca08f32SWang Nan freereg = free = fls(free) - 1; 45fca08f32SWang Nan 46fca08f32SWang Nan temp = __mem_to_opcode_arm(*pinsn); 47fca08f32SWang Nan insn = temp; 48fca08f32SWang Nan regs = oregs; 49fca08f32SWang Nan mask = 0xf; 50fca08f32SWang Nan 51fca08f32SWang Nan for (; regs; regs >>= 4, mask <<= 4, free <<= 4, temp >>= 4) { 52fca08f32SWang Nan if ((regs & 0xf) == REG_TYPE_NONE) 53fca08f32SWang Nan continue; 54fca08f32SWang Nan 55fca08f32SWang Nan if ((temp & 0xf) != 15) 56fca08f32SWang Nan continue; 57fca08f32SWang Nan 58fca08f32SWang Nan insn &= ~mask; 59fca08f32SWang Nan insn |= free & mask; 60fca08f32SWang Nan } 61fca08f32SWang Nan 62fca08f32SWang Nan *pinsn = __opcode_to_mem_arm(insn); 63fca08f32SWang Nan return freereg; 64fca08f32SWang Nan } 65fca08f32SWang Nan 66fca08f32SWang Nan static void uprobe_set_pc(struct arch_uprobe *auprobe, 67fca08f32SWang Nan struct arch_uprobe_task *autask, 68fca08f32SWang Nan struct pt_regs *regs) 69fca08f32SWang Nan { 70fca08f32SWang Nan u32 pcreg = auprobe->pcreg; 71fca08f32SWang Nan 72fca08f32SWang Nan autask->backup = regs->uregs[pcreg]; 73fca08f32SWang Nan regs->uregs[pcreg] = regs->ARM_pc + 8; 74fca08f32SWang Nan } 75fca08f32SWang Nan 76fca08f32SWang Nan static void uprobe_unset_pc(struct arch_uprobe *auprobe, 77fca08f32SWang Nan struct arch_uprobe_task *autask, 78fca08f32SWang Nan struct pt_regs *regs) 79fca08f32SWang Nan { 80fca08f32SWang Nan /* PC will be taken care of by common code */ 81fca08f32SWang Nan regs->uregs[auprobe->pcreg] = autask->backup; 82fca08f32SWang Nan } 83fca08f32SWang Nan 84fca08f32SWang Nan static void uprobe_aluwrite_pc(struct arch_uprobe *auprobe, 85fca08f32SWang Nan struct arch_uprobe_task *autask, 86fca08f32SWang Nan struct pt_regs *regs) 87fca08f32SWang Nan { 88fca08f32SWang Nan u32 pcreg = auprobe->pcreg; 89fca08f32SWang Nan 90fca08f32SWang Nan alu_write_pc(regs->uregs[pcreg], regs); 91fca08f32SWang Nan regs->uregs[pcreg] = autask->backup; 92fca08f32SWang Nan } 93fca08f32SWang Nan 94fca08f32SWang Nan static void uprobe_write_pc(struct arch_uprobe *auprobe, 95fca08f32SWang Nan struct arch_uprobe_task *autask, 96fca08f32SWang Nan struct pt_regs *regs) 97fca08f32SWang Nan { 98fca08f32SWang Nan u32 pcreg = auprobe->pcreg; 99fca08f32SWang Nan 100fca08f32SWang Nan load_write_pc(regs->uregs[pcreg], regs); 101fca08f32SWang Nan regs->uregs[pcreg] = autask->backup; 102fca08f32SWang Nan } 103fca08f32SWang Nan 104fca08f32SWang Nan enum probes_insn 105fca08f32SWang Nan decode_pc_ro(probes_opcode_t insn, struct arch_probes_insn *asi, 106fca08f32SWang Nan const struct decode_header *d) 107fca08f32SWang Nan { 108fca08f32SWang Nan struct arch_uprobe *auprobe = container_of(asi, struct arch_uprobe, 109fca08f32SWang Nan asi); 110fca08f32SWang Nan struct decode_emulate *decode = (struct decode_emulate *) d; 111fca08f32SWang Nan u32 regs = decode->header.type_regs.bits >> DECODE_TYPE_BITS; 112fca08f32SWang Nan int reg; 113fca08f32SWang Nan 114fca08f32SWang Nan reg = uprobes_substitute_pc(&auprobe->ixol[0], regs); 115fca08f32SWang Nan if (reg == 15) 116fca08f32SWang Nan return INSN_GOOD; 117fca08f32SWang Nan 118fca08f32SWang Nan if (reg == -1) 119fca08f32SWang Nan return INSN_REJECTED; 120fca08f32SWang Nan 121fca08f32SWang Nan auprobe->pcreg = reg; 122fca08f32SWang Nan auprobe->prehandler = uprobe_set_pc; 123fca08f32SWang Nan auprobe->posthandler = uprobe_unset_pc; 124fca08f32SWang Nan 125fca08f32SWang Nan return INSN_GOOD; 126fca08f32SWang Nan } 127fca08f32SWang Nan 128fca08f32SWang Nan enum probes_insn 129fca08f32SWang Nan decode_wb_pc(probes_opcode_t insn, struct arch_probes_insn *asi, 130fca08f32SWang Nan const struct decode_header *d, bool alu) 131fca08f32SWang Nan { 132fca08f32SWang Nan struct arch_uprobe *auprobe = container_of(asi, struct arch_uprobe, 133fca08f32SWang Nan asi); 134fca08f32SWang Nan enum probes_insn ret = decode_pc_ro(insn, asi, d); 135fca08f32SWang Nan 136fca08f32SWang Nan if (((insn >> 12) & 0xf) == 15) 137fca08f32SWang Nan auprobe->posthandler = alu ? uprobe_aluwrite_pc 138fca08f32SWang Nan : uprobe_write_pc; 139fca08f32SWang Nan 140fca08f32SWang Nan return ret; 141fca08f32SWang Nan } 142fca08f32SWang Nan 143fca08f32SWang Nan enum probes_insn 144fca08f32SWang Nan decode_rd12rn16rm0rs8_rwflags(probes_opcode_t insn, 145fca08f32SWang Nan struct arch_probes_insn *asi, 146fca08f32SWang Nan const struct decode_header *d) 147fca08f32SWang Nan { 148fca08f32SWang Nan return decode_wb_pc(insn, asi, d, true); 149fca08f32SWang Nan } 150fca08f32SWang Nan 151fca08f32SWang Nan enum probes_insn 152fca08f32SWang Nan decode_ldr(probes_opcode_t insn, struct arch_probes_insn *asi, 153fca08f32SWang Nan const struct decode_header *d) 154fca08f32SWang Nan { 155fca08f32SWang Nan return decode_wb_pc(insn, asi, d, false); 156fca08f32SWang Nan } 157fca08f32SWang Nan 158fca08f32SWang Nan enum probes_insn 159fca08f32SWang Nan uprobe_decode_ldmstm(probes_opcode_t insn, 160fca08f32SWang Nan struct arch_probes_insn *asi, 161fca08f32SWang Nan const struct decode_header *d) 162fca08f32SWang Nan { 163fca08f32SWang Nan struct arch_uprobe *auprobe = container_of(asi, struct arch_uprobe, 164fca08f32SWang Nan asi); 165fca08f32SWang Nan unsigned reglist = insn & 0xffff; 166fca08f32SWang Nan int rn = (insn >> 16) & 0xf; 167fca08f32SWang Nan int lbit = insn & (1 << 20); 168fca08f32SWang Nan unsigned used = reglist | (1 << rn); 169fca08f32SWang Nan 170fca08f32SWang Nan if (rn == 15) 171fca08f32SWang Nan return INSN_REJECTED; 172fca08f32SWang Nan 173fca08f32SWang Nan if (!(used & (1 << 15))) 174fca08f32SWang Nan return INSN_GOOD; 175fca08f32SWang Nan 176fca08f32SWang Nan if (used & (1 << 14)) 177fca08f32SWang Nan return INSN_REJECTED; 178fca08f32SWang Nan 179fca08f32SWang Nan /* Use LR instead of PC */ 180fca08f32SWang Nan insn ^= 0xc000; 181fca08f32SWang Nan 182fca08f32SWang Nan auprobe->pcreg = 14; 183fca08f32SWang Nan auprobe->ixol[0] = __opcode_to_mem_arm(insn); 184fca08f32SWang Nan 185fca08f32SWang Nan auprobe->prehandler = uprobe_set_pc; 186fca08f32SWang Nan if (lbit) 187fca08f32SWang Nan auprobe->posthandler = uprobe_write_pc; 188fca08f32SWang Nan else 189fca08f32SWang Nan auprobe->posthandler = uprobe_unset_pc; 190fca08f32SWang Nan 191fca08f32SWang Nan return INSN_GOOD; 192fca08f32SWang Nan } 193fca08f32SWang Nan 194fca08f32SWang Nan const union decode_action uprobes_probes_actions[] = { 195fca08f32SWang Nan [PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop}, 196fca08f32SWang Nan [PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop}, 197fca08f32SWang Nan [PROBES_BRANCH_IMM] = {.handler = simulate_blx1}, 198fca08f32SWang Nan [PROBES_MRS] = {.handler = simulate_mrs}, 199fca08f32SWang Nan [PROBES_BRANCH_REG] = {.handler = simulate_blx2bx}, 200fca08f32SWang Nan [PROBES_CLZ] = {.handler = probes_simulate_nop}, 201fca08f32SWang Nan [PROBES_SATURATING_ARITHMETIC] = {.handler = probes_simulate_nop}, 202fca08f32SWang Nan [PROBES_MUL1] = {.handler = probes_simulate_nop}, 203fca08f32SWang Nan [PROBES_MUL2] = {.handler = probes_simulate_nop}, 204fca08f32SWang Nan [PROBES_SWP] = {.handler = probes_simulate_nop}, 205fca08f32SWang Nan [PROBES_LDRSTRD] = {.decoder = decode_pc_ro}, 206fca08f32SWang Nan [PROBES_LOAD_EXTRA] = {.decoder = decode_pc_ro}, 207fca08f32SWang Nan [PROBES_LOAD] = {.decoder = decode_ldr}, 208fca08f32SWang Nan [PROBES_STORE_EXTRA] = {.decoder = decode_pc_ro}, 209fca08f32SWang Nan [PROBES_STORE] = {.decoder = decode_pc_ro}, 210fca08f32SWang Nan [PROBES_MOV_IP_SP] = {.handler = simulate_mov_ipsp}, 211fca08f32SWang Nan [PROBES_DATA_PROCESSING_REG] = { 212fca08f32SWang Nan .decoder = decode_rd12rn16rm0rs8_rwflags}, 213fca08f32SWang Nan [PROBES_DATA_PROCESSING_IMM] = { 214fca08f32SWang Nan .decoder = decode_rd12rn16rm0rs8_rwflags}, 215fca08f32SWang Nan [PROBES_MOV_HALFWORD] = {.handler = probes_simulate_nop}, 216fca08f32SWang Nan [PROBES_SEV] = {.handler = probes_simulate_nop}, 217fca08f32SWang Nan [PROBES_WFE] = {.handler = probes_simulate_nop}, 218fca08f32SWang Nan [PROBES_SATURATE] = {.handler = probes_simulate_nop}, 219fca08f32SWang Nan [PROBES_REV] = {.handler = probes_simulate_nop}, 220fca08f32SWang Nan [PROBES_MMI] = {.handler = probes_simulate_nop}, 221fca08f32SWang Nan [PROBES_PACK] = {.handler = probes_simulate_nop}, 222fca08f32SWang Nan [PROBES_EXTEND] = {.handler = probes_simulate_nop}, 223fca08f32SWang Nan [PROBES_EXTEND_ADD] = {.handler = probes_simulate_nop}, 224fca08f32SWang Nan [PROBES_MUL_ADD_LONG] = {.handler = probes_simulate_nop}, 225fca08f32SWang Nan [PROBES_MUL_ADD] = {.handler = probes_simulate_nop}, 226fca08f32SWang Nan [PROBES_BITFIELD] = {.handler = probes_simulate_nop}, 227fca08f32SWang Nan [PROBES_BRANCH] = {.handler = simulate_bbl}, 228fca08f32SWang Nan [PROBES_LDMSTM] = {.decoder = uprobe_decode_ldmstm} 229fca08f32SWang Nan }; 230