Skip to content

Commit

Permalink
[S390] ftrace: add dynamic ftrace support
Browse files Browse the repository at this point in the history
Dynamic ftrace support for s390.

Signed-off-by: Heiko Carstens <[email protected]>
Signed-off-by: Martin Schwidefsky <[email protected]>
  • Loading branch information
heicarst authored and Martin Schwidefsky committed Jun 12, 2009
1 parent a2b5367 commit dfd9f7a
Show file tree
Hide file tree
Showing 10 changed files with 276 additions and 29 deletions.
2 changes: 2 additions & 0 deletions arch/s390/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ config S390
select USE_GENERIC_SMP_HELPERS if SMP
select HAVE_SYSCALL_WRAPPERS
select HAVE_FUNCTION_TRACER
select HAVE_FTRACE_MCOUNT_RECORD
select HAVE_DYNAMIC_FTRACE
select HAVE_DEFAULT_NO_SPIN_MUTEXES
select HAVE_OPROFILE
select HAVE_KPROBES
Expand Down
19 changes: 19 additions & 0 deletions arch/s390/include/asm/ftrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,26 @@
#define _ASM_S390_FTRACE_H

#ifndef __ASSEMBLY__

extern void _mcount(void);
extern unsigned long ftrace_dyn_func;

struct dyn_arch_ftrace { };

#define MCOUNT_ADDR ((long)_mcount)

#ifdef CONFIG_64BIT
#define MCOUNT_INSN_SIZE 24
#define MCOUNT_OFFSET 14
#else
#define MCOUNT_INSN_SIZE 30
#define MCOUNT_OFFSET 8
#endif

static inline unsigned long ftrace_call_adjust(unsigned long addr)
{
return addr - MCOUNT_OFFSET;
}

#endif /* __ASSEMBLY__ */
#endif /* _ASM_S390_FTRACE_H */
8 changes: 6 additions & 2 deletions arch/s390/include/asm/lowcore.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
#define __LC_CPUID 0x02b0
#define __LC_INT_CLOCK 0x02c8
#define __LC_MACHINE_FLAGS 0x02d8
#define __LC_FTRACE_FUNC 0x02dc
#define __LC_IRB 0x0300
#define __LC_PFAULT_INTPARM 0x0080
#define __LC_CPU_TIMER_SAVE_AREA 0x00d8
Expand Down Expand Up @@ -113,6 +114,7 @@
#define __LC_INT_CLOCK 0x0340
#define __LC_VDSO_PER_CPU 0x0350
#define __LC_MACHINE_FLAGS 0x0358
#define __LC_FTRACE_FUNC 0x0360
#define __LC_IRB 0x0380
#define __LC_PASTE 0x03c0
#define __LC_PFAULT_INTPARM 0x11b8
Expand Down Expand Up @@ -281,7 +283,8 @@ struct _lowcore
__u64 int_clock; /* 0x02c8 */
__u64 clock_comparator; /* 0x02d0 */
__u32 machine_flags; /* 0x02d8 */
__u8 pad_0x02dc[0x0300-0x02dc]; /* 0x02dc */
__u32 ftrace_func; /* 0x02dc */
__u8 pad_0x02f0[0x0300-0x02f0]; /* 0x02f0 */

/* Interrupt response block */
__u8 irb[64]; /* 0x0300 */
Expand Down Expand Up @@ -386,7 +389,8 @@ struct _lowcore
__u64 clock_comparator; /* 0x0348 */
__u64 vdso_per_cpu_data; /* 0x0350 */
__u64 machine_flags; /* 0x0358 */
__u8 pad_0x0360[0x0380-0x0360]; /* 0x0360 */
__u64 ftrace_func; /* 0x0360 */
__u8 pad_0x0368[0x0380-0x0368]; /* 0x0368 */

/* Interrupt response block. */
__u8 irb[64]; /* 0x0380 */
Expand Down
5 changes: 5 additions & 0 deletions arch/s390/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ ifdef CONFIG_FUNCTION_TRACER
CFLAGS_REMOVE_early.o = -pg
endif

ifdef CONFIG_DYNAMIC_FTRACE
CFLAGS_REMOVE_ftrace.o = -pg
endif

#
# Passing null pointers is ok for smp code, since we access the lowcore here.
#
Expand Down Expand Up @@ -41,6 +45,7 @@ obj-$(CONFIG_COMPAT) += compat_linux.o compat_signal.o \
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_KPROBES) += kprobes.o
obj-$(CONFIG_FUNCTION_TRACER) += mcount.o
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o

