summaryrefslogtreecommitdiff
path: root/arch/s390/kernel/mcount.S
blob: 43ff91073d2a41e20d0805bb97b8b54e117dcb14 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Copyright IBM Corp. 2008, 2009
 *
 */

#include <linux/linkage.h>
#include <asm/asm-offsets.h>
#include <asm/ftrace.h>
#include <asm/nospec-insn.h>
#include <asm/ptrace.h>
#include <asm/export.h>


#define STACK_FRAME_SIZE	(STACK_FRAME_OVERHEAD + __PT_SIZE)
#define STACK_PTREGS		(STACK_FRAME_OVERHEAD)
#define STACK_PTREGS_GPRS	(STACK_PTREGS + __PT_GPRS)
#define STACK_PTREGS_PSW	(STACK_PTREGS + __PT_PSW)
#define STACK_PTREGS_ORIG_GPR2	(STACK_PTREGS + __PT_ORIG_GPR2)
#define STACK_PTREGS_FLAGS	(STACK_PTREGS + __PT_FLAGS)
/* packed stack: allocate just enough for r14, r15 and backchain */
#define TRACED_FUNC_FRAME_SIZE	24

#ifdef CONFIG_FUNCTION_TRACER

	GEN_BR_THUNK %r1
	GEN_BR_THUNK %r14

	.section .kprobes.text, "ax"

ENTRY(ftrace_stub)
	BR_EX	%r14
ENDPROC(ftrace_stub)

	.macro	ftrace_regs_entry, allregs=0
	stg	%r14,(__SF_GPRS+8*8)(%r15)	# save traced function caller

	.if \allregs == 1
	# save psw mask
	# don't put any instructions clobbering CC before this point
	epsw	%r1,%r14
	risbg	%r14,%r1,0,31,32
	.endif

	lgr	%r1,%r15
	# allocate stack frame for ftrace_caller to contain traced function
	aghi	%r15,-TRACED_FUNC_FRAME_SIZE
	stg	%r1,__SF_BACKCHAIN(%r15)
	stg	%r0,(__SF_GPRS+8*8)(%r15)
	stg	%r15,(__SF_GPRS+9*8)(%r15)
	# allocate pt_regs and stack frame for ftrace_trace_function
	aghi	%r15,-STACK_FRAME_SIZE
	stg	%r1,(STACK_PTREGS_GPRS+15*8)(%r15)
	xc	STACK_PTREGS_ORIG_GPR2(8,%r15),STACK_PTREGS_ORIG_GPR2(%r15)

	.if \allregs == 1
	stg	%r14,(STACK_PTREGS_PSW)(%r15)
	mvghi	STACK_PTREGS_FLAGS(%r15),_PIF_FTRACE_FULL_REGS
	.else
	xc	STACK_PTREGS_FLAGS(8,%r15),STACK_PTREGS_FLAGS(%r15)
	.endif

	lg	%r14,(__SF_GPRS+8*8)(%r1)	# restore original return address
	aghi	%r1,-TRACED_FUNC_FRAME_SIZE
	stg	%r1,__SF_BACKCHAIN(%r15)
	stg	%r0,(STACK_PTREGS_PSW+8)(%r15)
	stmg	%r2,%r14,(STACK_PTREGS_GPRS+2*8)(%r15)
	.endm

SYM_CODE_START(ftrace_regs_caller)
	ftrace_regs_entry	1
	j	ftrace_common
SYM_CODE_END(ftrace_regs_caller)

SYM_CODE_START(ftrace_caller)
	ftrace_regs_entry	0
	j	ftrace_common
SYM_CODE_END(ftrace_caller)

SYM_CODE_START(ftrace_common)
#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
	aghik	%r2,%r0,-MCOUNT_INSN_SIZE
	lgrl	%r4,function_trace_op
	lgrl	%r1,ftrace_func
#else
	lgr	%r2,%r0
	aghi	%r2,-MCOUNT_INSN_SIZE
	larl	%r4,function_trace_op
	lg	%r4,0(%r4)
	larl	%r1,ftrace_func
	lg	%r1,0(%r1)
#endif
	lgr	%r3,%r14
	la	%r5,STACK_PTREGS(%r15)
	BASR_EX	%r14,%r1
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
# The j instruction gets runtime patched to a nop instruction.
# See ftrace_enable_ftrace_graph_caller.
SYM_INNER_LABEL(ftrace_graph_caller, SYM_L_GLOBAL)
	j	.Lftrace_graph_caller_end
	lmg	%r2,%r3,(STACK_PTREGS_GPRS+14*8)(%r15)
	lg	%r4,(STACK_PTREGS_PSW+8)(%r15)
	brasl	%r14,prepare_ftrace_return
	stg	%r2,(STACK_PTREGS_GPRS+14*8)(%r15)
.Lftrace_graph_caller_end:
#endif
	lg	%r0,(STACK_PTREGS_PSW+8)(%r15)
#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
	ltg	%r1,STACK_PTREGS_ORIG_GPR2(%r15)
	locgrz	%r1,%r0
#else
	lg	%r1,STACK_PTREGS_ORIG_GPR2(%r15)
	ltgr	%r1,%r1
	jnz	0f
	lgr	%r1,%r0
#endif
0:	lmg	%r2,%r15,(STACK_PTREGS_GPRS+2*8)(%r15)
	BR_EX	%r1
SYM_CODE_END(ftrace_common)

#ifdef CONFIG_FUNCTION_GRAPH_TRACER

SYM_FUNC_START(return_to_handler)
	stmg	%r2,%r5,32(%r15)
	lgr	%r1,%r15
	aghi	%r15,-STACK_FRAME_OVERHEAD
	stg	%r1,__SF_BACKCHAIN(%r15)
	brasl	%r14,ftrace_return_to_handler
	aghi	%r15,STACK_FRAME_OVERHEAD
	lgr	%r14,%r2
	lmg	%r2,%r5,32(%r15)
	BR_EX	%r14
SYM_FUNC_END(return_to_handler)

#endif
#endif /* CONFIG_FUNCTION_TRACER */

#ifdef CONFIG_RETHOOK

SYM_FUNC_START(arch_rethook_trampoline)

	stg	%r14,(__SF_GPRS+8*8)(%r15)
	lay	%r15,-STACK_FRAME_SIZE(%r15)
	stmg	%r0,%r14,STACK_PTREGS_GPRS(%r15)

	# store original stack pointer in backchain and pt_regs
	lay	%r7,STACK_FRAME_SIZE(%r15)
	stg	%r7,__SF_BACKCHAIN(%r15)
	stg	%r7,STACK_PTREGS_GPRS+(15*8)(%r15)

	# store full psw
	epsw	%r2,%r3
	risbg	%r3,%r2,0,31,32
	stg	%r3,STACK_PTREGS_PSW(%r15)
	larl	%r1,arch_rethook_trampoline
	stg	%r1,STACK_PTREGS_PSW+8(%r15)

	lay	%r2,STACK_PTREGS(%r15)
	brasl	%r14,arch_rethook_trampoline_callback

	mvc	__SF_EMPTY(16,%r7),STACK_PTREGS_PSW(%r15)
	lmg	%r0,%r15,STACK_PTREGS_GPRS(%r15)
	lpswe	__SF_EMPTY(%r15)

SYM_FUNC_END(arch_rethook_trampoline)

#endif /* CONFIG_RETHOOK */