| 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	0xf7f0a018enum 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_KERNELenum 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 *);#endifvoid __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);#endifstatic 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;}
 |