^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * arch/arm/probes/kprobes/actions-common.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Some contents moved here from arch/arm/include/asm/kprobes-arm.c which is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Copyright (C) 2006, 2007 Motorola Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/kprobes.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <asm/opcodes.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include "core.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) static void __kprobes simulate_ldm1stm1(probes_opcode_t insn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) struct arch_probes_insn *asi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) struct pt_regs *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) int rn = (insn >> 16) & 0xf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) int lbit = insn & (1 << 20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) int wbit = insn & (1 << 21);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) int ubit = insn & (1 << 23);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) int pbit = insn & (1 << 24);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) long *addr = (long *)regs->uregs[rn];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) int reg_bit_vector;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) int reg_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) reg_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) reg_bit_vector = insn & 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) while (reg_bit_vector) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) reg_bit_vector &= (reg_bit_vector - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) ++reg_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) if (!ubit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) addr -= reg_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) addr += (!pbit == !ubit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) reg_bit_vector = insn & 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) while (reg_bit_vector) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) int reg = __ffs(reg_bit_vector);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) reg_bit_vector &= (reg_bit_vector - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) if (lbit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) regs->uregs[reg] = *addr++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) *addr++ = regs->uregs[reg];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) if (wbit) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) if (!ubit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) addr -= reg_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) addr -= (!pbit == !ubit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) regs->uregs[rn] = (long)addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) static void __kprobes simulate_stm1_pc(probes_opcode_t insn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) struct arch_probes_insn *asi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) struct pt_regs *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) unsigned long addr = regs->ARM_pc - 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) regs->ARM_pc = (long)addr + str_pc_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) simulate_ldm1stm1(insn, asi, regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) regs->ARM_pc = (long)addr + 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) static void __kprobes simulate_ldm1_pc(probes_opcode_t insn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) struct arch_probes_insn *asi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) struct pt_regs *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) simulate_ldm1stm1(insn, asi, regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) load_write_pc(regs->ARM_pc, regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) static void __kprobes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) emulate_generic_r0_12_noflags(probes_opcode_t insn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) struct arch_probes_insn *asi, struct pt_regs *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) register void *rregs asm("r1") = regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) register void *rfn asm("lr") = asi->insn_fn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) __asm__ __volatile__ (
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) "stmdb sp!, {%[regs], r11} \n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) "ldmia %[regs], {r0-r12} \n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) #if __LINUX_ARM_ARCH__ >= 6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) "blx %[fn] \n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) "str %[fn], [sp, #-4]! \n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) "adr lr, 1f \n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) "ldr pc, [sp], #4 \n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) "1: \n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) "ldr lr, [sp], #4 \n\t" /* lr = regs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) "stmia lr, {r0-r12} \n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) "ldr r11, [sp], #4 \n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) : [regs] "=r" (rregs), [fn] "=r" (rfn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) : "0" (rregs), "1" (rfn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) : "r0", "r2", "r3", "r4", "r5", "r6", "r7",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) "r8", "r9", "r10", "r12", "memory", "cc"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) static void __kprobes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) emulate_generic_r2_14_noflags(probes_opcode_t insn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) struct arch_probes_insn *asi, struct pt_regs *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) emulate_generic_r0_12_noflags(insn, asi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) (struct pt_regs *)(regs->uregs+2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) static void __kprobes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) emulate_ldm_r3_15(probes_opcode_t insn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) struct arch_probes_insn *asi, struct pt_regs *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) emulate_generic_r0_12_noflags(insn, asi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) (struct pt_regs *)(regs->uregs+3));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) load_write_pc(regs->ARM_pc, regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) enum probes_insn __kprobes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) kprobe_decode_ldmstm(probes_opcode_t insn, struct arch_probes_insn *asi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) const struct decode_header *h)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) probes_insn_handler_t *handler = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) unsigned reglist = insn & 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) int is_ldm = insn & 0x100000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) int rn = (insn >> 16) & 0xf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) if (rn <= 12 && (reglist & 0xe000) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) /* Instruction only uses registers in the range R0..R12 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) handler = emulate_generic_r0_12_noflags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) } else if (rn >= 2 && (reglist & 0x8003) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) /* Instruction only uses registers in the range R2..R14 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) rn -= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) reglist >>= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) handler = emulate_generic_r2_14_noflags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) } else if (rn >= 3 && (reglist & 0x0007) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) /* Instruction only uses registers in the range R3..R15 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) if (is_ldm && (reglist & 0x8000)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) rn -= 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) reglist >>= 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) handler = emulate_ldm_r3_15;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) if (handler) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) /* We can emulate the instruction in (possibly) modified form */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) asi->insn[0] = __opcode_to_mem_arm((insn & 0xfff00000) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) (rn << 16) | reglist);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) asi->insn_handler = handler;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) return INSN_GOOD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) /* Fallback to slower simulation... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) if (reglist & 0x8000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) handler = is_ldm ? simulate_ldm1_pc : simulate_stm1_pc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) handler = simulate_ldm1stm1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) asi->insn_handler = handler;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) return INSN_GOOD_NO_SLOT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)