mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00

On UP systems, only a single task can be 'current' at the same time, which means we can use a global variable to track it. This means we can also enable THREAD_INFO_IN_TASK for those systems, as in that case, thread_info is accessed via current rather than the other way around, removing the need to store thread_info at the base of the task stack. This, in turn, permits us to enable IRQ stacks and vmap'ed stacks on UP systems as well. To partially mitigate the performance overhead of this arrangement, use a ADD/ADD/LDR sequence with the appropriate PC-relative group relocations to load the value of current when needed. This means that accessing current will still only require a single load as before, avoiding the need for a literal to carry the address of the global variable in each function. However, accessing thread_info will now require this load as well. Acked-by: Linus Walleij <linus.walleij@linaro.org> Acked-by: Nicolas Pitre <nico@fluxnic.net> Signed-off-by: Ard Biesheuvel <ardb@kernel.org> Tested-by: Marc Zyngier <maz@kernel.org> Tested-by: Vladimir Murzin <vladimir.murzin@arm.com> # ARMv7M
62 lines
1.7 KiB
C
62 lines
1.7 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/*
|
|
* Copyright (c) 2021 Keith Packard <keithp@keithp.com>
|
|
* Copyright (c) 2021 Google, LLC <ardb@kernel.org>
|
|
*/
|
|
|
|
#ifndef _ASM_ARM_CURRENT_H
|
|
#define _ASM_ARM_CURRENT_H
|
|
|
|
#ifndef __ASSEMBLY__
|
|
#include <asm/insn.h>
|
|
|
|
struct task_struct;
|
|
|
|
extern struct task_struct *__current;
|
|
|
|
static inline __attribute_const__ struct task_struct *get_current(void)
|
|
{
|
|
struct task_struct *cur;
|
|
|
|
#if __has_builtin(__builtin_thread_pointer) && \
|
|
defined(CONFIG_CURRENT_POINTER_IN_TPIDRURO) && \
|
|
!(defined(CONFIG_THUMB2_KERNEL) && \
|
|
defined(CONFIG_CC_IS_CLANG) && CONFIG_CLANG_VERSION < 130001)
|
|
/*
|
|
* Use the __builtin helper when available - this results in better
|
|
* code, especially when using GCC in combination with the per-task
|
|
* stack protector, as the compiler will recognize that it needs to
|
|
* load the TLS register only once in every function.
|
|
*
|
|
* Clang < 13.0.1 gets this wrong for Thumb2 builds:
|
|
* https://github.com/ClangBuiltLinux/linux/issues/1485
|
|
*/
|
|
cur = __builtin_thread_pointer();
|
|
#elif defined(CONFIG_CURRENT_POINTER_IN_TPIDRURO) || defined(CONFIG_SMP)
|
|
asm("0: mrc p15, 0, %0, c13, c0, 3 \n\t"
|
|
#ifdef CONFIG_CPU_V6
|
|
"1: \n\t"
|
|
" .subsection 1 \n\t"
|
|
"2: " LOAD_SYM_ARMV6(%0, __current) " \n\t"
|
|
" b 1b \n\t"
|
|
" .previous \n\t"
|
|
" .pushsection \".alt.smp.init\", \"a\" \n\t"
|
|
" .long 0b - . \n\t"
|
|
" b . + (2b - 0b) \n\t"
|
|
" .popsection \n\t"
|
|
#endif
|
|
: "=r"(cur));
|
|
#elif __LINUX_ARM_ARCH__>=7 || \
|
|
(defined(MODULE) && defined(CONFIG_ARM_MODULE_PLTS))
|
|
cur = __current;
|
|
#else
|
|
asm(LOAD_SYM_ARMV6(%0, __current) : "=r"(cur));
|
|
#endif
|
|
return cur;
|
|
}
|
|
|
|
#define current get_current()
|
|
|
|
#endif /* __ASSEMBLY__ */
|
|
|
|
#endif /* _ASM_ARM_CURRENT_H */
|