diff options
author | Heiko Carstens <heiko.carstens@de.ibm.com> | 2009-06-12 04:26:46 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2009-06-12 04:27:39 -0400 |
commit | 88dbd2037229bd2ed7543ffd0d8f2d9dec9d31d2 (patch) | |
tree | 60dd9e5ec02fb95872809c7076a4e717fc82dea5 /arch/s390 | |
parent | 8b4488f85d619253c9e631ec723368f400106771 (diff) |
[S390] ftrace: add function graph tracer support
Function graph tracer support for s390.
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390')
-rw-r--r-- | arch/s390/Kconfig | 1 | ||||
-rw-r--r-- | arch/s390/include/asm/ftrace.h | 10 | ||||
-rw-r--r-- | arch/s390/kernel/Makefile | 6 | ||||
-rw-r--r-- | arch/s390/kernel/ftrace.c | 72 | ||||
-rw-r--r-- | arch/s390/kernel/mcount.S | 79 | ||||
-rw-r--r-- | arch/s390/kernel/s390_ext.c | 3 | ||||
-rw-r--r-- | arch/s390/kernel/time.c | 2 | ||||
-rw-r--r-- | arch/s390/kernel/vmlinux.lds.S | 1 |
8 files changed, 164 insertions, 10 deletions
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 480590f21570..9023cc900bda 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig | |||
@@ -85,6 +85,7 @@ config S390 | |||
85 | select HAVE_FUNCTION_TRACE_MCOUNT_TEST | 85 | select HAVE_FUNCTION_TRACE_MCOUNT_TEST |
86 | select HAVE_FTRACE_MCOUNT_RECORD | 86 | select HAVE_FTRACE_MCOUNT_RECORD |
87 | select HAVE_DYNAMIC_FTRACE | 87 | select HAVE_DYNAMIC_FTRACE |
88 | select HAVE_FUNCTION_GRAPH_TRACER | ||
88 | select HAVE_DEFAULT_NO_SPIN_MUTEXES | 89 | select HAVE_DEFAULT_NO_SPIN_MUTEXES |
89 | select HAVE_OPROFILE | 90 | select HAVE_OPROFILE |
90 | select HAVE_KPROBES | 91 | select HAVE_KPROBES |
diff --git a/arch/s390/include/asm/ftrace.h b/arch/s390/include/asm/ftrace.h index ba23d8f97d07..96c14a9102b8 100644 --- a/arch/s390/include/asm/ftrace.h +++ b/arch/s390/include/asm/ftrace.h | |||
@@ -11,11 +11,13 @@ struct dyn_arch_ftrace { }; | |||
11 | #define MCOUNT_ADDR ((long)_mcount) | 11 | #define MCOUNT_ADDR ((long)_mcount) |
12 | 12 | ||
13 | #ifdef CONFIG_64BIT | 13 | #ifdef CONFIG_64BIT |
14 | #define MCOUNT_INSN_SIZE 24 | 14 | #define MCOUNT_OFFSET_RET 18 |
15 | #define MCOUNT_OFFSET 14 | 15 | #define MCOUNT_INSN_SIZE 24 |
16 | #define MCOUNT_OFFSET 14 | ||
16 | #else | 17 | #else |
17 | #define MCOUNT_INSN_SIZE 30 | 18 | #define MCOUNT_OFFSET_RET 26 |
18 | #define MCOUNT_OFFSET 8 | 19 | #define MCOUNT_INSN_SIZE 30 |
20 | #define MCOUNT_OFFSET 8 | ||
19 | #endif | 21 | #endif |
20 | 22 | ||
21 | static inline unsigned long ftrace_call_adjust(unsigned long addr) | 23 | static inline unsigned long ftrace_call_adjust(unsigned long addr) |
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index ce172bfaab8a..c75ed43b1a18 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile | |||
@@ -3,11 +3,8 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | ifdef CONFIG_FUNCTION_TRACER | 5 | ifdef CONFIG_FUNCTION_TRACER |
6 | # Do not trace early boot code | 6 | # Don't trace early setup code and tracing code |
7 | CFLAGS_REMOVE_early.o = -pg | 7 | CFLAGS_REMOVE_early.o = -pg |
8 | endif | ||
9 | |||
10 | ifdef CONFIG_DYNAMIC_FTRACE | ||
11 | CFLAGS_REMOVE_ftrace.o = -pg | 8 | CFLAGS_REMOVE_ftrace.o = -pg |
12 | endif | 9 | endif |
13 | 10 | ||
@@ -46,6 +43,7 @@ obj-$(CONFIG_STACKTRACE) += stacktrace.o | |||
46 | obj-$(CONFIG_KPROBES) += kprobes.o | 43 | obj-$(CONFIG_KPROBES) += kprobes.o |
47 | obj-$(CONFIG_FUNCTION_TRACER) += mcount.o | 44 | obj-$(CONFIG_FUNCTION_TRACER) += mcount.o |
48 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o | 45 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o |
46 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o | ||
49 | 47 | ||
50 | # Kexec part | 48 | # Kexec part |
51 | S390_KEXEC_OBJS := machine_kexec.o crash.o | 49 | S390_KEXEC_OBJS := machine_kexec.o crash.o |
diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c index 0b81a784e039..c92a10953279 100644 --- a/arch/s390/kernel/ftrace.c +++ b/arch/s390/kernel/ftrace.c | |||
@@ -7,13 +7,17 @@ | |||
7 | * | 7 | * |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/hardirq.h> | ||
10 | #include <linux/uaccess.h> | 11 | #include <linux/uaccess.h> |
11 | #include <linux/ftrace.h> | 12 | #include <linux/ftrace.h> |
12 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
13 | #include <linux/types.h> | 14 | #include <linux/types.h> |
14 | #include <asm/lowcore.h> | 15 | #include <asm/lowcore.h> |
15 | 16 | ||
17 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
18 | |||
16 | void ftrace_disable_code(void); | 19 | void ftrace_disable_code(void); |
20 | void ftrace_disable_return(void); | ||
17 | void ftrace_call_code(void); | 21 | void ftrace_call_code(void); |
18 | void ftrace_nop_code(void); | 22 | void ftrace_nop_code(void); |
19 | 23 | ||
@@ -28,6 +32,7 @@ asm( | |||
28 | " .word 0x0024\n" | 32 | " .word 0x0024\n" |
29 | " lg %r1,"__stringify(__LC_FTRACE_FUNC)"\n" | 33 | " lg %r1,"__stringify(__LC_FTRACE_FUNC)"\n" |
30 | " basr %r14,%r1\n" | 34 | " basr %r14,%r1\n" |
35 | "ftrace_disable_return:\n" | ||
31 | " lg %r14,8(15)\n" | 36 | " lg %r14,8(15)\n" |
32 | " lgr %r0,%r0\n" | 37 | " lgr %r0,%r0\n" |
33 | "0:\n"); | 38 | "0:\n"); |
@@ -50,6 +55,7 @@ asm( | |||
50 | " j 0f\n" | 55 | " j 0f\n" |
51 | " l %r1,"__stringify(__LC_FTRACE_FUNC)"\n" | 56 | " l %r1,"__stringify(__LC_FTRACE_FUNC)"\n" |
52 | " basr %r14,%r1\n" | 57 | " basr %r14,%r1\n" |
58 | "ftrace_disable_return:\n" | ||
53 | " l %r14,4(%r15)\n" | 59 | " l %r14,4(%r15)\n" |
54 | " j 0f\n" | 60 | " j 0f\n" |
55 | " bcr 0,%r7\n" | 61 | " bcr 0,%r7\n" |
@@ -130,3 +136,69 @@ int __init ftrace_dyn_arch_init(void *data) | |||
130 | *(unsigned long *)data = 0; | 136 | *(unsigned long *)data = 0; |
131 | return 0; | 137 | return 0; |
132 | } | 138 | } |
139 | |||
140 | #endif /* CONFIG_DYNAMIC_FTRACE */ | ||
141 | |||
142 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
143 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
144 | /* | ||
145 | * Patch the kernel code at ftrace_graph_caller location: | ||
146 | * The instruction there is branch relative on condition. The condition mask | ||
147 | * is either all ones (always branch aka disable ftrace_graph_caller) or all | ||
148 | * zeroes (nop aka enable ftrace_graph_caller). | ||
149 | * Instruction format for brc is a7m4xxxx where m is the condition mask. | ||
150 | */ | ||
151 | int ftrace_enable_ftrace_graph_caller(void) | ||
152 | { | ||
153 | unsigned short opcode = 0xa704; | ||
154 | |||
155 | return probe_kernel_write(ftrace_graph_caller, &opcode, sizeof(opcode)); | ||
156 | } | ||
157 | |||
158 | int ftrace_disable_ftrace_graph_caller(void) | ||
159 | { | ||
160 | unsigned short opcode = 0xa7f4; | ||
161 | |||
162 | return probe_kernel_write(ftrace_graph_caller, &opcode, sizeof(opcode)); | ||
163 | } | ||
164 | |||
165 | static inline unsigned long ftrace_mcount_call_adjust(unsigned long addr) | ||
166 | { | ||
167 | return addr - (ftrace_disable_return - ftrace_disable_code); | ||
168 | } | ||
169 | |||
170 | #else /* CONFIG_DYNAMIC_FTRACE */ | ||
171 | |||
172 | static inline unsigned long ftrace_mcount_call_adjust(unsigned long addr) | ||
173 | { | ||
174 | return addr - MCOUNT_OFFSET_RET; | ||
175 | } | ||
176 | |||
177 | #endif /* CONFIG_DYNAMIC_FTRACE */ | ||
178 | |||
179 | /* | ||
180 | * Hook the return address and push it in the stack of return addresses | ||
181 | * in current thread info. | ||
182 | */ | ||
183 | unsigned long prepare_ftrace_return(unsigned long ip, unsigned long parent) | ||
184 | { | ||
185 | struct ftrace_graph_ent trace; | ||
186 | |||
187 | /* Nmi's are currently unsupported. */ | ||
188 | if (unlikely(in_nmi())) | ||
189 | goto out; | ||
190 | if (unlikely(atomic_read(¤t->tracing_graph_pause))) | ||
191 | goto out; | ||
192 | if (ftrace_push_return_trace(parent, ip, &trace.depth) == -EBUSY) | ||
193 | goto out; | ||
194 | trace.func = ftrace_mcount_call_adjust(ip) & PSW_ADDR_INSN; | ||
195 | /* Only trace if the calling function expects to. */ | ||
196 | if (!ftrace_graph_entry(&trace)) { | ||
197 | current->curr_ret_stack--; | ||
198 | goto out; | ||
199 | } | ||
200 | parent = (unsigned long)return_to_handler; | ||
201 | out: | ||
202 | return parent; | ||
203 | } | ||
204 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
diff --git a/arch/s390/kernel/mcount.S b/arch/s390/kernel/mcount.S index 0aa85ec94d08..2a0a5e97ba8c 100644 --- a/arch/s390/kernel/mcount.S +++ b/arch/s390/kernel/mcount.S | |||
@@ -34,6 +34,18 @@ ftrace_caller: | |||
34 | larl %r14,ftrace_dyn_func | 34 | larl %r14,ftrace_dyn_func |
35 | lg %r14,0(%r14) | 35 | lg %r14,0(%r14) |
36 | basr %r14,%r14 | 36 | basr %r14,%r14 |
37 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
38 | .globl ftrace_graph_caller | ||
39 | ftrace_graph_caller: | ||
40 | # This unconditional branch gets runtime patched. Change only if | ||
41 | # you know what you are doing. See ftrace_enable_graph_caller(). | ||
42 | j 0f | ||
43 | lg %r2,272(%r15) | ||
44 | lg %r3,168(%r15) | ||
45 | brasl %r14,prepare_ftrace_return | ||
46 | stg %r2,168(%r15) | ||
47 | 0: | ||
48 | #endif | ||
37 | aghi %r15,160 | 49 | aghi %r15,160 |
38 | lmg %r2,%r5,32(%r15) | 50 | lmg %r2,%r5,32(%r15) |
39 | lg %r14,112(%r15) | 51 | lg %r14,112(%r15) |
@@ -62,6 +74,12 @@ _mcount: | |||
62 | larl %r14,ftrace_trace_function | 74 | larl %r14,ftrace_trace_function |
63 | lg %r14,0(%r14) | 75 | lg %r14,0(%r14) |
64 | basr %r14,%r14 | 76 | basr %r14,%r14 |
77 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
78 | lg %r2,272(%r15) | ||
79 | lg %r3,168(%r15) | ||
80 | brasl %r14,prepare_ftrace_return | ||
81 | stg %r2,168(%r15) | ||
82 | #endif | ||
65 | aghi %r15,160 | 83 | aghi %r15,160 |
66 | lmg %r2,%r5,32(%r15) | 84 | lmg %r2,%r5,32(%r15) |
67 | lg %r14,112(%r15) | 85 | lg %r14,112(%r15) |
@@ -69,6 +87,22 @@ _mcount: | |||
69 | 87 | ||
70 | #endif /* CONFIG_DYNAMIC_FTRACE */ | 88 | #endif /* CONFIG_DYNAMIC_FTRACE */ |
71 | 89 | ||
90 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
91 | |||
92 | .globl return_to_handler | ||
93 | return_to_handler: | ||
94 | stmg %r2,%r5,32(%r15) | ||
95 | lgr %r1,%r15 | ||
96 | aghi %r15,-160 | ||
97 | stg %r1,__SF_BACKCHAIN(%r15) | ||
98 | brasl %r14,ftrace_return_to_handler | ||
99 | aghi %r15,160 | ||
100 | lgr %r14,%r2 | ||
101 | lmg %r2,%r5,32(%r15) | ||
102 | br %r14 | ||
103 | |||
104 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
105 | |||
72 | #else /* CONFIG_64BIT */ | 106 | #else /* CONFIG_64BIT */ |
73 | 107 | ||
74 | #ifdef CONFIG_DYNAMIC_FTRACE | 108 | #ifdef CONFIG_DYNAMIC_FTRACE |
@@ -96,6 +130,21 @@ ftrace_caller: | |||
96 | l %r14,0b-0b(%r1) | 130 | l %r14,0b-0b(%r1) |
97 | l %r14,0(%r14) | 131 | l %r14,0(%r14) |
98 | basr %r14,%r14 | 132 | basr %r14,%r14 |
133 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
134 | .globl ftrace_graph_caller | ||
135 | ftrace_graph_caller: | ||
136 | # This unconditional branch gets runtime patched. Change only if | ||
137 | # you know what you are doing. See ftrace_enable_graph_caller(). | ||
138 | j 1f | ||
139 | bras %r1,0f | ||
140 | .long prepare_ftrace_return | ||
141 | 0: l %r2,152(%r15) | ||
142 | l %r4,0(%r1) | ||
143 | l %r3,100(%r15) | ||
144 | basr %r14,%r4 | ||
145 | st %r2,100(%r15) | ||
146 | 1: | ||
147 | #endif | ||
99 | ahi %r15,96 | 148 | ahi %r15,96 |
100 | l %r14,56(%r15) | 149 | l %r14,56(%r15) |
101 | 3: lm %r2,%r5,16(%r15) | 150 | 3: lm %r2,%r5,16(%r15) |
@@ -128,10 +177,40 @@ _mcount: | |||
128 | l %r14,0b-0b(%r1) | 177 | l %r14,0b-0b(%r1) |
129 | l %r14,0(%r14) | 178 | l %r14,0(%r14) |
130 | basr %r14,%r14 | 179 | basr %r14,%r14 |
180 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
181 | bras %r1,0f | ||
182 | .long prepare_ftrace_return | ||
183 | 0: l %r2,152(%r15) | ||
184 | l %r4,0(%r1) | ||
185 | l %r3,100(%r15) | ||
186 | basr %r14,%r4 | ||
187 | st %r2,100(%r15) | ||
188 | #endif | ||
131 | ahi %r15,96 | 189 | ahi %r15,96 |
132 | l %r14,56(%r15) | 190 | l %r14,56(%r15) |
133 | 3: lm %r2,%r5,16(%r15) | 191 | 3: lm %r2,%r5,16(%r15) |
134 | br %r14 | 192 | br %r14 |
135 | 193 | ||
136 | #endif /* CONFIG_DYNAMIC_FTRACE */ | 194 | #endif /* CONFIG_DYNAMIC_FTRACE */ |
195 | |||
196 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
197 | |||
198 | .globl return_to_handler | ||
199 | return_to_handler: | ||
200 | stm %r2,%r5,16(%r15) | ||
201 | st %r14,56(%r15) | ||
202 | lr %r0,%r15 | ||
203 | ahi %r15,-96 | ||
204 | st %r0,__SF_BACKCHAIN(%r15) | ||
205 | bras %r1,0f | ||
206 | .long ftrace_return_to_handler | ||
207 | 0: l %r2,0b-0b(%r1) | ||
208 | basr %r14,%r2 | ||
209 | lr %r14,%r2 | ||
210 | ahi %r15,96 | ||
211 | lm %r2,%r5,16(%r15) | ||
212 | br %r14 | ||
213 | |||
214 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
215 | |||
137 | #endif /* CONFIG_64BIT */ | 216 | #endif /* CONFIG_64BIT */ |
diff --git a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c index 6b0686d78fc7..0de305b598ce 100644 --- a/arch/s390/kernel/s390_ext.c +++ b/arch/s390/kernel/s390_ext.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
13 | #include <linux/ftrace.h> | ||
13 | #include <linux/errno.h> | 14 | #include <linux/errno.h> |
14 | #include <linux/kernel_stat.h> | 15 | #include <linux/kernel_stat.h> |
15 | #include <linux/interrupt.h> | 16 | #include <linux/interrupt.h> |
@@ -112,7 +113,7 @@ int unregister_early_external_interrupt(__u16 code, ext_int_handler_t handler, | |||
112 | return 0; | 113 | return 0; |
113 | } | 114 | } |
114 | 115 | ||
115 | void do_extint(struct pt_regs *regs, unsigned short code) | 116 | void __irq_entry do_extint(struct pt_regs *regs, unsigned short code) |
116 | { | 117 | { |
117 | ext_int_info_t *p; | 118 | ext_int_info_t *p; |
118 | int index; | 119 | int index; |
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index ad9a999aaa92..215330a2c128 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c | |||
@@ -70,7 +70,7 @@ static DEFINE_PER_CPU(struct clock_event_device, comparators); | |||
70 | /* | 70 | /* |
71 | * Scheduler clock - returns current time in nanosec units. | 71 | * Scheduler clock - returns current time in nanosec units. |
72 | */ | 72 | */ |
73 | unsigned long long sched_clock(void) | 73 | unsigned long long notrace sched_clock(void) |
74 | { | 74 | { |
75 | return ((get_clock_xt() - sched_clock_base_cc) * 125) >> 9; | 75 | return ((get_clock_xt() - sched_clock_base_cc) * 125) >> 9; |
76 | } | 76 | } |
diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S index 89399b8756c2..a53db23ee092 100644 --- a/arch/s390/kernel/vmlinux.lds.S +++ b/arch/s390/kernel/vmlinux.lds.S | |||
@@ -34,6 +34,7 @@ SECTIONS | |||
34 | SCHED_TEXT | 34 | SCHED_TEXT |
35 | LOCK_TEXT | 35 | LOCK_TEXT |
36 | KPROBES_TEXT | 36 | KPROBES_TEXT |
37 | IRQENTRY_TEXT | ||
37 | *(.fixup) | 38 | *(.fixup) |
38 | *(.gnu.warning) | 39 | *(.gnu.warning) |
39 | } :text = 0x0700 | 40 | } :text = 0x0700 |