123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- /*
- * arch/arm/kernel/kprobes.h
- *
- * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
- *
- * Some contents moved here from arch/arm/include/asm/kprobes.h which is
- * Copyright (C) 2006, 2007 Motorola Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- */
- #ifndef _ARM_KERNEL_KPROBES_H
- #define _ARM_KERNEL_KPROBES_H
- /*
- * These undefined instructions must be unique and
- * reserved solely for kprobes' use.
- */
- #define KPROBE_ARM_BREAKPOINT_INSTRUCTION 0x07f001f8
- #define KPROBE_THUMB16_BREAKPOINT_INSTRUCTION 0xde18
- #define KPROBE_THUMB32_BREAKPOINT_INSTRUCTION 0xf7f0a018
- enum kprobe_insn {
- INSN_REJECTED,
- INSN_GOOD,
- INSN_GOOD_NO_SLOT
- };
- typedef enum kprobe_insn (kprobe_decode_insn_t)(kprobe_opcode_t,
- struct arch_specific_insn *);
- #ifdef CONFIG_THUMB2_KERNEL
- enum kprobe_insn thumb16_kprobe_decode_insn(kprobe_opcode_t,
- struct arch_specific_insn *);
- enum kprobe_insn thumb32_kprobe_decode_insn(kprobe_opcode_t,
- struct arch_specific_insn *);
- #else /* !CONFIG_THUMB2_KERNEL */
- enum kprobe_insn arm_kprobe_decode_insn(kprobe_opcode_t,
- struct arch_specific_insn *);
- #endif
- void __init arm_kprobe_decode_init(void);
- extern kprobe_check_cc * const kprobe_condition_checks[16];
- #if __LINUX_ARM_ARCH__ >= 7
- /* str_pc_offset is architecturally defined from ARMv7 onwards */
- #define str_pc_offset 8
- #define find_str_pc_offset()
- #else /* __LINUX_ARM_ARCH__ < 7 */
- /* We need a run-time check to determine str_pc_offset */
- extern int str_pc_offset;
- void __init find_str_pc_offset(void);
- #endif
- /*
- * Update ITSTATE after normal execution of an IT block instruction.
- *
- * The 8 IT state bits are split into two parts in CPSR:
- * ITSTATE<1:0> are in CPSR<26:25>
- * ITSTATE<7:2> are in CPSR<15:10>
- */
- static inline unsigned long it_advance(unsigned long cpsr)
- {
- if ((cpsr & 0x06000400) == 0) {
- /* ITSTATE<2:0> == 0 means end of IT block, so clear IT state */
- cpsr &= ~PSR_IT_MASK;
- } else {
- /* We need to shift left ITSTATE<4:0> */
- const unsigned long mask = 0x06001c00; /* Mask ITSTATE<4:0> */
- unsigned long it = cpsr & mask;
- it <<= 1;
- it |= it >> (27 - 10); /* Carry ITSTATE<2> to correct place */
- it &= mask;
- cpsr &= ~mask;
- cpsr |= it;
- }
- return cpsr;
- }
- static inline void __kprobes bx_write_pc(long pcv, struct pt_regs *regs)
- {
- long cpsr = regs->ARM_cpsr;
- if (pcv & 0x1) {
- cpsr |= PSR_T_BIT;
- pcv &= ~0x1;
- } else {
- cpsr &= ~PSR_T_BIT;
- pcv &= ~0x2; /* Avoid UNPREDICTABLE address allignment */
- }
- regs->ARM_cpsr = cpsr;
- regs->ARM_pc = pcv;
- }
- #if __LINUX_ARM_ARCH__ >= 6
- /* Kernels built for >= ARMv6 should never run on <= ARMv5 hardware, so... */
- #define load_write_pc_interworks true
- #define test_load_write_pc_interworking()
- #else /* __LINUX_ARM_ARCH__ < 6 */
- /* We need run-time testing to determine if load_write_pc() should interwork. */
- extern bool load_write_pc_interworks;
- void __init test_load_write_pc_interworking(void);
- #endif
- static inline void __kprobes load_write_pc(long pcv, struct pt_regs *regs)
- {
- if (load_write_pc_interworks)
- bx_write_pc(pcv, regs);
- else
- regs->ARM_pc = pcv;
- }
|