# Kexec part
S390_KEXEC_OBJS := machine_kexec.o crash.o
Expand Down
4 changes: 4 additions & 0 deletions arch/s390/kernel/early.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/ftrace.h>
#include <linux/lockdep.h>
#include <linux/module.h>
#include <linux/pfn.h>
Expand Down Expand Up @@ -410,5 +411,8 @@ void __init startup_init(void)
sclp_facilities_detect();
detect_memory_layout(memory_chunk);
S390_lowcore.machine_flags = machine_flags;
#ifdef CONFIG_DYNAMIC_FTRACE
S390_lowcore.ftrace_func = (unsigned long)ftrace_caller;
#endif
lockdep_on();
}
132 changes: 132 additions & 0 deletions arch/s390/kernel/ftrace.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/*
* Dynamic function tracer architecture backend.
*
* Copyright IBM Corp. 2009
*
* Author(s): Heiko Carstens <[email protected]>,
*
*/

#include <linux/uaccess.h>
#include <linux/ftrace.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <asm/lowcore.h>

void ftrace_disable_code(void);
void ftrace_call_code(void);
void ftrace_nop_code(void);

#define FTRACE_INSN_SIZE 4

#ifdef CONFIG_64BIT

asm(
" .align 4\n"
"ftrace_disable_code:\n"
" j 0f\n"
" .word 0x0024\n"
" lg %r1,"__stringify(__LC_FTRACE_FUNC)"\n"
" basr %r14,%r1\n"
" lg %r14,8(15)\n"
" lgr %r0,%r0\n"
"0:\n");

asm(
" .align 4\n"
"ftrace_nop_code:\n"
" j .+"__stringify(MCOUNT_INSN_SIZE)"\n");

asm(
" .align 4\n"
"ftrace_call_code:\n"
" stg %r14,8(%r15)\n");

#else /* CONFIG_64BIT */

asm(
" .align 4\n"
"ftrace_disable_code:\n"
" j 0f\n"
" l %r1,"__stringify(__LC_FTRACE_FUNC)"\n"
" basr %r14,%r1\n"
" l %r14,4(%r15)\n"
" j 0f\n"
" bcr 0,%r7\n"
" bcr 0,%r7\n"
" bcr 0,%r7\n"
" bcr 0,%r7\n"
" bcr 0,%r7\n"
" bcr 0,%r7\n"
"0:\n");

asm(
" .align 4\n"
"ftrace_nop_code:\n"
" j .+"__stringify(MCOUNT_INSN_SIZE)"\n");

asm(
" .align 4\n"
"ftrace_call_code:\n"
" st %r14,4(%r15)\n");

#endif /* CONFIG_64BIT */

static int ftrace_modify_code(unsigned long ip,
void *old_code, int old_size,
void *new_code, int new_size)
{
unsigned char replaced[MCOUNT_INSN_SIZE];

/*
* Note: Due to modules code can disappear and change.
* We need to protect against faulting as well as code
* changing. We do this by using the probe_kernel_*
* functions.
* This however is just a simple sanity check.
*/
if (probe_kernel_read(replaced, (void *)ip, old_size))
return -EFAULT;
if (memcmp(replaced, old_code, old_size) != 0)
return -EINVAL;
if (probe_kernel_write((void *)ip, new_code, new_size))
return -EPERM;
return 0;
}

static int ftrace_make_initial_nop(struct module *mod, struct dyn_ftrace *rec,
unsigned long addr)
{
return ftrace_modify_code(rec->ip,
ftrace_call_code, FTRACE_INSN_SIZE,
ftrace_disable_code, MCOUNT_INSN_SIZE);
}

int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
unsigned long addr)
{
if (addr == MCOUNT_ADDR)
return ftrace_make_initial_nop(mod, rec, addr);
return ftrace_modify_code(rec->ip,
ftrace_call_code, FTRACE_INSN_SIZE,
ftrace_nop_code, FTRACE_INSN_SIZE);
}

int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
{
return ftrace_modify_code(rec->ip,
ftrace_nop_code, FTRACE_INSN_SIZE,
ftrace_call_code, FTRACE_INSN_SIZE);
}

int ftrace_update_ftrace_func(ftrace_func_t func)
{
ftrace_dyn_func = (unsigned long)func;
return 0;
}

