Discussion:
[PATCH 0/4] Improve syscall entry code
Russell King - ARM Linux
2017-07-20 09:31:44 UTC
Permalink
The system call entry code has become less optimal as various kernel
features such as context tracking and irq tracing have been added.

For example, we stack the registers on SWI entry, but inside the
enable_irq macro, we re-stack r0-r3, call the trace function, and
unstack them. This stacking and unstacking is unnecessary as we
can merely reload them from the original entry stacking. Similar
happens within the ct_user_exit macro. So, with both features
enabled, we end up stacking and unstacking r0-r3 twice, which is
completely unnecessary.

We also need the 'lr' value for when we need to read the SWI
instruction, but this will be clobbered by the function calls for
these features. Rather than stacking or re-reading that register,
move it to another register if necessary.

We achieve this by:

1. use register aliases for the saved psr and pc values.
2. move the get_thread_info later to free up a spare register (r9).
3. use this spare register 'r9' to store the saved pc value if we
have any of these features enabled, otherwise just use 'lr'.
4. switch to using the non-stacking variants of the trace and
context tracking macros, and reload r0-r3 where necessary.

arch/arm/kernel/entry-common.S | 44 +++++++++++++++++++++++++++++-------------
1 file changed, 31 insertions(+), 13 deletions(-)
--
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
Russell King
2017-07-20 09:32:29 UTC
Permalink
Obtain the thread info structure later in the syscall processing, so
that we free up a register for earlier code.

Signed-off-by: Russell King <rmk+***@armlinux.org.uk>
---
arch/arm/kernel/entry-common.S | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 9abe47a206d9..374c28723547 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -152,7 +152,6 @@ ENTRY(vector_swi)
alignment_trap r10, ip, __cr_alignment
enable_irq
ct_user_exit
- get_thread_info tsk

