aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390')
-rw-r--r--arch/s390/Kconfig2
-rw-r--r--arch/s390/include/asm/ftrace.h19
-rw-r--r--arch/s390/include/asm/lowcore.h8
-rw-r--r--arch/s390/kernel/Makefile5
-rw-r--r--arch/s390/kernel/early.c4
-rw-r--r--arch/s390/kernel/ftrace.c132
-rw-r--r--arch/s390/kernel/mcount.S119
-rw-r--r--arch/s390/kernel/setup.c2
-rw-r--r--arch/s390/kernel/smp.c1
9 files changed, 263 insertions, 29 deletions
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 1094787e97e5..b674e79044a0 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -82,6 +82,8 @@ config S390
82 select USE_GENERIC_SMP_HELPERS if SMP 82 select USE_GENERIC_SMP_HELPERS if SMP
83 select HAVE_SYSCALL_WRAPPERS 83 select HAVE_SYSCALL_WRAPPERS
84 select HAVE_FUNCTION_TRACER 84 select HAVE_FUNCTION_TRACER
85 select HAVE_FTRACE_MCOUNT_RECORD
86 select HAVE_DYNAMIC_FTRACE
85 select HAVE_DEFAULT_NO_SPIN_MUTEXES 87 select HAVE_DEFAULT_NO_SPIN_MUTEXES
86 select HAVE_OPROFILE 88 select HAVE_OPROFILE
87 select HAVE_KPROBES 89 select HAVE_KPROBES
diff --git a/arch/s390/include/asm/ftrace.h b/arch/s390/include/asm/ftrace.h
index 5a5bc75e19d4..ba23d8f97d07 100644
--- a/arch/s390/include/asm/ftrace.h
+++ b/arch/s390/include/asm/ftrace.h
@@ -2,7 +2,26 @@
2#define _ASM_S390_FTRACE_H 2#define _ASM_S390_FTRACE_H
3 3
4#ifndef __ASSEMBLY__ 4#ifndef __ASSEMBLY__
5
5extern void _mcount(void); 6extern void _mcount(void);
7extern unsigned long ftrace_dyn_func;
8
9struct dyn_arch_ftrace { };
10
11#define MCOUNT_ADDR ((long)_mcount)
12
13#ifdef CONFIG_64BIT
14#define MCOUNT_INSN_SIZE 24
15#define MCOUNT_OFFSET 14
16#else
17#define MCOUNT_INSN_SIZE 30
18#define MCOUNT_OFFSET 8
6#endif 19#endif
7 20
21static inline unsigned long ftrace_call_adjust(unsigned long addr)
22{
23 return addr - MCOUNT_OFFSET;
24}
25
26#endif /* __ASSEMBLY__ */
8#endif /* _ASM_S390_FTRACE_H */ 27#endif /* _ASM_S390_FTRACE_H */
diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h
index 713fe9fb1fcc..5046ad6b7a63 100644
--- a/arch/s390/include/asm/lowcore.h
+++ b/arch/s390/include/asm/lowcore.h
@@ -68,6 +68,7 @@
68#define __LC_CPUID 0x02b0 68#define __LC_CPUID 0x02b0
69#define __LC_INT_CLOCK 0x02c8 69#define __LC_INT_CLOCK 0x02c8
70#define __LC_MACHINE_FLAGS 0x02d8 70#define __LC_MACHINE_FLAGS 0x02d8
71#define __LC_FTRACE_FUNC 0x02dc
71#define __LC_IRB 0x0300 72#define __LC_IRB 0x0300
72#define __LC_PFAULT_INTPARM 0x0080 73#define __LC_PFAULT_INTPARM 0x0080
73#define __LC_CPU_TIMER_SAVE_AREA 0x00d8 74#define __LC_CPU_TIMER_SAVE_AREA 0x00d8
@@ -113,6 +114,7 @@
113#define __LC_INT_CLOCK 0x0340 114#define __LC_INT_CLOCK 0x0340
114#define __LC_VDSO_PER_CPU 0x0350 115#define __LC_VDSO_PER_CPU 0x0350
115#define __LC_MACHINE_FLAGS 0x0358 116#define __LC_MACHINE_FLAGS 0x0358
117#define __LC_FTRACE_FUNC 0x0360
116#define __LC_IRB 0x0380 118#define __LC_IRB 0x0380
117#define __LC_PASTE 0x03c0 119#define __LC_PASTE 0x03c0
118#define __LC_PFAULT_INTPARM 0x11b8 120#define __LC_PFAULT_INTPARM 0x11b8
@@ -281,7 +283,8 @@ struct _lowcore
281 __u64 int_clock; /* 0x02c8 */ 283 __u64 int_clock; /* 0x02c8 */
282 __u64 clock_comparator; /* 0x02d0 */ 284 __u64 clock_comparator; /* 0x02d0 */
283 __u32 machine_flags; /* 0x02d8 */ 285 __u32 machine_flags; /* 0x02d8 */
284 __u8 pad_0x02dc[0x0300-0x02dc]; /* 0x02dc */ 286 __u32 ftrace_func; /* 0x02dc */
287 __u8 pad_0x02f0[0x0300-0x02f0]; /* 0x02f0 */
285 288
286 /* Interrupt response block */ 289 /* Interrupt response block */
287 __u8 irb[64]; /* 0x0300 */ 290 __u8 irb[64]; /* 0x0300 */
@@ -386,7 +389,8 @@ struct _lowcore
386 __u64 clock_comparator; /* 0x0348 */ 389 __u64 clock_comparator; /* 0x0348 */
387 __u64 vdso_per_cpu_data; /* 0x0350 */ 390 __u64 vdso_per_cpu_data; /* 0x0350 */
388 __u64 machine_flags; /* 0x0358 */ 391 __u64 machine_flags; /* 0x0358 */
389 __u8 pad_0x0360[0x0380-0x0360]; /* 0x0360 */ 392 __u64 ftrace_func; /* 0x0360 */
393 __u8 pad_0x0368[0x0380-0x0368]; /* 0x0368 */
390 394
391 /* Interrupt response block. */ 395 /* Interrupt response block. */
392 __u8 irb[64]; /* 0x0380 */ 396 __u8 irb[64]; /* 0x0380 */
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
index 0657de7944fe..ce172bfaab8a 100644
--- a/arch/s390/kernel/Makefile
+++ b/arch/s390/kernel/Makefile
@@ -7,6 +7,10 @@ ifdef CONFIG_FUNCTION_TRACER
7CFLAGS_REMOVE_early.o = -pg 7CFLAGS_REMOVE_early.o = -pg
8endif 8endif
9 9
10ifdef CONFIG_DYNAMIC_FTRACE
11CFLAGS_REMOVE_ftrace.o = -pg
12endif
13
10# 14#
11# Passing null pointers is ok for smp code, since we access the lowcore here. 15# Passing null pointers is ok for smp code, since we access the lowcore here.
12# 16#
@@ -41,6 +45,7 @@ obj-$(CONFIG_COMPAT) += compat_linux.o compat_signal.o \
41obj-$(CONFIG_STACKTRACE) += stacktrace.o 45obj-$(CONFIG_STACKTRACE) += stacktrace.o
42obj-$(CONFIG_KPROBES) += kprobes.o 46obj-$(CONFIG_KPROBES) += kprobes.o
43obj-$(CONFIG_FUNCTION_TRACER) += mcount.o 47obj-$(CONFIG_FUNCTION_TRACER) += mcount.o
48obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
44 49
45# Kexec part 50# Kexec part
46S390_KEXEC_OBJS := machine_kexec.o crash.o 51S390_KEXEC_OBJS := machine_kexec.o crash.o
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
index cf09948faad6..fb263736826c 100644
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -11,6 +11,7 @@
11#include <linux/errno.h> 11#include <linux/errno.h>
12#include <linux/string.h> 12#include <linux/string.h>
13#include <linux/ctype.h> 13#include <linux/ctype.h>
14#include <linux/ftrace.h>
14#include <linux/lockdep.h> 15#include <linux/lockdep.h>
15#include <linux/module.h> 16#include <linux/module.h>
16#include <linux/pfn.h> 17#include <linux/pfn.h>
@@ -410,5 +411,8 @@ void __init startup_init(void)
410 sclp_facilities_detect(); 411 sclp_facilities_detect();
411 detect_memory_layout(memory_chunk); 412 detect_memory_layout(memory_chunk);
412 S390_lowcore.machine_flags = machine_flags; 413 S390_lowcore.machine_flags = machine_flags;
414#ifdef CONFIG_DYNAMIC_FTRACE
415 S390_lowcore.ftrace_func = (unsigned long)ftrace_caller;
416#endif
413 lockdep_on(); 417 lockdep_on();
414} 418}
diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c
new file mode 100644
index 000000000000..0b81a784e039
--- /dev/null
+++ b/arch/s390/kernel/ftrace.c
@@ -0,0 +1,132 @@
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
16void ftrace_disable_code(void);
17void ftrace_call_code(void);
18void ftrace_nop_code(void);
19
20#define FTRACE_INSN_SIZE 4
21
22#ifdef CONFIG_64BIT
23
24asm(
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
35asm(
36 " .align 4\n"
37 "ftrace_nop_code:\n"
38 " j .+"__stringify(MCOUNT_INSN_SIZE)"\n");
39
40asm(
41 " .align 4\n"
42 "ftrace_call_code:\n"
43 " stg %r14,8(%r15)\n");
44
45#else /* CONFIG_64BIT */
46
47asm(
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
63asm(
64 " .align 4\n"
65 "ftrace_nop_code:\n"
66 " j .+"__stringify(MCOUNT_INSN_SIZE)"\n");
67
68asm(
69 " .align 4\n"
70 "ftrace_call_code:\n"
71 " st %r14,4(%r15)\n");
72
73#endif /* CONFIG_64BIT */
74
75static 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
97static 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
105int 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
115int 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
122int ftrace_update_ftrace_func(ftrace_func_t func)
123{
124 ftrace_dyn_func = (unsigned long)func;
125 return 0;
126}
127
128int __init ftrace_dyn_arch_init(void *data)
129{
130 *(unsigned long *)data = 0;
131 return 0;
132}
diff --git a/arch/s390/kernel/mcount.S b/arch/s390/kernel/mcount.S
index 80641224a095..de274996f640 100644
--- a/arch/s390/kernel/mcount.S
+++ b/arch/s390/kernel/mcount.S
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright IBM Corp. 2008 2 * Copyright IBM Corp. 2008,2009
3 * 3 *
4 * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>, 4 * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
5 * 5 *
@@ -7,36 +7,46 @@
7 7
8#include <asm/asm-offsets.h> 8#include <asm/asm-offsets.h>
9 9
10#ifndef CONFIG_64BIT 10 .globl ftrace_stub
11.globl _mcount 11ftrace_stub:
12 br %r14
13
14#ifdef CONFIG_64BIT
15
16#ifdef CONFIG_DYNAMIC_FTRACE
17
18 .globl _mcount
12_mcount: 19_mcount:
13 stm %r0,%r5,8(%r15)
14 st %r14,56(%r15)
15 lr %r1,%r15
16 ahi %r15,-96
17 l %r3,100(%r15)
18 la %r2,0(%r14)
19 st %r1,__SF_BACKCHAIN(%r15)
20 la %r3,0(%r3)
21 bras %r14,0f
22 .long ftrace_trace_function
230: l %r14,0(%r14)
24 l %r14,0(%r14)
25 basr %r14,%r14
26 ahi %r15,96
27 lm %r0,%r5,8(%r15)
28 l %r14,56(%r15)
29 br %r14 20 br %r14
30 21
31.globl ftrace_stub 22 .globl ftrace_caller
32ftrace_stub: 23ftrace_caller:
24 stmg %r2,%r5,32(%r15)
25 stg %r14,112(%r15)
26 lgr %r1,%r15
27 aghi %r15,-160
28 stg %r1,__SF_BACKCHAIN(%r15)
29 lgr %r2,%r14
30 lg %r3,168(%r15)
31 larl %r14,ftrace_dyn_func
32 lg %r14,0(%r14)
33 basr %r14,%r14
34 aghi %r15,160
35 lmg %r2,%r5,32(%r15)
36 lg %r14,112(%r15)
33 br %r14 37 br %r14
34 38
35#else /* CONFIG_64BIT */ 39 .data
40 .globl ftrace_dyn_func
41ftrace_dyn_func:
42 .quad ftrace_stub
43 .previous
44
45#else /* CONFIG_DYNAMIC_FTRACE */
36 46
37.globl _mcount 47 .globl _mcount
38_mcount: 48_mcount:
39 stmg %r0,%r5,16(%r15) 49 stmg %r2,%r5,32(%r15)
40 stg %r14,112(%r15) 50 stg %r14,112(%r15)
41 lgr %r1,%r15 51 lgr %r1,%r15
42 aghi %r15,-160 52 aghi %r15,-160
@@ -47,12 +57,67 @@ _mcount:
47 lg %r14,0(%r14) 57 lg %r14,0(%r14)
48 basr %r14,%r14 58 basr %r14,%r14
49 aghi %r15,160 59 aghi %r15,160
50 lmg %r0,%r5,16(%r15) 60 lmg %r2,%r5,32(%r15)
51 lg %r14,112(%r15) 61 lg %r14,112(%r15)
52 br %r14 62 br %r14
53 63
54.globl ftrace_stub 64#endif /* CONFIG_DYNAMIC_FTRACE */
55ftrace_stub: 65
66#else /* CONFIG_64BIT */
67
68#ifdef CONFIG_DYNAMIC_FTRACE
69
70 .globl _mcount
71_mcount:
72 br %r14
73
74 .globl ftrace_caller
75ftrace_caller:
76 stm %r2,%r5,16(%r15)
77 st %r14,56(%r15)
78 lr %r1,%r15
79 ahi %r15,-96
80 l %r3,100(%r15)
81 la %r2,0(%r14)
82 st %r1,__SF_BACKCHAIN(%r15)
83 la %r3,0(%r3)
84 bras %r14,0f
85 .long ftrace_dyn_func
860: l %r14,0(%r14)
87 l %r14,0(%r14)
88 basr %r14,%r14
89 ahi %r15,96
90 lm %r2,%r5,16(%r15)
91 l %r14,56(%r15)
92 br %r14
93
94 .data
95 .globl ftrace_dyn_func
96ftrace_dyn_func:
97 .long ftrace_stub
98 .previous
99
100#else /* CONFIG_DYNAMIC_FTRACE */
101
102 .globl _mcount
103_mcount:
104 stm %r2,%r5,16(%r15)
105 st %r14,56(%r15)
106 lr %r1,%r15
107 ahi %r15,-96
108 l %r3,100(%r15)
109 la %r2,0(%r14)
110 st %r1,__SF_BACKCHAIN(%r15)
111 la %r3,0(%r3)
112 bras %r14,0f
113 .long ftrace_trace_function
1140: l %r14,0(%r14)
115 l %r14,0(%r14)
116 basr %r14,%r14
117 ahi %r15,96
118 lm %r2,%r5,16(%r15)
119 l %r14,56(%r15)
56 br %r14 120 br %r14
57 121
122#endif /* CONFIG_DYNAMIC_FTRACE */
58#endif /* CONFIG_64BIT */ 123#endif /* CONFIG_64BIT */
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 7402b6a39ead..9717717c6fea 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -42,6 +42,7 @@
42#include <linux/ctype.h> 42#include <linux/ctype.h>
43#include <linux/reboot.h> 43#include <linux/reboot.h>
44#include <linux/topology.h> 44#include <linux/topology.h>
45#include <linux/ftrace.h>
45 46
46#include <asm/ipl.h> 47#include <asm/ipl.h>
47#include <asm/uaccess.h> 48#include <asm/uaccess.h>
@@ -442,6 +443,7 @@ setup_lowcore(void)
442 lc->steal_timer = S390_lowcore.steal_timer; 443 lc->steal_timer = S390_lowcore.steal_timer;
443 lc->last_update_timer = S390_lowcore.last_update_timer; 444 lc->last_update_timer = S390_lowcore.last_update_timer;
444 lc->last_update_clock = S390_lowcore.last_update_clock; 445 lc->last_update_clock = S390_lowcore.last_update_clock;
446 lc->ftrace_func = S390_lowcore.ftrace_func;
445 set_prefix((u32)(unsigned long) lc); 447 set_prefix((u32)(unsigned long) lc);
446 lowcore_ptr[0] = lc; 448 lowcore_ptr[0] = lc;
447} 449}
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 0af302ceac2d..cc8c484984e3 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -572,6 +572,7 @@ int __cpuinit __cpu_up(unsigned int cpu)
572 cpu_lowcore->cpu_nr = cpu; 572 cpu_lowcore->cpu_nr = cpu;
573 cpu_lowcore->kernel_asce = S390_lowcore.kernel_asce; 573 cpu_lowcore->kernel_asce = S390_lowcore.kernel_asce;
574 cpu_lowcore->machine_flags = S390_lowcore.machine_flags; 574 cpu_lowcore->machine_flags = S390_lowcore.machine_flags;
575 cpu_lowcore->ftrace_func = S390_lowcore.ftrace_func;
575 eieio(); 576 eieio();
576 577
577 while (signal_processor(cpu, sigp_restart) == sigp_busy) 578 while (signal_processor(cpu, sigp_restart) == sigp_busy)