int __init ftrace_dyn_arch_init(void *data)
{
*(unsigned long *)data = 0;
return 0;
}
119 changes: 92 additions & 27 deletions arch/s390/kernel/mcount.S
Original file line number Diff line number Diff line change
@@ -1,42 +1,52 @@
/*
* Copyright IBM Corp. 2008
* Copyright IBM Corp. 2008,2009
*
* Author(s): Heiko Carstens <[email protected]>,
*
*/

#include <asm/asm-offsets.h>

#ifndef CONFIG_64BIT
.globl _mcount
.globl ftrace_stub
ftrace_stub:
br %r14

#ifdef CONFIG_64BIT

#ifdef CONFIG_DYNAMIC_FTRACE

.globl _mcount
_mcount:
stm %r0,%r5,8(%r15)
st %r14,56(%r15)
lr %r1,%r15
ahi %r15,-96
l %r3,100(%r15)
la %r2,0(%r14)
st %r1,__SF_BACKCHAIN(%r15)
la %r3,0(%r3)
bras %r14,0f
.long ftrace_trace_function
0: l %r14,0(%r14)
l %r14,0(%r14)
basr %r14,%r14
ahi %r15,96
lm %r0,%r5,8(%r15)
l %r14,56(%r15)
br %r14

.globl ftrace_stub
ftrace_stub:
.globl ftrace_caller
ftrace_caller:
stmg %r2,%r5,32(%r15)
stg %r14,112(%r15)
lgr %r1,%r15
aghi %r15,-160
stg %r1,__SF_BACKCHAIN(%r15)
lgr %r2,%r14
lg %r3,168(%r15)
larl %r14,ftrace_dyn_func
lg %r14,0(%r14)
basr %r14,%r14
aghi %r15,160
lmg %r2,%r5,32(%r15)
lg %r14,112(%r15)
br %r14

#else /* CONFIG_64BIT */
.data
.globl ftrace_dyn_func
ftrace_dyn_func:
.quad ftrace_stub
.previous

#else /* CONFIG_DYNAMIC_FTRACE */

.globl _mcount
.globl _mcount
_mcount:
stmg %r0,%r5,16(%r15)
stmg %r2,%r5,32(%r15)
stg %r14,112(%r15)
lgr %r1,%r15
aghi %r15,-160
Expand All @@ -47,12 +57,67 @@ _mcount:
lg %r14,0(%r14)
basr %r14,%r14
aghi %r15,160
lmg %r0,%r5,16(%r15)
lmg %r2,%r5,32(%r15)
lg %r14,112(%r15)
br %r14

.globl ftrace_stub
ftrace_stub:
#endif /* CONFIG_DYNAMIC_FTRACE */

#else /* CONFIG_64BIT */

#ifdef CONFIG_DYNAMIC_FTRACE

.globl _mcount
_mcount:
br %r14

.globl ftrace_caller
ftrace_caller:
stm %r2,%r5,16(%r15)
st %r14,56(%r15)
lr %r1,%r15
ahi %r15,-96
l %r3,100(%r15)
la %r2,0(%r14)
st %r1,__SF_BACKCHAIN(%r15)
la %r3,0(%r3)
bras %r14,0f
.long ftrace_dyn_func
0: l %r14,0(%r14)
l %r14,0(%r14)
basr %r14,%r14
ahi %r15,96
lm %r2,%r5,16(%r15)
l %r14,56(%r15)
br %r14

.data
.globl ftrace_dyn_func
ftrace_dyn_func:
.long ftrace_stub
.previous

#else /* CONFIG_DYNAMIC_FTRACE */

.globl _mcount
_mcount:
stm %r2,%r5,16(%r15)
st %r14,56(%r15)
lr %r1,%r15
ahi %r15,-96
l %r3,100(%r15)
la %r2,0(%r14)
st %r1,__SF_BACKCHAIN(%r15)
la %r3,0(%r3)
bras %r14,0f
.long ftrace_trace_function
0: l %r14,0(%r14)
l %r14,0(%r14)
basr %r14,%r14
ahi %r15,96
lm %r2,%r5,16(%r15)
l %r14,56(%r15)
br %r14

#endif /* CONFIG_DYNAMIC_FTRACE */
#endif /* CONFIG_64BIT */
Loading

0 comments on commit dfd9f7a

Please sign in to comment.