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/kernel | |
| 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/kernel')
| -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 |
6 files changed, 157 insertions, 6 deletions
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 |
