linux/arch/arm/probes/kprobes/actions-arm.c
<<
>>
Prefs
   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
  68static void __kprobes
  69emulate_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                : "0" (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
  97static void __kprobes
  98emulate_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
 127static void __kprobes
 128emulate_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), "0" (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
 154static void __kprobes
 155emulate_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                : "0" (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
 189static void __kprobes
 190emulate_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                : "0" (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
 216static void __kprobes
 217emulate_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                : "0" (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
 246static void __kprobes
 247emulate_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                : "0" (rdv), "r" (rmv), [fn] "r" (asi->insn_fn)
 260                : "lr", "memory", "cc"
 261        );
 262
 263        regs->uregs[rd] = rdv;
 264}
 265
 266static void __kprobes
 267emulate_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                : "0" (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
 297const 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
 336const struct decode_checker *kprobes_arm_checkers[] = {arm_stack_checker, arm_regs_checker, NULL};
 337