]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - arch/s390/kernel/ftrace.c
[S390] ftrace: add dynamic ftrace support
[mirror_ubuntu-artful-kernel.git] / arch / s390 / kernel / ftrace.c
1 /*
2 * Dynamic function tracer architecture backend.
3 *
4 * Copyright IBM Corp. 2009
5 *
6 * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
7 *
8 */
9
10 #include <linux/uaccess.h>
11 #include <linux/ftrace.h>
12 #include <linux/kernel.h>
13 #include <linux/types.h>
14 #include <asm/lowcore.h>
15
16 void ftrace_disable_code(void);
17 void ftrace_call_code(void);
18 void ftrace_nop_code(void);
19
20 #define FTRACE_INSN_SIZE 4
21
22 #ifdef CONFIG_64BIT
23
24 asm(
25 " .align 4\n"
26 "ftrace_disable_code:\n"
27 " j 0f\n"
28 " .word 0x0024\n"
29 " lg %r1,"__stringify(__LC_FTRACE_FUNC)"\n"
30 " basr %r14,%r1\n"
31 " lg %r14,8(15)\n"
32 " lgr %r0,%r0\n"
33 "0:\n");
34
35 asm(
36 " .align 4\n"
37 "ftrace_nop_code:\n"
38 " j .+"__stringify(MCOUNT_INSN_SIZE)"\n");
39
40 asm(
41 " .align 4\n"
42 "ftrace_call_code:\n"
43 " stg %r14,8(%r15)\n");
44
45 #else /* CONFIG_64BIT */
46
47 asm(
48 " .align 4\n"
49 "ftrace_disable_code:\n"
50 " j 0f\n"
51 " l %r1,"__stringify(__LC_FTRACE_FUNC)"\n"
52 " basr %r14,%r1\n"
53 " l %r14,4(%r15)\n"
54 " j 0f\n"
55 " bcr 0,%r7\n"
56 " bcr 0,%r7\n"
57 " bcr 0,%r7\n"
58 " bcr 0,%r7\n"
59 " bcr 0,%r7\n"
60 " bcr 0,%r7\n"
61 "0:\n");
62
63 asm(
64 " .align 4\n"
65 "ftrace_nop_code:\n"
66 " j .+"__stringify(MCOUNT_INSN_SIZE)"\n");
67
68 asm(
69 " .align 4\n"
70 "ftrace_call_code:\n"
71 " st %r14,4(%r15)\n");
72
73 #endif /* CONFIG_64BIT */
74
75 static int ftrace_modify_code(unsigned long ip,
76 void *old_code, int old_size,
77 void *new_code, int new_size)
78 {
79 unsigned char replaced[MCOUNT_INSN_SIZE];
80
81 /*
82 * Note: Due to modules code can disappear and change.
83 * We need to protect against faulting as well as code
84 * changing. We do this by using the probe_kernel_*
85 * functions.
86 * This however is just a simple sanity check.
87 */
88 if (probe_kernel_read(replaced, (void *)ip, old_size))
89 return -EFAULT;
90 if (memcmp(replaced, old_code, old_size) != 0)
91 return -EINVAL;
92 if (probe_kernel_write((void *)ip, new_code, new_size))
93 return -EPERM;
94 return 0;
95 }
96
97 static int ftrace_make_initial_nop(struct module *mod, struct dyn_ftrace *rec,
98 unsigned long addr)
99 {
100 return ftrace_modify_code(rec->ip,
101 ftrace_call_code, FTRACE_INSN_SIZE,
102 ftrace_disable_code, MCOUNT_INSN_SIZE);
103 }
104
105 int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
106 unsigned long addr)
107 {
108 if (addr == MCOUNT_ADDR)
109 return ftrace_make_initial_nop(mod, rec, addr);
110 return ftrace_modify_code(rec->ip,
111 ftrace_call_code, FTRACE_INSN_SIZE,
112 ftrace_nop_code, FTRACE_INSN_SIZE);
113 }
114
115 int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
116 {
117 return ftrace_modify_code(rec->ip,
118 ftrace_nop_code, FTRACE_INSN_SIZE,
119 ftrace_call_code, FTRACE_INSN_SIZE);
120 }
121
122 int ftrace_update_ftrace_func(ftrace_func_t func)
123 {
124 ftrace_dyn_func = (unsigned long)func;
125 return 0;
126 }
127
128 int __init ftrace_dyn_arch_init(void *data)
129 {
130 *(unsigned long *)data = 0;
131 return 0;
132 }