Commit b832faec authored by Ard Biesheuvel's avatar Ard Biesheuvel

ARM: switch_to: clean up Thumb2 code path

The load-multiple instruction that essentially performs the switch_to
operation in ARM mode, by loading all callee save registers as well the
stack pointer and the program counter, is split into 3 separate loads
for Thumb-2, with the IP register used as a temporary to capture the
value of R4 before it gets overwritten.

We can clean this up a bit, by sticking with a single LDMIA instruction,
but one that pops SP and PC into IP and LR, respectively, and by using
ordinary move register and branch instructions to get those values into
SP and PC. This also allows us to move the set_current call closer to
the assignment of SP, reducing the window where those are mutually out
of sync. This is especially relevant for CONFIG_VMAP_STACK, which is
being introduced in a subsequent patch, where we need to issue a load
that might fault from the new stack while running from the old one, to
ensure that stale PMD entries in the VMALLOC space are synced up.
Signed-off-by: default avatarArd Biesheuvel <ardb@kernel.org>
Tested-by: default avatarKeith Packard <keithpac@amazon.com>
Tested-by: default avatarMarc Zyngier <maz@kernel.org>
Tested-by: Vladimir Murzin <vladimir.murzin@arm.com> # ARMv7M
parent 532319b9
...@@ -823,13 +823,26 @@ ENTRY(__switch_to) ...@@ -823,13 +823,26 @@ ENTRY(__switch_to)
#if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_SMP) #if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_SMP)
str r7, [r8] str r7, [r8]
#endif #endif
THUMB( mov ip, r4 )
mov r0, r5 mov r0, r5
#if !defined(CONFIG_THUMB2_KERNEL)
set_current r7 set_current r7
ARM( ldmia r4, {r4 - sl, fp, sp, pc} ) @ Load all regs saved previously ldmia r4, {r4 - sl, fp, sp, pc} @ Load all regs saved previously
THUMB( ldmia ip!, {r4 - sl, fp} ) @ Load all regs saved previously #else
THUMB( ldr sp, [ip], #4 ) mov r1, r7
THUMB( ldr pc, [ip] ) ldmia r4, {r4 - sl, fp, ip, lr} @ Load all regs saved previously
@ When CONFIG_THREAD_INFO_IN_TASK=n, the update of SP itself is what
@ effectuates the task switch, as that is what causes the observable
@ values of current and current_thread_info to change. When
@ CONFIG_THREAD_INFO_IN_TASK=y, setting current (and therefore
@ current_thread_info) is done explicitly, and the update of SP just
@ switches us to another stack, with few other side effects. In order
@ to prevent this distinction from causing any inconsistencies, let's
@ keep the 'set_current' call as close as we can to the update of SP.
set_current r1
mov sp, ip
ret lr
#endif
UNWIND(.fnend ) UNWIND(.fnend )
ENDPROC(__switch_to) ENDPROC(__switch_to)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment