Commit c2755910 authored by Ard Biesheuvel's avatar Ard Biesheuvel

ARM: smp: defer TPIDRURO update for SMP v6 configurations too

Defer TPIDURO updates for user space until exit also for CPU_V6+SMP
configurations so that we can decide at runtime whether to use it to
carry the current pointer, provided that we are running on a CPU that
actually implements this register. This is needed for
THREAD_INFO_IN_TASK support for UP systems, which requires that all SMP
capable systems use the TPIDRURO based access to 'current' as the only
remaining alternative will be a global variable which only works on UP.
Acked-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Acked-by: default avatarNicolas Pitre <nico@fluxnic.net>
Signed-off-by: default avatarArd Biesheuvel <ardb@kernel.org>
Tested-by: default avatarMarc Zyngier <maz@kernel.org>
Tested-by: Vladimir Murzin <vladimir.murzin@arm.com> # ARMv7M
parent b87cf911
...@@ -18,13 +18,14 @@ ...@@ -18,13 +18,14 @@
.endm .endm
.macro switch_tls_v6, base, tp, tpuser, tmp1, tmp2 .macro switch_tls_v6, base, tp, tpuser, tmp1, tmp2
ldr \tmp1, =elf_hwcap ldr_va \tmp1, elf_hwcap
ldr \tmp1, [\tmp1, #0]
mov \tmp2, #0xffff0fff mov \tmp2, #0xffff0fff
tst \tmp1, #HWCAP_TLS @ hardware TLS available? tst \tmp1, #HWCAP_TLS @ hardware TLS available?
streq \tp, [\tmp2, #-15] @ set TLS value at 0xffff0ff0 streq \tp, [\tmp2, #-15] @ set TLS value at 0xffff0ff0
mrcne p15, 0, \tmp2, c13, c0, 2 @ get the user r/w register mrcne p15, 0, \tmp2, c13, c0, 2 @ get the user r/w register
#ifndef CONFIG_SMP
mcrne p15, 0, \tp, c13, c0, 3 @ yes, set TLS register mcrne p15, 0, \tp, c13, c0, 3 @ yes, set TLS register
#endif
mcrne p15, 0, \tpuser, c13, c0, 2 @ set user r/w register mcrne p15, 0, \tpuser, c13, c0, 2 @ set user r/w register
strne \tmp2, [\base, #TI_TP_VALUE + 4] @ save it strne \tmp2, [\base, #TI_TP_VALUE + 4] @ save it
.endm .endm
...@@ -43,7 +44,7 @@ ...@@ -43,7 +44,7 @@
#elif defined(CONFIG_CPU_V6) #elif defined(CONFIG_CPU_V6)
#define tls_emu 0 #define tls_emu 0
#define has_tls_reg (elf_hwcap & HWCAP_TLS) #define has_tls_reg (elf_hwcap & HWCAP_TLS)
#define defer_tls_reg_update 0 #define defer_tls_reg_update IS_ENABLED(CONFIG_SMP)
#define switch_tls switch_tls_v6 #define switch_tls switch_tls_v6
#elif defined(CONFIG_CPU_32v6K) #elif defined(CONFIG_CPU_32v6K)
#define tls_emu 0 #define tls_emu 0
...@@ -81,11 +82,11 @@ static inline void set_tls(unsigned long val) ...@@ -81,11 +82,11 @@ static inline void set_tls(unsigned long val)
*/ */
barrier(); barrier();
if (!tls_emu && !defer_tls_reg_update) { if (!tls_emu) {
if (has_tls_reg) { if (has_tls_reg && !defer_tls_reg_update) {
asm("mcr p15, 0, %0, c13, c0, 3" asm("mcr p15, 0, %0, c13, c0, 3"
: : "r" (val)); : : "r" (val));
} else { } else if (!has_tls_reg) {
#ifdef CONFIG_KUSER_HELPERS #ifdef CONFIG_KUSER_HELPERS
/* /*
* User space must never try to access this * User space must never try to access this
......
...@@ -292,12 +292,21 @@ ...@@ -292,12 +292,21 @@
.macro restore_user_regs, fast = 0, offset = 0 .macro restore_user_regs, fast = 0, offset = 0
#if defined(CONFIG_CPU_32v6K) && !defined(CONFIG_CPU_V6) #if defined(CONFIG_CPU_32v6K) || defined(CONFIG_SMP)
#if defined(CONFIG_CPU_V6) && defined(CONFIG_SMP)
ALT_SMP(b .L1_\@ )
ALT_UP( nop )
ldr_va r1, elf_hwcap
tst r1, #HWCAP_TLS @ hardware TLS available?
beq .L2_\@
.L1_\@:
#endif
@ The TLS register update is deferred until return to user space so we @ The TLS register update is deferred until return to user space so we
@ can use it for other things while running in the kernel @ can use it for other things while running in the kernel
get_thread_info r1 get_thread_info r1
ldr r1, [r1, #TI_TP_VALUE] ldr r1, [r1, #TI_TP_VALUE]
mcr p15, 0, r1, c13, c0, 3 @ set TLS register mcr p15, 0, r1, c13, c0, 3 @ set TLS register
.L2_\@:
#endif #endif
uaccess_enable r1, isb=0 uaccess_enable r1, isb=0
......
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