From: "Steven Rostedt (VMware)" When ftrace_regs_caller was created, it was designed to preserve flags as much as possible as it needed to act just like a breakpoint triggered on the same location. But the design is over complicated as it treated all operations as modifying flags. But push, mov and lea do not modify flags. This means the code can become more simplified by allowing flags to be stored further down. Making ftrace_regs_caller simpler will also be useful in implementing fentry logic. Reviewed-by: Masami Hiramatsu Signed-off-by: Steven Rostedt (VMware) --- arch/x86/kernel/ftrace_32.S | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/arch/x86/kernel/ftrace_32.S b/arch/x86/kernel/ftrace_32.S index 6f855dfb786d..2002aadd25f8 100644 --- a/arch/x86/kernel/ftrace_32.S +++ b/arch/x86/kernel/ftrace_32.S @@ -55,23 +55,30 @@ WEAK(ftrace_stub) END(ftrace_caller) ENTRY(ftrace_regs_caller) - pushf /* push flags before compare (in cs location) */ - /* * i386 does not save SS and ESP when coming from kernel. * Instead, to get sp, ®s->sp is used (see ptrace.h). * Unfortunately, that means eflags must be at the same location * as the current return ip is. We move the return ip into the - * ip location, and move flags into the return ip location. - */ - pushl 4(%esp) /* save return ip into ip slot */ + * regs->ip location, and move flags into the return ip location. + */ + pushl $__KERNEL_CS + pushl 4(%esp) /* Save the return ip */ + + /* temporarily save flags in the orig_ax location */ + pushf - pushl $0 /* Load 0 into orig_ax */ pushl %gs pushl %fs pushl %es pushl %ds pushl %eax + + /* move flags into the location of where the return ip was */ + movl 5*4(%esp), %eax + movl $0, 5*4(%esp) /* Load 0 into orig_ax */ + movl %eax, 8*4(%esp) /* Load flags in return ip */ + pushl %ebp pushl %edi pushl %esi @@ -79,11 +86,6 @@ ENTRY(ftrace_regs_caller) pushl %ecx pushl %ebx - movl 13*4(%esp), %eax /* Get the saved flags */ - movl %eax, 14*4(%esp) /* Move saved flags into regs->flags location */ - /* clobbering return ip */ - movl $__KERNEL_CS, 13*4(%esp) - movl 12*4(%esp), %eax /* Load ip (1st parameter) */ subl $MCOUNT_INSN_SIZE, %eax /* Adjust ip */ movl 0x4(%ebp), %edx /* Load parent ip (2nd parameter) */ @@ -94,10 +96,14 @@ GLOBAL(ftrace_regs_call) call ftrace_stub addl $4, %esp /* Skip pt_regs */ - movl 14*4(%esp), %eax /* Move flags back into cs */ - movl %eax, 13*4(%esp) /* Needed to keep addl from modifying flags */ - movl 12*4(%esp), %eax /* Get return ip from regs->ip */ - movl %eax, 14*4(%esp) /* Put return ip back for ret */ + + /* Since we don't care about cs, move flags there to simplify return */ + movl 14*4(%esp), %eax + movl %eax, 13*4(%esp) + + /* Move return ip back to its original location */ + movl 12*4(%esp), %eax + movl %eax, 14*4(%esp) popl %ebx popl %ecx @@ -110,12 +116,11 @@ GLOBAL(ftrace_regs_call) popl %es popl %fs popl %gs - addl $8, %esp /* Skip orig_ax and ip */ - popf /* Pop flags at end (no addl to corrupt flags) */ - jmp .Lftrace_ret + addl $8, %esp /* Skip orig_ax and old ip */ - popf - jmp ftrace_stub + popf /* flags is in the cs location */ + + jmp .Lftrace_ret #else /* ! CONFIG_DYNAMIC_FTRACE */ ENTRY(mcount) -- 2.10.2