~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/metag/kernel/ftrace.c

Version: ~ [ linux-4.16-rc2 ] ~ [ linux-4.15.4 ] ~ [ linux-4.14.20 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.82 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.116 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.49 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.95 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.54 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.99 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.39.4 ] ~ [ linux-2.6.38.8 ] ~ [ linux-2.6.37.6 ] ~ [ linux-2.6.36.4 ] ~ [ linux-2.6.35.14 ] ~ [ linux-2.6.34.15 ] ~ [ linux-2.6.33.20 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.27.62 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * Copyright (C) 2008 Imagination Technologies Ltd.
  3  * Licensed under the GPL
  4  *
  5  * Dynamic ftrace support.
  6  */
  7 
  8 #include <linux/ftrace.h>
  9 #include <linux/io.h>
 10 #include <linux/uaccess.h>
 11 
 12 #include <asm/cacheflush.h>
 13 
 14 #define D04_MOVT_TEMPLATE       0x02200005
 15 #define D04_CALL_TEMPLATE       0xAC200005
 16 #define D1RTP_MOVT_TEMPLATE     0x03200005
 17 #define D1RTP_CALL_TEMPLATE     0xAC200006
 18 
 19 static const unsigned long NOP[2] = {0xa0fffffe, 0xa0fffffe};
 20 static unsigned long movt_and_call_insn[2];
 21 
 22 static unsigned char *ftrace_nop_replace(void)
 23 {
 24         return (char *)&NOP[0];
 25 }
 26 
 27 static unsigned char *ftrace_call_replace(unsigned long pc, unsigned long addr)
 28 {
 29         unsigned long hi16, low16;
 30 
 31         hi16 = (addr & 0xffff0000) >> 13;
 32         low16 = (addr & 0x0000ffff) << 3;
 33 
 34         /*
 35          * The compiler makes the call to mcount_wrapper()
 36          * (Meta's wrapper around mcount()) through the register
 37          * D0.4. So whenever we're patching one of those compiler-generated
 38          * calls we also need to go through D0.4. Otherwise use D1RtP.
 39          */
 40         if (pc == (unsigned long)&ftrace_call) {
 41                 writel(D1RTP_MOVT_TEMPLATE | hi16, &movt_and_call_insn[0]);
 42                 writel(D1RTP_CALL_TEMPLATE | low16, &movt_and_call_insn[1]);
 43         } else {
 44                 writel(D04_MOVT_TEMPLATE | hi16, &movt_and_call_insn[0]);
 45                 writel(D04_CALL_TEMPLATE | low16, &movt_and_call_insn[1]);
 46         }
 47 
 48         return (unsigned char *)&movt_and_call_insn[0];
 49 }
 50 
 51 static int ftrace_modify_code(unsigned long pc, unsigned char *old_code,
 52                               unsigned char *new_code)
 53 {
 54         unsigned char replaced[MCOUNT_INSN_SIZE];
 55 
 56         /*
 57          * Note:
 58          * We are paranoid about modifying text, as if a bug was to happen, it
 59          * could cause us to read or write to someplace that could cause harm.
 60          * Carefully read and modify the code with probe_kernel_*(), and make
 61          * sure what we read is what we expected it to be before modifying it.
 62          */
 63 
 64         /* read the text we want to modify */
 65         if (probe_kernel_read(replaced, (void *)pc, MCOUNT_INSN_SIZE))
 66                 return -EFAULT;
 67 
 68         /* Make sure it is what we expect it to be */
 69         if (memcmp(replaced, old_code, MCOUNT_INSN_SIZE) != 0)
 70                 return -EINVAL;
 71 
 72         /* replace the text with the new text */
 73         if (probe_kernel_write((void *)pc, new_code, MCOUNT_INSN_SIZE))
 74                 return -EPERM;
 75 
 76         flush_icache_range(pc, pc + MCOUNT_INSN_SIZE);
 77 
 78         return 0;
 79 }
 80 
 81 int ftrace_update_ftrace_func(ftrace_func_t func)
 82 {
 83         int ret;
 84         unsigned long pc;
 85         unsigned char old[MCOUNT_INSN_SIZE], *new;
 86 
 87         pc = (unsigned long)&ftrace_call;
 88         memcpy(old, &ftrace_call, MCOUNT_INSN_SIZE);
 89         new = ftrace_call_replace(pc, (unsigned long)func);
 90         ret = ftrace_modify_code(pc, old, new);
 91 
 92         return ret;
 93 }
 94 
 95 int ftrace_make_nop(struct module *mod,
 96                     struct dyn_ftrace *rec, unsigned long addr)
 97 {
 98         unsigned char *new, *old;
 99         unsigned long ip = rec->ip;
100 
101         old = ftrace_call_replace(ip, addr);
102         new = ftrace_nop_replace();
103 
104         return ftrace_modify_code(ip, old, new);
105 }
106 
107 int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
108 {
109         unsigned char *new, *old;
110         unsigned long ip = rec->ip;
111 
112         old = ftrace_nop_replace();
113         new = ftrace_call_replace(ip, addr);
114 
115         return ftrace_modify_code(ip, old, new);
116 }
117 
118 int __init ftrace_dyn_arch_init(void)
119 {
120         return 0;
121 }
122 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp