1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * arch/arm/probes/kprobes/actions-arm.c 4 * 5 * Copyright (C) 2006, 2007 Motorola Inc. 6 */ 7 8 /* 9 * We do not have hardware single-stepping on ARM, This 10 * effort is further complicated by the ARM not having a 11 * "next PC" register. Instructions that change the PC 12 * can't be safely single-stepped in a MP environment, so 13 * we have a lot of work to do: 14 * 15 * In the prepare phase: 16 * *) If it is an instruction that does anything 17 * with the CPU mode, we reject it for a kprobe. 18 * (This is out of laziness rather than need. The 19 * instructions could be simulated.) 20 * 21 * *) Otherwise, decode the instruction rewriting its 22 * registers to take fixed, ordered registers and 23 * setting a handler for it to run the instruction. 24 * 25 * In the execution phase by an instruction's handler: 26 * 27 * *) If the PC is written to by the instruction, the 28 * instruction must be fully simulated in software. 29 * 30 * *) Otherwise, a modified form of the instruction is 31 * directly executed. Its handler calls the 32 * instruction in insn[0]. In insn[1] is a 33 * "mov pc, lr" to return. 34 * 35 * Before calling, load up the reordered registers 36 * from the original instruction's registers. If one 37 * of the original input registers is the PC, compute 38 * and adjust the appropriate input register. 39 * 40 * After call completes, copy the output registers to 41 * the original instruction's original registers. 42 * 43 * We don't use a real breakpoint instruction since that 44 * would have us in the kernel go from SVC mode to SVC 45 * mode losing the link register. Instead we use an 46 * undefined instruction. To simplify processing, the 47 * undefined instruction used for kprobes must be reserved 48 * exclusively for kprobes use. 49 * 50 * TODO: ifdef out some instruction decoding based on architecture. 51 */ 52 53 #include <linux/kernel.h> 54 #include <linux/kprobes.h> 55 #include <linux/ptrace.h> 56 57 #include "../decode-arm.h" 58 #include "core.h" 59 #include "checkers.h" 60 61 #if __LINUX_ARM_ARCH__ >= 6 62 #define BLX(reg) "blx "reg" \n\t" 63 #else 64 #define BLX(reg) "mov lr, pc \n\t" \ 65 "mov pc, "reg" \n\t" 66 #endif 67 68 static void __kprobes 69 emulate_ldrdstrd(probes_opcode_t insn, 70 struct arch_probes_insn *asi, struct pt_regs *regs) 71 { 72 unsigned long pc = regs->ARM_pc + 4; 73 int rt = (insn >> 12) & 0xf; 74 int rn = (insn >> 16) & 0xf; 75 int rm = insn & 0xf; 76 77 register unsigned long rtv asm("r0") = regs->uregs[rt]; 78 register unsigned long rt2v asm("r1") = regs->uregs[rt+1]; 79 register unsigned long rnv asm("r2") = (rn == 15) ? pc 80 : regs->uregs[rn]; 81 register unsigned long rmv asm("r3") = regs->uregs[rm]; 82 83 __asm__ __volatile__ ( 84 BLX("%[fn]") 85 : "=r" (rtv), "=r" (rt2v), "=r" (rnv) 86 : "" (rtv), "1" (rt2v), "2" (rnv), "r" (rmv), 87 [fn] "r" (asi->insn_fn) 88 : "lr", "memory", "cc" 89 ); 90 91 regs->uregs[rt] = rtv; 92 regs->uregs[rt+1] = rt2v; 93 if (is_writeback(insn)) 94 regs->uregs[rn] = rnv; 95 } 96 97 static void __kprobes 98 emulate_ldr(probes_opcode_t insn, 99 struct arch_probes_insn *asi, struct pt_regs *regs) 100 { 101 unsigned long pc = regs->ARM_pc + 4; 102 int rt = (insn >> 12) & 0xf; 103 int rn = (insn >> 16) & 0xf; 104 int rm = insn & 0xf; 105 106 register unsigned long rtv asm("r0"); 107 register unsigned long rnv asm("r2") = (rn == 15) ? pc 108 : regs->uregs[rn]; 109 register unsigned long rmv asm("r3") = regs->uregs[rm]; 110 111 __asm__ __volatile__ ( 112 BLX("%[fn]") 113 : "=r" (rtv), "=r" (rnv) 114 : "1" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn) 115 : "lr", "memory", "cc" 116 ); 117 118 if (rt == 15) 119 load_write_pc(rtv, regs); 120 else 121 regs->uregs[rt] = rtv; 122 123 if (is_writeback(insn)) 124 regs->uregs[rn] = rnv; 125 } 126 127 static void __kprobes 128 emulate_str(probes_opcode_t insn, 129 struct arch_probes_insn *asi, struct pt_regs *regs) 130 { 131 unsigned long rtpc = regs->ARM_pc - 4 + str_pc_offset; 132 unsigned long rnpc = regs->ARM_pc + 4; 133 int rt = (insn >> 12) & 0xf; 134 int rn = (insn >> 16) & 0xf; 135 int rm = insn & 0xf; 136 137 register unsigned long rtv asm("r0") = (rt == 15) ? rtpc 138 : regs->uregs[rt]; 139 register unsigned long rnv asm("r2") = (rn == 15) ? rnpc 140 : regs->uregs[rn]; 141 register unsigned long rmv asm("r3") = regs->uregs[rm]; 142 143 __asm__ __volatile__ ( 144 BLX("%[fn]") 145 : "=r" (rnv) 146 : "r" (rtv), "" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn) 147 : "lr", "memory", "cc" 148 ); 149 150 if (is_writeback(insn)) 151 regs->uregs[rn] = rnv; 152 } 153 154 static void __kprobes 155 emulate_rd12rn16rm0rs8_rwflags(probes_opcode_t insn, 156 struct arch_probes_insn *asi, struct pt_regs *regs) 157 { 158 unsigned long pc = regs->ARM_pc + 4; 159 int rd = (insn >> 12) & 0xf; 160 int rn = (insn >> 16) & 0xf; 161 int rm = insn & 0xf; 162 int rs = (insn >> 8) & 0xf; 163 164 register unsigned long rdv asm("r0") = regs->uregs[rd]; 165 register unsigned long rnv asm("r2") = (rn == 15) ? pc 166 : regs->uregs[rn]; 167 register unsigned long rmv asm("r3") = (rm == 15) ? pc 168 : regs->uregs[rm]; 169 register unsigned long rsv asm("r1") = regs->uregs[rs]; 170 unsigned long cpsr = regs->ARM_cpsr; 171 172 __asm__ __volatile__ ( 173 "msr cpsr_fs, %[cpsr] \n\t" 174 BLX("%[fn]") 175 "mrs %[cpsr], cpsr \n\t" 176 : "=r" (rdv), [cpsr] "=r" (cpsr) 177 : "" (rdv), "r" (rnv), "r" (rmv), "r" (rsv), 178 "1" (cpsr), [fn] "r" (asi->insn_fn) 179 : "lr", "memory", "cc" 180 ); 181 182 if (rd == 15) 183 alu_write_pc(rdv, regs); 184 else 185 regs->uregs[rd] = rdv; 186 regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); 187 } 188 189 static void __kprobes 190 emulate_rd12rn16rm0_rwflags_nopc(probes_opcode_t insn, 191 struct arch_probes_insn *asi, struct pt_regs *regs) 192 { 193 int rd = (insn >> 12) & 0xf; 194 int rn = (insn >> 16) & 0xf; 195 int rm = insn & 0xf; 196 197 register unsigned long rdv asm("r0") = regs->uregs[rd]; 198 register unsigned long rnv asm("r2") = regs->uregs[rn]; 199 register unsigned long rmv asm("r3") = regs->uregs[rm]; 200 unsigned long cpsr = regs->ARM_cpsr; 201 202 __asm__ __volatile__ ( 203 "msr cpsr_fs, %[cpsr] \n\t" 204 BLX("%[fn]") 205 "mrs %[cpsr], cpsr \n\t" 206 : "=r" (rdv), [cpsr] "=r" (cpsr) 207 : "" (rdv), "r" (rnv), "r" (rmv), 208 "1" (cpsr), [fn] "r" (asi->insn_fn) 209 : "lr", "memory", "cc" 210 ); 211 212 regs->uregs[rd] = rdv; 213 regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); 214 } 215 216 static void __kprobes 217 emulate_rd16rn12rm0rs8_rwflags_nopc(probes_opcode_t insn, 218 struct arch_probes_insn *asi, 219 struct pt_regs *regs) 220 { 221 int rd = (insn >> 16) & 0xf; 222 int rn = (insn >> 12) & 0xf; 223 int rm = insn & 0xf; 224 int rs = (insn >> 8) & 0xf; 225 226 register unsigned long rdv asm("r2") = regs->uregs[rd]; 227 register unsigned long rnv asm("r0") = regs->uregs[rn]; 228 register unsigned long rmv asm("r3") = regs->uregs[rm]; 229 register unsigned long rsv asm("r1") = regs->uregs[rs]; 230 unsigned long cpsr = regs->ARM_cpsr; 231 232 __asm__ __volatile__ ( 233 "msr cpsr_fs, %[cpsr] \n\t" 234 BLX("%[fn]") 235 "mrs %[cpsr], cpsr \n\t" 236 : "=r" (rdv), [cpsr] "=r" (cpsr) 237 : "" (rdv), "r" (rnv), "r" (rmv), "r" (rsv), 238 "1" (cpsr), [fn] "r" (asi->insn_fn) 239 : "lr", "memory", "cc" 240 ); 241 242 regs->uregs[rd] = rdv; 243 regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); 244 } 245 246 static void __kprobes 247 emulate_rd12rm0_noflags_nopc(probes_opcode_t insn, 248 struct arch_probes_insn *asi, struct pt_regs *regs) 249 { 250 int rd = (insn >> 12) & 0xf; 251 int rm = insn & 0xf; 252 253 register unsigned long rdv asm("r0") = regs->uregs[rd]; 254 register unsigned long rmv asm("r3") = regs->uregs[rm]; 255 256 __asm__ __volatile__ ( 257 BLX("%[fn]") 258 : "=r" (rdv) 259 : "" (rdv), "r" (rmv), [fn] "r" (asi->insn_fn) 260 : "lr", "memory", "cc" 261 ); 262 263 regs->uregs[rd] = rdv; 264 } 265 266 static void __kprobes 267 emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(probes_opcode_t insn, 268 struct arch_probes_insn *asi, 269 struct pt_regs *regs) 270 { 271 int rdlo = (insn >> 12) & 0xf; 272 int rdhi = (insn >> 16) & 0xf; 273 int rn = insn & 0xf; 274 int rm = (insn >> 8) & 0xf; 275 276 register unsigned long rdlov asm("r0") = regs->uregs[rdlo]; 277 register unsigned long rdhiv asm("r2") = regs->uregs[rdhi]; 278 register unsigned long rnv asm("r3") = regs->uregs[rn]; 279 register unsigned long rmv asm("r1") = regs->uregs[rm]; 280 unsigned long cpsr = regs->ARM_cpsr; 281 282 __asm__ __volatile__ ( 283 "msr cpsr_fs, %[cpsr] \n\t" 284 BLX("%[fn]") 285 "mrs %[cpsr], cpsr \n\t" 286 : "=r" (rdlov), "=r" (rdhiv), [cpsr] "=r" (cpsr) 287 : "" (rdlov), "1" (rdhiv), "r" (rnv), "r" (rmv), 288 "2" (cpsr), [fn] "r" (asi->insn_fn) 289 : "lr", "memory", "cc" 290 ); 291 292 regs->uregs[rdlo] = rdlov; 293 regs->uregs[rdhi] = rdhiv; 294 regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); 295 } 296 297 const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = { 298 [PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop}, 299 [PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop}, 300 [PROBES_BRANCH_IMM] = {.handler = simulate_blx1}, 301 [PROBES_MRS] = {.handler = simulate_mrs}, 302 [PROBES_BRANCH_REG] = {.handler = simulate_blx2bx}, 303 [PROBES_CLZ] = {.handler = emulate_rd12rm0_noflags_nopc}, 304 [PROBES_SATURATING_ARITHMETIC] = { 305 .handler = emulate_rd12rn16rm0_rwflags_nopc}, 306 [PROBES_MUL1] = {.handler = emulate_rdlo12rdhi16rn0rm8_rwflags_nopc}, 307 [PROBES_MUL2] = {.handler = emulate_rd16rn12rm0rs8_rwflags_nopc}, 308 [PROBES_SWP] = {.handler = emulate_rd12rn16rm0_rwflags_nopc}, 309 [PROBES_LDRSTRD] = {.handler = emulate_ldrdstrd}, 310 [PROBES_LOAD_EXTRA] = {.handler = emulate_ldr}, 311 [PROBES_LOAD] = {.handler = emulate_ldr}, 312 [PROBES_STORE_EXTRA] = {.handler = emulate_str}, 313 [PROBES_STORE] = {.handler = emulate_str}, 314 [PROBES_MOV_IP_SP] = {.handler = simulate_mov_ipsp}, 315 [PROBES_DATA_PROCESSING_REG] = { 316 .handler = emulate_rd12rn16rm0rs8_rwflags}, 317 [PROBES_DATA_PROCESSING_IMM] = { 318 .handler = emulate_rd12rn16rm0rs8_rwflags}, 319 [PROBES_MOV_HALFWORD] = {.handler = emulate_rd12rm0_noflags_nopc}, 320 [PROBES_SEV] = {.handler = probes_emulate_none}, 321 [PROBES_WFE] = {.handler = probes_simulate_nop}, 322 [PROBES_SATURATE] = {.handler = emulate_rd12rn16rm0_rwflags_nopc}, 323 [PROBES_REV] = {.handler = emulate_rd12rm0_noflags_nopc}, 324 [PROBES_MMI] = {.handler = emulate_rd12rn16rm0_rwflags_nopc}, 325 [PROBES_PACK] = {.handler = emulate_rd12rn16rm0_rwflags_nopc}, 326 [PROBES_EXTEND] = {.handler = emulate_rd12rm0_noflags_nopc}, 327 [PROBES_EXTEND_ADD] = {.handler = emulate_rd12rn16rm0_rwflags_nopc}, 328 [PROBES_MUL_ADD_LONG] = { 329 .handler = emulate_rdlo12rdhi16rn0rm8_rwflags_nopc}, 330 [PROBES_MUL_ADD] = {.handler = emulate_rd16rn12rm0rs8_rwflags_nopc}, 331 [PROBES_BITFIELD] = {.handler = emulate_rd12rm0_noflags_nopc}, 332 [PROBES_BRANCH] = {.handler = simulate_bbl}, 333 [PROBES_LDMSTM] = {.decoder = kprobe_decode_ldmstm} 334 }; 335 336 const struct decode_checker *kprobes_arm_checkers[] = {arm_stack_checker, arm_regs_checker, NULL}; 337
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.