[PATCH 1/4] x86: entry.S: tidy up several suboptimal insns

Denys Vlasenko
2015-02-24T18:52:22Z

In all three 32-bit entry points, %eax is zero-extended to %rax.
It is safe to do 32-bit compare when checking that syscall#
is not too large.

The last instance of "mysterious" SS+8 constant is replaced by SIZEOF_PTREGS.

The $AUDIT_ARCH_X86_64 parameter to syscall_trace_enter_phase1/2
is a 32-bit constant, loading it with 64-bit MOV produces 10-byte insn
instead of 5-byte one.

After TEST insn, JE anctually means "jump of zero",
let's use JZ mnemonic instead.

At irq_return_via_sysret:
* avoid redundant load of %r11 (it is already loaded a few instructions before).
* do not needlessly increment %rsp - we are going to return to userspace
via SYSRET, this insn doesn't use stack for return.

Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
CC: Linus Torvalds <torvalds@linux-foundation.org>
CC: Steven Rostedt <rostedt@goodmis.org>
CC: Ingo Molnar <mingo@kernel.org>
CC: Borislav Petkov <bp@alien8.de>
CC: "H. Peter Anvin" <hpa@zytor.com>
CC: Andy Lutomirski <luto@amacapital.net>
CC: Oleg Nesterov <oleg@redhat.com>
CC: Frederic Weisbecker <fweisbec@gmail.com>
CC: Alexei Starovoitov <ast@plumgrid.com>
CC: Will Drewry <wad@chromium.org>
CC: Kees Cook <keescook@chromium.org>
CC: x86@kernel.org
CC: linux-kernel@vger.kernel.org
---
arch/x86/ia32/ia32entry.S | 14 +++++++-------
arch/x86/include/asm/calling.h | 3 +++
arch/x86/kernel/entry_64.S | 13 ++++++-------
3 files changed, 16 insertions(+), 14 deletions(-)

diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
index 6dcd372..01eca80 100644
--- a/arch/x86/ia32/ia32entry.S
+++ b/arch/x86/ia32/ia32entry.S
@@ -163,8 +163,8 @@ sysenter_flags_fixed:
orl $TS_COMPAT,TI_status+THREAD_INFO(%rsp,RIP)
testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags+THREAD_INFO(%rsp,RIP)
CFI_REMEMBER_STATE
- jnz sysenter_tracesys
- cmpq $(IA32_NR_syscalls-1),%rax
+ jnz sysenter_tracesys
+ cmpl $(IA32_NR_syscalls-1),%eax
ja ia32_badsys
sysenter_do_call:
/* 32bit syscall -> 64bit C ABI argument conversion */
@@ -350,9 +350,9 @@ ENTRY(ia32_cstar_target)
orl $TS_COMPAT,TI_status+THREAD_INFO(%rsp,RIP)
testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags+THREAD_INFO(%rsp,RIP)
CFI_REMEMBER_STATE
- jnz cstar_tracesys
- cmpq $IA32_NR_syscalls-1,%rax
- ja ia32_badsys
+ jnz cstar_tracesys
+ cmpl $(IA32_NR_syscalls-1),%eax
+ ja ia32_badsys
cstar_do_call:
/* 32bit syscall -> 64bit C ABI argument conversion */
movl %edi,%r8d /* arg5 */
@@ -473,7 +473,7 @@ ENTRY(ia32_syscall)
orl $TS_COMPAT,TI_status+THREAD_INFO(%rsp,RIP)
testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags+THREAD_INFO(%rsp,RIP)
jnz ia32_tracesys
- cmpq $(IA32_NR_syscalls-1),%rax
+ cmpl $(IA32_NR_syscalls-1),%eax
ja ia32_badsys
ia32_do_call:
/* 32bit syscall -> 64bit C ABI argument conversion */
@@ -536,7 +536,7 @@ ia32_ptregs_common:
CFI_ENDPROC
CFI_STARTPROC32 simple
CFI_SIGNAL_FRAME
- CFI_DEF_CFA rsp,SS+8
+ CFI_DEF_CFA rsp,SIZEOF_PTREGS
CFI_REL_OFFSET rax,RAX
CFI_REL_OFFSET rcx,RCX
CFI_REL_OFFSET rdx,RDX
diff --git a/arch/x86/include/asm/calling.h b/arch/x86/include/asm/calling.h
index 3374235..f1a962f 100644
--- a/arch/x86/include/asm/calling.h
+++ b/arch/x86/include/asm/calling.h
@@ -176,6 +176,9 @@ For 32-bit we have the following conventions - kernel is built with
.macro RESTORE_C_REGS_EXCEPT_RCX
RESTORE_C_REGS_HELPER 1,0,1,1,1
.endm
+ .macro RESTORE_C_REGS_EXCEPT_R11
+ RESTORE_C_REGS_HELPER 1,1,0,1,1
+ .endm
.macro RESTORE_RSI_RDI
RESTORE_C_REGS_HELPER 0,0,0,0,0
.endm
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index 64f2fd3..b93f3a2 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -312,7 +312,7 @@ int_ret_from_sys_call_fixup:
/* Do syscall tracing */
tracesys:
movq %rsp, %rdi
- movq $AUDIT_ARCH_X86_64, %rsi
+ movl $AUDIT_ARCH_X86_64, %esi
call syscall_trace_enter_phase1
test %rax, %rax
jnz tracesys_phase2 /* if needed, run the slow path */
@@ -323,7 +323,7 @@ tracesys_phase2:
SAVE_EXTRA_REGS
FIXUP_TOP_OF_STACK %rdi
movq %rsp, %rdi
- movq $AUDIT_ARCH_X86_64, %rsi
+ movl $AUDIT_ARCH_X86_64, %esi
movq %rax,%rdx
call syscall_trace_enter_phase2

@@ -686,7 +686,7 @@ ret_from_intr:
exit_intr:
GET_THREAD_INFO(%rcx)
testl $3,CS(%rsp)
- je retint_kernel
+ jz retint_kernel

/* Interrupt came from user space */
/*
@@ -742,7 +742,7 @@ retint_swapgs: /* return to user-space */
cmpq %r11,EFLAGS(%rsp) /* R11 == RFLAGS */
jne opportunistic_sysret_failed

- testq $X86_EFLAGS_RF,%r11 /* sysret can't restore RF */
+ testl $X86_EFLAGS_RF,%r11d /* sysret can't restore RF */
jnz opportunistic_sysret_failed

/* nothing to check for RSP */
@@ -756,9 +756,8 @@ retint_swapgs: /* return to user-space */
*/
irq_return_via_sysret:
CFI_REMEMBER_STATE
- RESTORE_C_REGS
- REMOVE_PT_GPREGS_FROM_STACK 8
- movq (RSP-RIP)(%rsp),%rsp
+ RESTORE_C_REGS_EXCEPT_R11
+ movq RSP(%rsp),%rsp
USERGS_SYSRET64
CFI_RESTORE_STATE

--
1.8.1.4