cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ftrace.c (5915B)


      1/*
      2 * Ftrace support for Microblaze.
      3 *
      4 * Copyright (C) 2009 Michal Simek <monstr@monstr.eu>
      5 * Copyright (C) 2009 PetaLogix
      6 *
      7 * Based on MIPS and PowerPC ftrace code
      8 *
      9 * This file is subject to the terms and conditions of the GNU General Public
     10 * License. See the file "COPYING" in the main directory of this archive
     11 * for more details.
     12 */
     13
     14#include <asm/cacheflush.h>
     15#include <linux/ftrace.h>
     16
     17#ifdef CONFIG_FUNCTION_GRAPH_TRACER
     18/*
     19 * Hook the return address and push it in the stack of return addrs
     20 * in current thread info.
     21 */
     22void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
     23{
     24	unsigned long old;
     25	int faulted;
     26	unsigned long return_hooker = (unsigned long)
     27				&return_to_handler;
     28
     29	if (unlikely(ftrace_graph_is_dead()))
     30		return;
     31
     32	if (unlikely(atomic_read(&current->tracing_graph_pause)))
     33		return;
     34
     35	/*
     36	 * Protect against fault, even if it shouldn't
     37	 * happen. This tool is too much intrusive to
     38	 * ignore such a protection.
     39	 */
     40	asm volatile("	1:	lwi	%0, %2, 0;"		\
     41			"2:	swi	%3, %2, 0;"		\
     42			"	addik	%1, r0, 0;"		\
     43			"3:"					\
     44			"	.section .fixup, \"ax\";"	\
     45			"4:	brid	3b;"			\
     46			"	addik	%1, r0, 1;"		\
     47			"	.previous;"			\
     48			"	.section __ex_table,\"a\";"	\
     49			"	.word	1b,4b;"			\
     50			"	.word	2b,4b;"			\
     51			"	.previous;"			\
     52			: "=&r" (old), "=r" (faulted)
     53			: "r" (parent), "r" (return_hooker)
     54	);
     55
     56	flush_dcache_range((u32)parent, (u32)parent + 4);
     57	flush_icache_range((u32)parent, (u32)parent + 4);
     58
     59	if (unlikely(faulted)) {
     60		ftrace_graph_stop();
     61		WARN_ON(1);
     62		return;
     63	}
     64
     65	if (function_graph_enter(old, self_addr, 0, NULL))
     66		*parent = old;
     67}
     68#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
     69
     70#ifdef CONFIG_DYNAMIC_FTRACE
     71/* save value to addr - it is save to do it in asm */
     72static int ftrace_modify_code(unsigned long addr, unsigned int value)
     73{
     74	int faulted = 0;
     75
     76	__asm__ __volatile__("	1:	swi	%2, %1, 0;"		\
     77				"	addik	%0, r0, 0;"		\
     78				"2:"					\
     79				"	.section .fixup, \"ax\";"	\
     80				"3:	brid	2b;"			\
     81				"	addik	%0, r0, 1;"		\
     82				"	.previous;"			\
     83				"	.section __ex_table,\"a\";"	\
     84				"	.word	1b,3b;"			\
     85				"	.previous;"			\
     86				: "=r" (faulted)
     87				: "r" (addr), "r" (value)
     88	);
     89
     90	if (unlikely(faulted))
     91		return -EFAULT;
     92
     93	flush_dcache_range(addr, addr + 4);
     94	flush_icache_range(addr, addr + 4);
     95
     96	return 0;
     97}
     98
     99#define MICROBLAZE_NOP 0x80000000
    100#define MICROBLAZE_BRI 0xb800000C
    101
    102static unsigned int recorded; /* if save was or not */
    103static unsigned int imm; /* saving whole imm instruction */
    104
    105/* There are two approaches howto solve ftrace_make nop function - look below */
    106#undef USE_FTRACE_NOP
    107
    108#ifdef USE_FTRACE_NOP
    109static unsigned int bralid; /* saving whole bralid instruction */
    110#endif
    111
    112int ftrace_make_nop(struct module *mod,
    113			struct dyn_ftrace *rec, unsigned long addr)
    114{
    115	/* we have this part of code which we are working with
    116	 * b000c000        imm     -16384
    117	 * b9fc8e30        bralid  r15, -29136     // c0008e30 <_mcount>
    118	 * 80000000        or      r0, r0, r0
    119	 *
    120	 * The first solution (!USE_FTRACE_NOP-could be called branch solution)
    121	 * b000c000        bri	12 (0xC - jump to any other instruction)
    122	 * b9fc8e30        bralid  r15, -29136     // c0008e30 <_mcount>
    123	 * 80000000        or      r0, r0, r0
    124	 * any other instruction
    125	 *
    126	 * The second solution (USE_FTRACE_NOP) - no jump just nops
    127	 * 80000000        or      r0, r0, r0
    128	 * 80000000        or      r0, r0, r0
    129	 * 80000000        or      r0, r0, r0
    130	 */
    131	int ret = 0;
    132
    133	if (recorded == 0) {
    134		recorded = 1;
    135		imm = *(unsigned int *)rec->ip;
    136		pr_debug("%s: imm:0x%x\n", __func__, imm);
    137#ifdef USE_FTRACE_NOP
    138		bralid = *(unsigned int *)(rec->ip + 4);
    139		pr_debug("%s: bralid 0x%x\n", __func__, bralid);
    140#endif /* USE_FTRACE_NOP */
    141	}
    142
    143#ifdef USE_FTRACE_NOP
    144	ret = ftrace_modify_code(rec->ip, MICROBLAZE_NOP);
    145	ret += ftrace_modify_code(rec->ip + 4, MICROBLAZE_NOP);
    146#else /* USE_FTRACE_NOP */
    147	ret = ftrace_modify_code(rec->ip, MICROBLAZE_BRI);
    148#endif /* USE_FTRACE_NOP */
    149	return ret;
    150}
    151
    152/* I believe that first is called ftrace_make_nop before this function */
    153int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
    154{
    155	int ret;
    156	pr_debug("%s: addr:0x%x, rec->ip: 0x%x, imm:0x%x\n",
    157		__func__, (unsigned int)addr, (unsigned int)rec->ip, imm);
    158	ret = ftrace_modify_code(rec->ip, imm);
    159#ifdef USE_FTRACE_NOP
    160	pr_debug("%s: bralid:0x%x\n", __func__, bralid);
    161	ret += ftrace_modify_code(rec->ip + 4, bralid);
    162#endif /* USE_FTRACE_NOP */
    163	return ret;
    164}
    165
    166int ftrace_update_ftrace_func(ftrace_func_t func)
    167{
    168	unsigned long ip = (unsigned long)(&ftrace_call);
    169	unsigned int upper = (unsigned int)func;
    170	unsigned int lower = (unsigned int)func;
    171	int ret = 0;
    172
    173	/* create proper saving to ftrace_call poll */
    174	upper = 0xb0000000 + (upper >> 16); /* imm func_upper */
    175	lower = 0x32800000 + (lower & 0xFFFF); /* addik r20, r0, func_lower */
    176
    177	pr_debug("%s: func=0x%x, ip=0x%x, upper=0x%x, lower=0x%x\n",
    178		__func__, (unsigned int)func, (unsigned int)ip, upper, lower);
    179
    180	/* save upper and lower code */
    181	ret = ftrace_modify_code(ip, upper);
    182	ret += ftrace_modify_code(ip + 4, lower);
    183
    184	/* We just need to replace the rtsd r15, 8 with NOP */
    185	ret += ftrace_modify_code((unsigned long)&ftrace_caller,
    186				  MICROBLAZE_NOP);
    187
    188	return ret;
    189}
    190
    191#ifdef CONFIG_FUNCTION_GRAPH_TRACER
    192unsigned int old_jump; /* saving place for jump instruction */
    193
    194int ftrace_enable_ftrace_graph_caller(void)
    195{
    196	unsigned int ret;
    197	unsigned long ip = (unsigned long)(&ftrace_call_graph);
    198
    199	old_jump = *(unsigned int *)ip; /* save jump over instruction */
    200	ret = ftrace_modify_code(ip, MICROBLAZE_NOP);
    201
    202	pr_debug("%s: Replace instruction: 0x%x\n", __func__, old_jump);
    203	return ret;
    204}
    205
    206int ftrace_disable_ftrace_graph_caller(void)
    207{
    208	unsigned int ret;
    209	unsigned long ip = (unsigned long)(&ftrace_call_graph);
    210
    211	ret = ftrace_modify_code(ip, old_jump);
    212
    213	pr_debug("%s\n", __func__);
    214	return ret;
    215}
    216#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
    217#endif /* CONFIG_DYNAMIC_FTRACE */