GNU Linux-libre 4.19.263-gnu1
[releases.git] / arch / x86 / kernel / ftrace_32.S
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  *  Copyright (C) 2017  Steven Rostedt, VMware Inc.
4  */
5
6 #include <linux/linkage.h>
7 #include <asm/page_types.h>
8 #include <asm/segment.h>
9 #include <asm/export.h>
10 #include <asm/ftrace.h>
11 #include <asm/nospec-branch.h>
12 #include <asm/frame.h>
13
14 #ifdef CC_USING_FENTRY
15 # define function_hook  __fentry__
16 EXPORT_SYMBOL(__fentry__)
17 #else
18 # define function_hook  mcount
19 EXPORT_SYMBOL(mcount)
20 #endif
21
22 #ifdef CONFIG_DYNAMIC_FTRACE
23
24 /* mcount uses a frame pointer even if CONFIG_FRAME_POINTER is not set */
25 #if !defined(CC_USING_FENTRY) || defined(CONFIG_FRAME_POINTER)
26 # define USING_FRAME_POINTER
27 #endif
28
29 #ifdef USING_FRAME_POINTER
30 # define MCOUNT_FRAME                   1       /* using frame = true  */
31 #else
32 # define MCOUNT_FRAME                   0       /* using frame = false */
33 #endif
34
35 ENTRY(function_hook)
36         ret
37 END(function_hook)
38
39 ENTRY(ftrace_caller)
40
41 #ifdef USING_FRAME_POINTER
42 # ifdef CC_USING_FENTRY
43         /*
44          * Frame pointers are of ip followed by bp.
45          * Since fentry is an immediate jump, we are left with
46          * parent-ip, function-ip. We need to add a frame with
47          * parent-ip followed by ebp.
48          */
49         pushl   4(%esp)                         /* parent ip */
50         pushl   %ebp
51         movl    %esp, %ebp
52         pushl   2*4(%esp)                       /* function ip */
53 # endif
54         /* For mcount, the function ip is directly above */
55         pushl   %ebp
56         movl    %esp, %ebp
57 #endif
58         pushl   %eax
59         pushl   %ecx
60         pushl   %edx
61         pushl   $0                              /* Pass NULL as regs pointer */
62
63 #ifdef USING_FRAME_POINTER
64         /* Load parent ebp into edx */
65         movl    4*4(%esp), %edx
66 #else
67         /* There's no frame pointer, load the appropriate stack addr instead */
68         lea     4*4(%esp), %edx
69 #endif
70
71         movl    (MCOUNT_FRAME+4)*4(%esp), %eax  /* load the rip */
72         /* Get the parent ip */
73         movl    4(%edx), %edx                   /* edx has ebp */
74
75         movl    function_trace_op, %ecx
76         subl    $MCOUNT_INSN_SIZE, %eax
77
78 .globl ftrace_call
79 ftrace_call:
80         call    ftrace_stub
81
82         addl    $4, %esp                        /* skip NULL pointer */
83         popl    %edx
84         popl    %ecx
85         popl    %eax
86 #ifdef USING_FRAME_POINTER
87         popl    %ebp
88 # ifdef CC_USING_FENTRY
89         addl    $4,%esp                         /* skip function ip */
90         popl    %ebp                            /* this is the orig bp */
91         addl    $4, %esp                        /* skip parent ip */
92 # endif
93 #endif
94 .Lftrace_ret:
95 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
96 .globl ftrace_graph_call
97 ftrace_graph_call:
98         jmp     ftrace_stub
99 #endif
100
101 /* This is weak to keep gas from relaxing the jumps */
102 WEAK(ftrace_stub)
103         ret
104 END(ftrace_caller)
105
106 ENTRY(ftrace_regs_caller)
107         /*
108          * i386 does not save SS and ESP when coming from kernel.
109          * Instead, to get sp, &regs->sp is used (see ptrace.h).
110          * Unfortunately, that means eflags must be at the same location
111          * as the current return ip is. We move the return ip into the
112          * regs->ip location, and move flags into the return ip location.
113          */
114         pushl   $__KERNEL_CS
115         pushl   4(%esp)                         /* Save the return ip */
116         pushl   $0                              /* Load 0 into orig_ax */
117         pushl   %gs
118         pushl   %fs
119         pushl   %es
120         pushl   %ds
121         pushl   %eax
122
123         /* Get flags and place them into the return ip slot */
124         pushf
125         popl    %eax
126         movl    %eax, 8*4(%esp)
127
128         pushl   %ebp
129         pushl   %edi
130         pushl   %esi
131         pushl   %edx
132         pushl   %ecx
133         pushl   %ebx
134
135         ENCODE_FRAME_POINTER
136
137         movl    12*4(%esp), %eax                /* Load ip (1st parameter) */
138         subl    $MCOUNT_INSN_SIZE, %eax         /* Adjust ip */
139 #ifdef CC_USING_FENTRY
140         movl    15*4(%esp), %edx                /* Load parent ip (2nd parameter) */
141 #else
142         movl    0x4(%ebp), %edx                 /* Load parent ip (2nd parameter) */
143 #endif
144         movl    function_trace_op, %ecx         /* Save ftrace_pos in 3rd parameter */
145         pushl   %esp                            /* Save pt_regs as 4th parameter */
146
147 GLOBAL(ftrace_regs_call)
148         call    ftrace_stub
149
150         addl    $4, %esp                        /* Skip pt_regs */
151
152         /* restore flags */
153         push    14*4(%esp)
154         popf
155
156         /* Move return ip back to its original location */
157         movl    12*4(%esp), %eax
158         movl    %eax, 14*4(%esp)
159
160         popl    %ebx
161         popl    %ecx
162         popl    %edx
163         popl    %esi
164         popl    %edi
165         popl    %ebp
166         popl    %eax
167         popl    %ds
168         popl    %es
169         popl    %fs
170         popl    %gs
171
172         /* use lea to not affect flags */
173         lea     3*4(%esp), %esp                 /* Skip orig_ax, ip and cs */
174
175         jmp     .Lftrace_ret
176 #else /* ! CONFIG_DYNAMIC_FTRACE */
177
178 ENTRY(function_hook)
179         cmpl    $__PAGE_OFFSET, %esp
180         jb      ftrace_stub                     /* Paging not enabled yet? */
181
182         cmpl    $ftrace_stub, ftrace_trace_function
183         jnz     .Ltrace
184 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
185         cmpl    $ftrace_stub, ftrace_graph_return
186         jnz     ftrace_graph_caller
187
188         cmpl    $ftrace_graph_entry_stub, ftrace_graph_entry
189         jnz     ftrace_graph_caller
190 #endif
191 .globl ftrace_stub
192 ftrace_stub:
193         ret
194
195         /* taken from glibc */
196 .Ltrace:
197         pushl   %eax
198         pushl   %ecx
199         pushl   %edx
200         movl    0xc(%esp), %eax
201         movl    0x4(%ebp), %edx
202         subl    $MCOUNT_INSN_SIZE, %eax
203
204         movl    ftrace_trace_function, %ecx
205         CALL_NOSPEC %ecx
206
207         popl    %edx
208         popl    %ecx
209         popl    %eax
210         jmp     ftrace_stub
211 END(function_hook)
212 #endif /* CONFIG_DYNAMIC_FTRACE */
213
214 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
215 ENTRY(ftrace_graph_caller)
216         pushl   %eax
217         pushl   %ecx
218         pushl   %edx
219         movl    3*4(%esp), %eax
220         /* Even with frame pointers, fentry doesn't have one here */
221 #ifdef CC_USING_FENTRY
222         lea     4*4(%esp), %edx
223         movl    $0, %ecx
224 #else
225         lea     0x4(%ebp), %edx
226         movl    (%ebp), %ecx
227 #endif
228         subl    $MCOUNT_INSN_SIZE, %eax
229         call    prepare_ftrace_return
230         popl    %edx
231         popl    %ecx
232         popl    %eax
233         ret
234 END(ftrace_graph_caller)
235
236 .globl return_to_handler
237 return_to_handler:
238         pushl   %eax
239         pushl   %edx
240 #ifdef CC_USING_FENTRY
241         movl    $0, %eax
242 #else
243         movl    %ebp, %eax
244 #endif
245         call    ftrace_return_to_handler
246         movl    %eax, %ecx
247         popl    %edx
248         popl    %eax
249         JMP_NOSPEC %ecx
250 #endif