All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] s390: add support for DYNAMIC_FTRACE_WITH_REGS
@ 2014-07-03 12:00 Vojtech Pavlik
  2014-07-08  8:07 ` Heiko Carstens
  0 siblings, 1 reply; 8+ messages in thread
From: Vojtech Pavlik @ 2014-07-03 12:00 UTC (permalink / raw)
  To: Martin Schwidefsky, Heiko Carstens, Steven Rostedt
  Cc: Jiri Kosina, Jiri Slaby, linux390, linux-s390, linux-kernel

Add support for DYNAMIC_FTRACE_WITH_REGS to 64-bit and 31-bit s390
architectures. This is required for kGraft and kpatch to work on s390.

It's done by adding a _regs variant of ftrace_caller that preserves
registers and puts them on stack in a struct pt_regs layout and
allows modification of return address by changing the PSW (instruction
pointer) member od struct pt_regs. 

Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
Reviewed-by: Jiri Kosina <jkosina@suse.cz>
Cc: Steven Rostedt <rostedt@goodmis.org>

---

 arch/s390/Kconfig               |    1 
 arch/s390/include/asm/ftrace.h  |    4 ++
 arch/s390/include/asm/lowcore.h |   12 ++++---
 arch/s390/kernel/asm-offsets.c  |    1 
 arch/s390/kernel/early.c        |    3 +
 arch/s390/kernel/ftrace.c       |   68 +++++++++++++++++++++++++++++++++++-----
 arch/s390/kernel/mcount.S       |   43 +++++++++++++++++++++++++
 arch/s390/kernel/mcount64.S     |   38 ++++++++++++++++++++++
 arch/s390/kernel/setup.c        |    1 
 arch/s390/kernel/smp.c          |    1 
 include/linux/ftrace.h          |    1 
 11 files changed, 160 insertions(+), 13 deletions(-)

diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index bb63499..1de14d3 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -113,6 +113,7 @@ config S390
 	select HAVE_C_RECORDMCOUNT
 	select HAVE_DEBUG_KMEMLEAK
 	select HAVE_DYNAMIC_FTRACE
+	select HAVE_DYNAMIC_FTRACE_WITH_REGS
 	select HAVE_FTRACE_MCOUNT_RECORD
 	select HAVE_FUNCTION_GRAPH_TRACER
 	select HAVE_FUNCTION_TRACER
diff --git a/arch/s390/include/asm/ftrace.h b/arch/s390/include/asm/ftrace.h
index bf246da..df87fd2 100644
--- a/arch/s390/include/asm/ftrace.h
+++ b/arch/s390/include/asm/ftrace.h
@@ -17,6 +17,10 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr)
 
 #endif /* __ASSEMBLY__ */
 
+#ifdef CONFIG_DYNAMIC_FTRACE
+#define ARCH_SUPPORTS_FTRACE_OPS 1
+#endif
+
 #ifdef CONFIG_64BIT
 #define MCOUNT_INSN_SIZE  12
 #else
diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h
index 4349197..31b064a 100644
--- a/arch/s390/include/asm/lowcore.h
+++ b/arch/s390/include/asm/lowcore.h
@@ -142,9 +142,10 @@ struct _lowcore {
 	__u32	percpu_offset;			/* 0x02f0 */
 	__u32	machine_flags;			/* 0x02f4 */
 	__u32	ftrace_func;			/* 0x02f8 */
-	__u32	spinlock_lockval;		/* 0x02fc */
+	__u32	ftrace_regs_func;		/* 0x02fc */
+	__u32	spinlock_lockval;		/* 0x0300 */
 
-	__u8	pad_0x0300[0x0e00-0x0300];	/* 0x0300 */
+	__u8	pad_0x0304[0x0e00-0x0304];	/* 0x0304 */
 
 	/*
 	 * 0xe00 contains the address of the IPL Parameter Information
@@ -287,9 +288,10 @@ struct _lowcore {
 	__u64	vdso_per_cpu_data;		/* 0x0380 */
 	__u64	machine_flags;			/* 0x0388 */
 	__u64	ftrace_func;			/* 0x0390 */
-	__u64	gmap;				/* 0x0398 */
-	__u32	spinlock_lockval;		/* 0x03a0 */
-	__u8	pad_0x03a0[0x0400-0x03a4];	/* 0x03a4 */
+	__u64	ftrace_regs_func;		/* 0x0398 */
+	__u64	gmap;				/* 0x03a0 */
+	__u32	spinlock_lockval;		/* 0x03a8 */
+	__u8	pad_0x03ac[0x0400-0x03ac];	/* 0x03ac */
 
 	/* Per cpu primary space access list */
 	__u32	paste[16];			/* 0x0400 */
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c
index afe1715..12ef6ce 100644
--- a/arch/s390/kernel/asm-offsets.c
+++ b/arch/s390/kernel/asm-offsets.c
@@ -150,6 +150,7 @@ int main(void)
 	DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock));
 	DEFINE(__LC_MACHINE_FLAGS, offsetof(struct _lowcore, machine_flags));
 	DEFINE(__LC_FTRACE_FUNC, offsetof(struct _lowcore, ftrace_func));
+	DEFINE(__LC_FTRACE_REGS_FUNC, offsetof(struct _lowcore, ftrace_regs_func));
 	DEFINE(__LC_DUMP_REIPL, offsetof(struct _lowcore, ipib));
 	BLANK();
 	DEFINE(__LC_CPU_TIMER_SAVE_AREA, offsetof(struct _lowcore, cpu_timer_save_area));
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
index 0dff972..2ab52d2 100644
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -493,5 +493,8 @@ void __init startup_init(void)
 #ifdef CONFIG_DYNAMIC_FTRACE
 	S390_lowcore.ftrace_func = (unsigned long)ftrace_caller;
 #endif
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
+	S390_lowcore.ftrace_regs_func = (unsigned long)ftrace_regs_caller;
+#endif
 	lockdep_on();
 }
diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c
index 54d6493..7d1ec79 100644
--- a/arch/s390/kernel/ftrace.c
+++ b/arch/s390/kernel/ftrace.c
@@ -21,6 +21,7 @@
 
 void ftrace_disable_code(void);
 void ftrace_enable_insn(void);
+void ftrace_enable_regs_insn(void);
 
 #ifdef CONFIG_64BIT
 /*
@@ -56,7 +57,13 @@ asm(
 	"0:\n"
 	"	.align	4\n"
 	"ftrace_enable_insn:\n"
-	"	lg	%r1,"__stringify(__LC_FTRACE_FUNC)"\n");
+	"	lg	%r1,"__stringify(__LC_FTRACE_FUNC)"\n"
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
+	"	.align	4\n"
+	"ftrace_enable_regs_insn:\n"
+	"	lg	%r1,"__stringify(__LC_FTRACE_REGS_FUNC)"\n"
+#endif
+);
 
 #define FTRACE_INSN_SIZE	6
 
@@ -101,7 +108,13 @@ asm(
 	"1:\n"
 	"	.align	4\n"
 	"ftrace_enable_insn:\n"
-	"	l	%r14,"__stringify(__LC_FTRACE_FUNC)"\n");
+	"	l	%r14,"__stringify(__LC_FTRACE_FUNC)"\n"
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
+	"	.align	4\n"
+	"ftrace_enable_regs_insn:\n"
+	"	l	%r14,"__stringify(__LC_FTRACE_REGS_FUNC)"\n"
+#endif
+);
 
 #define FTRACE_INSN_SIZE	4
 
@@ -119,12 +132,29 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
 
 int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
 {
-	if (probe_kernel_write((void *) rec->ip, ftrace_enable_insn,
-			       FTRACE_INSN_SIZE))
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
+	if (rec->flags & FTRACE_FL_REGS) {
+		if (probe_kernel_write((void *) rec->ip, ftrace_enable_regs_insn,
+				       FTRACE_INSN_SIZE))
 		return -EPERM;
+	} else
+#endif
+	{
+		if (probe_kernel_write((void *) rec->ip, ftrace_enable_insn,
+				       FTRACE_INSN_SIZE))
+		return -EPERM;
+	}
 	return 0;
 }
 
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
+int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
+				unsigned long addr)
+{
+	return ftrace_make_call(rec, addr);
+}
+#endif
+
 int ftrace_update_ftrace_func(ftrace_func_t func)
 {
 	return 0;
@@ -173,19 +203,41 @@ out:
 int ftrace_enable_ftrace_graph_caller(void)
 {
 	unsigned short offset;
+	int ret;
+
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
+	offset = ((void *) prepare_ftrace_return -
+		  (void *) ftrace_regs_graph_caller) / 2;
+	if ((ret = probe_kernel_write((void *) ftrace_regs_graph_caller + 2,
+				  &offset, sizeof(offset))))
+		return ret;
+#endif
 
 	offset = ((void *) prepare_ftrace_return -
 		  (void *) ftrace_graph_caller) / 2;
-	return probe_kernel_write((void *) ftrace_graph_caller + 2,
-				  &offset, sizeof(offset));
+	if ((ret = probe_kernel_write((void *) ftrace_graph_caller + 2,
+				  &offset, sizeof(offset))))
+		return ret;
+
+	return 0;
 }
 
 int ftrace_disable_ftrace_graph_caller(void)
 {
 	static unsigned short offset = 0x0002;
+	int ret;
 
-	return probe_kernel_write((void *) ftrace_graph_caller + 2,
-				  &offset, sizeof(offset));
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
+	if ((ret = probe_kernel_write((void *) ftrace_regs_graph_caller + 2,
+			  &offset, sizeof(offset))))
+		return ret;
+#endif
+
+	if ((ret = probe_kernel_write((void *) ftrace_graph_caller + 2,
+			  &offset, sizeof(offset))))
+		return ret;
+
+	return 0;
 }
 
 #endif /* CONFIG_DYNAMIC_FTRACE */
diff --git a/arch/s390/kernel/mcount.S b/arch/s390/kernel/mcount.S
index 08dcf21..e4322cf 100644
--- a/arch/s390/kernel/mcount.S
+++ b/arch/s390/kernel/mcount.S
@@ -53,6 +53,49 @@ ENTRY(ftrace_graph_caller)
 3:	lm	%r2,%r5,16(%r15)
 	br	%r14
 
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
+ENTRY(ftrace_regs_caller)
+	bras	%r1,1f
+0:	.long	function_trace_stop
+1:	l	%r1,0(%r1)
+	icm	%r1,0xf,0(%r1)
+	bnzr	%r14
+	lr	%r1,%r15
+	ahi	%r15,-188
+	st	%r1,__SF_BACKCHAIN(%r15)
+	st	%r1,168(%r15)
+	stm	%r0,%r13,108(%r15)
+	st	%r14,104(%r15)
+	lr	%r2,%r14
+	ahi	%r2,-MCOUNT_INSN_SIZE
+	l	%r3,192(%r15)
+	st	%r3,164(%r15)
+	bras	%r1,1f
+0:	.long	ftrace_trace_function
+1:	.long	function_trace_op
+	l	%r4,1b-0b(%r1)
+	l	%r4,0(%r4)
+	lr	%r5, %r15
+	ahi	%r5, 96
+	l	%r14,0(%r1)
+	l	%r14,0(%r14)
+	basr	%r14,%r14
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+	l	%r2,192(%r15)
+	l	%r3,244(%r15)
+ENTRY(ftrace_regs_graph_caller)
+# The bras instruction gets runtime patched to call prepare_ftrace_return.
+# See ftrace_enable_ftrace_graph_caller. The patched instruction is:
+#	bras	%r14,prepare_ftrace_return
+	bras	%r14,0f
+0:	st	%r2,192(%r15)
+#endif
+	lm	%r0,%r13,108(%r15)
+	l	%r14,104(%r15)
+	ahi	%r15,188
+	br	%r14
+#endif
+
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 
 ENTRY(return_to_handler)
diff --git a/arch/s390/kernel/mcount64.S b/arch/s390/kernel/mcount64.S
index 1c52eae..bcad958 100644
--- a/arch/s390/kernel/mcount64.S
+++ b/arch/s390/kernel/mcount64.S
@@ -49,6 +49,44 @@ ENTRY(ftrace_graph_caller)
 	lg	%r14,112(%r15)
 	br	%r14
 
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
+ENTRY(ftrace_regs_caller)
+	larl	%r1,function_trace_stop
+	icm	%r1,0xf,0(%r1)
+	bnzr	%r14
+	lgr	%r1,%r15
+	aghi	%r15,-336
+	stg	%r1,__SF_BACKCHAIN(%r15)
+	stg	%r1,304(%r15)
+	stmg	%r0,%r13,184(%r15)
+	stg	%r14,176(%r15)
+	lgr	%r2,%r14
+	aghi	%r2,-MCOUNT_INSN_SIZE
+	lg	%r3,344(%r15)
+	stg	%r3,296(%r15)
+	larl	%r4,function_trace_op
+	lg	%r4,0(%r4)
+	lgr	%r5, %r15
+	aghi	%r5, 160
+	larl	%r14,ftrace_trace_function
+	lg	%r14,0(%r14)
+	basr	%r14,%r14
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+	lg	%r2,344(%r15)
+	lg	%r3,448(%r15)
+ENTRY(ftrace_regs_graph_caller)
+# The bras instruction gets runtime patched to call prepare_ftrace_return.
+# See ftrace_enable_ftrace_graph_caller. The patched instruction is:
+#	bras	%r14,prepare_ftrace_return
+	bras	%r14,0f
+0:	stg	%r2,344(%r15)
+#endif
+	lmg	%r0,%r13,184(%r15)
+	lg	%r14,176(%r15)
+	aghi	%r15,336
+	br	%r14
+#endif
+
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 
 ENTRY(return_to_handler)
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 1e2264b..6cdf2a1 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -352,6 +352,7 @@ static void __init setup_lowcore(void)
 	lc->last_update_timer = S390_lowcore.last_update_timer;
 	lc->last_update_clock = S390_lowcore.last_update_clock;
 	lc->ftrace_func = S390_lowcore.ftrace_func;
+	lc->ftrace_regs_func = S390_lowcore.ftrace_regs_func;
 
 	restart_stack = __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0);
 	restart_stack += ASYNC_SIZE;
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 243c7e5..152967a 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -232,6 +232,7 @@ static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu)
 	lc->kernel_asce = S390_lowcore.kernel_asce;
 	lc->machine_flags = S390_lowcore.machine_flags;
 	lc->ftrace_func = S390_lowcore.ftrace_func;
+	lc->ftrace_regs_func = S390_lowcore.ftrace_regs_func;
 	lc->user_timer = lc->system_timer = lc->steal_timer = 0;
 	__ctl_store(lc->cregs_save_area, 0, 15);
 	save_access_regs((unsigned int *) lc->access_regs_save_area);
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 404a686..70ccc82 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -441,6 +441,7 @@ void ftrace_modify_all_code(int command);
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 extern void ftrace_graph_caller(void);
+extern void ftrace_regs_graph_caller(void);
 extern int ftrace_enable_ftrace_graph_caller(void);
 extern int ftrace_disable_ftrace_graph_caller(void);
 #else

^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2014-08-15 12:01 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-07-03 12:00 [PATCH] s390: add support for DYNAMIC_FTRACE_WITH_REGS Vojtech Pavlik
2014-07-08  8:07 ` Heiko Carstens
2014-08-15 11:57   ` Heiko Carstens
2014-08-15 11:59     ` [PATCH 1/5] s390: pass march flag to assembly files as well Heiko Carstens
2014-08-15 11:59     ` [PATCH 2/5] s390/ftrace: optimize patched mcount calling code Heiko Carstens
2014-08-15 12:00     ` [PATCH 3/5] s390/ftrace: optimize function graph caller code Heiko Carstens
2014-08-15 12:00     ` [PATCH 4/5] s390/ftrace: add HAVE_DYNAMIC_FTRACE_WITH_REGS support Heiko Carstens
2014-08-15 12:01     ` [PATCH 5/5] s390/ftrace: enforce DYNAMIC_FTRACE if FUNCTION_TRACER is selected Heiko Carstens

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.