/*
* Get the system call number.
@@ -209,6 +208,7 @@ ENTRY(vector_swi)
bic scno, scno, #0xff000000 @ mask off SWI op-code
eor scno, scno, #__NR_SYSCALL_BASE @ check OS number
#endif
+ get_thread_info tsk

local_restart:
ldr r10, [tsk, #TI_FLAGS] @ check for syscall tracing
@@ -240,6 +240,7 @@ ENTRY(vector_swi)
9001:
sub lr, saved_pc, #4
str lr, [sp, #S_PC]
+ get_thread_info tsk
b ret_fast_syscall
#endif
ENDPROC(vector_swi)
--
2.7.4
Russell King
2017-07-20 09:32:24 UTC
Permalink
Use aliases for the saved (and preserved) PSR and PC values so that we
can control which registers are used.

Signed-off-by: Russell King <rmk+***@armlinux.org.uk>
---
arch/arm/kernel/entry-common.S | 24 ++++++++++++++----------
1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index eb5cd77bf1d8..9abe47a206d9 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -27,6 +27,8 @@

#include "entry-header.S"

+saved_psr .req r8
+saved_pc .req lr

.align 5
#if !(IS_ENABLED(CONFIG_TRACE_IRQFLAGS) || IS_ENABLED(CONFIG_CONTEXT_TRACKING))
@@ -141,9 +143,9 @@ ENTRY(vector_swi)
ARM( stmdb r8, {sp, lr}^ ) @ Calling sp, lr
THUMB( mov r8, sp )
THUMB( store_user_sp_lr r8, r10, S_SP ) @ calling sp, lr
- mrs r8, spsr @ called from non-FIQ mode, so ok.
- str lr, [sp, #S_PC] @ Save calling PC
- str r8, [sp, #S_PSR] @ Save CPSR
+ mrs saved_psr, spsr @ called from non-FIQ mode, so ok.
+ str saved_pc, [sp, #S_PC] @ Save calling PC
+ str saved_psr, [sp, #S_PSR] @ Save CPSR
str r0, [sp, #S_OLD_R0] @ Save OLD_R0
#endif
zero_fp
@@ -163,11 +165,11 @@ ENTRY(vector_swi)
* value to determine if it is an EABI or an old ABI call.
*/
#ifdef CONFIG_ARM_THUMB
- tst r8, #PSR_T_BIT
+ tst saved_psr, #PSR_T_BIT
movne r10, #0 @ no thumb OABI emulation
- USER( ldreq r10, [lr, #-4] ) @ get SWI instruction
+ USER( ldreq r10, [saved_pc, #-4] ) @ get SWI instruction
#else
- USER( ldr r10, [lr, #-4] ) @ get SWI instruction
+ USER( ldr r10, [saved_pc, #-4] ) @ get SWI instruction
#endif
ARM_BE8(rev r10, r10) @ little endian instruction

@@ -178,15 +180,17 @@ ENTRY(vector_swi)
*/
#elif defined(CONFIG_ARM_THUMB)
/* Legacy ABI only, possibly thumb mode. */
- tst r8, #PSR_T_BIT @ this is SPSR from save_user_regs
+ tst saved_psr, #PSR_T_BIT @ this is SPSR from save_user_regs
addne scno, r7, #__NR_SYSCALL_BASE @ put OS number in
- USER( ldreq scno, [lr, #-4] )
+ USER( ldreq scno, [saved_pc, #-4] )

#else
/* Legacy ABI only. */
- USER( ldr scno, [lr, #-4] ) @ get SWI instruction
+ USER( ldr scno, [saved_pc, #-4] ) @ get SWI instruction
#endif

+ /* saved_psr and saved_pc are now dead */
+
uaccess_disable tbl

adr tbl, sys_call_table @ load syscall table pointer
@@ -234,7 +238,7 @@ ENTRY(vector_swi)
* current task.
*/
9001:
- sub lr, lr, #4
+ sub lr, saved_pc, #4
str lr, [sp, #S_PC]
b ret_fast_syscall
#endif
--
2.7.4
Russell King
2017-07-20 09:32:34 UTC
Permalink
Move the saved PC value into r9, thereby moving it into a caller-saved
register for functions that we may call during the entry to a syscall.

Signed-off-by: Russell King <rmk+***@armlinux.org.uk>
---
arch/arm/kernel/entry-common.S | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 374c28723547..1b3fc79d0e8b 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -28,7 +28,13 @@
#include "entry-header.S"

saved_psr .req r8
+#if defined(CONFIG_TRACE_IRQFLAGS) || defined(CONFIG_CONTEXT_TRACKING)
+saved_pc .req r9
+#define TRACE(x...) x
+#else
saved_pc .req lr
+#define TRACE(x...)
+#endif

.align 5
#if !(IS_ENABLED(CONFIG_TRACE_IRQFLAGS) || IS_ENABLED(CONFIG_CONTEXT_TRACKING))
@@ -144,6 +150,7 @@ ENTRY(vector_swi)
THUMB( mov r8, sp )
THUMB( store_user_sp_lr r8, r10, S_SP ) @ calling sp, lr
mrs saved_psr, spsr @ called from non-FIQ mode, so ok.
+ TRACE( mov saved_pc, lr )
str saved_pc, [sp, #S_PC] @ Save calling PC
str saved_psr, [sp, #S_PSR] @ Save CPSR
str r0, [sp, #S_OLD_R0] @ Save OLD_R0
--
2.7.4
Russell King
2017-07-20 09:32:39 UTC
Permalink
Avoid repeatedly saving and restoring registers around the calls to
trace_hardirqs_on() and context_tracking_user_exit(). With the
previous changes, we no longer need to preserve "lr" across these
calls, and if we re-load r0-r3 later, we can avoid preserving these
regsiters too.

Signed-off-by: Russell King <rmk+***@armlinux.org.uk>
---
arch/arm/kernel/entry-common.S | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 1b3fc79d0e8b..0b60adf4a5d9 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -157,8 +157,9 @@ ENTRY(vector_swi)
#endif
zero_fp
alignment_trap r10, ip, __cr_alignment
- enable_irq
- ct_user_exit
+ asm_trace_hardirqs_on save=0
+ enable_irq_notrace
+ ct_user_exit save=0

/*
* Get the system call number.
@@ -216,6 +217,11 @@ ENTRY(vector_swi)
eor scno, scno, #__NR_SYSCALL_BASE @ check OS number
#endif
get_thread_info tsk
+ /*
+ * Reload the registers that may have been corrupted on entry to
+ * the syscall assembly (by tracing or context tracking.)
+ */
+ TRACE( ldmia sp, {r0 - r3} )

local_restart:
ldr r10, [tsk, #TI_FLAGS] @ check for syscall tracing
--
2.7.4
Loading...