LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH 0/2]: ARM: Enable THREAD_INFO_IN_TASK
@ 2021-09-02 15:54 Keith Packard
2021-09-02 15:54 ` [PATCH 1/2] ARM: Add per-cpu variable holding cpu number Keith Packard
` (4 more replies)
0 siblings, 5 replies; 36+ messages in thread
From: Keith Packard @ 2021-09-02 15:54 UTC (permalink / raw)
To: linux-kernel
Cc: Abbott Liu, Alexander Sverdlin, Al Viro, Andrew Morton,
Anshuman Khandual, Ard Biesheuvel, Arnd Bergmann,
Bjorn Andersson, Florian Fainelli, Geert Uytterhoeven,
Hartley Sweeten, Jens Axboe, Jian Cai, Joe Perches,
Keith Packard, Linus Walleij, linux-arm-kernel, Maninder Singh,
Manivannan Sadhasivam, Marc Zyngier, Masahiro Yamada,
Mike Rapoport, Nick Desaulniers, Nick Desaulniers, Nicolas Pitre,
Peter Zijlstra, Russell King, Thomas Gleixner,
Uwe Kleine-König, Valentin Schneider, Vaneet Narang,
Wolfram Sang (Renesas),
YiFei Zhu, Keith Packard
Placing thread_info in the kernel stack leaves it vulnerable to stack
overflow attacks. This short series addresses that by using the
existing THREAD_INFO_IN_TASK infrastructure.
As this is my first patch in this part of the kernel, I'm looking for
feedback about the general approach as well as specific comments on
places where I've missed something.
I've only run this on armhf running under qemu, so while I've tried to
make patches for other code paths, I haven't been able to test those.
(yes, I know checkpatch.pl complains about whitespace in asm-offsets.c, I
decided to leave the existing whitespace alone)
Signed-off-by: Keith Packard <keithpac@amazon.com>
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH 1/2] ARM: Add per-cpu variable holding cpu number
2021-09-02 15:54 [PATCH 0/2]: ARM: Enable THREAD_INFO_IN_TASK Keith Packard
@ 2021-09-02 15:54 ` Keith Packard
2021-09-02 15:54 ` [PATCH 2/2] ARM: Move thread_info into task_struct Keith Packard
` (3 subsequent siblings)
4 siblings, 0 replies; 36+ messages in thread
From: Keith Packard @ 2021-09-02 15:54 UTC (permalink / raw)
To: linux-kernel
Cc: Abbott Liu, Alexander Sverdlin, Al Viro, Andrew Morton,
Anshuman Khandual, Ard Biesheuvel, Arnd Bergmann,
Bjorn Andersson, Florian Fainelli, Geert Uytterhoeven,
Hartley Sweeten, Jens Axboe, Jian Cai, Joe Perches,
Keith Packard, Linus Walleij, linux-arm-kernel, Maninder Singh,
Manivannan Sadhasivam, Marc Zyngier, Masahiro Yamada,
Mike Rapoport, Nick Desaulniers, Nick Desaulniers, Nicolas Pitre,
Peter Zijlstra, Russell King, Thomas Gleixner,
Uwe Kleine-König, Valentin Schneider, Vaneet Narang,
Wolfram Sang (Renesas),
YiFei Zhu, Keith Packard
To help move thread_info into task_struct, stop using the cpu number
contained in the thread_info block in C code and use a per-cpu
variable instead. This value will be initialized long before the
task_struct cpu value for the various idle threads are set, which
avoids ordering issues during CPU startup.
Signed-off-by: Keith Packard <keithpac@amazon.com>
---
arch/arm/include/asm/smp.h | 5 ++++-
arch/arm/kernel/smp.c | 14 ++++++++++++++
2 files changed, 18 insertions(+), 1 deletion(-)
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 5d508f5d56c4..3aca2c2089bc 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -15,7 +15,10 @@
# error "<asm/smp.h> included in non-SMP build"
#endif
-#define raw_smp_processor_id() (current_thread_info()->cpu)
+#define raw_smp_processor_id() this_cpu_read(cpu_number)
+#define __smp_processor_id() __this_cpu_read(cpu_number)
+
+DECLARE_PER_CPU_READ_MOSTLY(unsigned int, cpu_number);
struct seq_file;
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 74679240a9d8..0457e25109c6 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -51,6 +51,9 @@
#define CREATE_TRACE_POINTS
#include <trace/events/ipi.h>
+DEFINE_PER_CPU_READ_MOSTLY(unsigned int, cpu_number);
+EXPORT_PER_CPU_SYMBOL(cpu_number);
+
/*
* as from 2.5, kernels no longer have an init_tasks structure
* so we need some other way of telling a new secondary core
@@ -495,6 +498,7 @@ void __init smp_prepare_boot_cpu(void)
void __init smp_prepare_cpus(unsigned int max_cpus)
{
unsigned int ncores = num_possible_cpus();
+ unsigned int cpu;
init_cpu_topology();
@@ -505,6 +509,16 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
*/
if (max_cpus > ncores)
max_cpus = ncores;
+
+ /*
+ * Initialize the cpu_number value for each cpu before we
+ * start it. This ensures that the value is valid during cpu
+ * initialization, even before the idle task_struct cpu member
+ * is set
+ */
+ for_each_possible_cpu(cpu)
+ per_cpu(cpu_number, cpu) = cpu;
+
if (ncores > 1 && max_cpus) {
/*
* Initialise the present map, which describes the set of CPUs
--
2.33.0
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH 2/2] ARM: Move thread_info into task_struct
2021-09-02 15:54 [PATCH 0/2]: ARM: Enable THREAD_INFO_IN_TASK Keith Packard
2021-09-02 15:54 ` [PATCH 1/2] ARM: Add per-cpu variable holding cpu number Keith Packard
@ 2021-09-02 15:54 ` Keith Packard
2021-09-02 16:07 ` [PATCH 0/2]: ARM: Enable THREAD_INFO_IN_TASK Kees Cook
` (2 subsequent siblings)
4 siblings, 0 replies; 36+ messages in thread
From: Keith Packard @ 2021-09-02 15:54 UTC (permalink / raw)
To: linux-kernel
Cc: Abbott Liu, Alexander Sverdlin, Al Viro, Andrew Morton,
Anshuman Khandual, Ard Biesheuvel, Arnd Bergmann,
Bjorn Andersson, Florian Fainelli, Geert Uytterhoeven,
Hartley Sweeten, Jens Axboe, Jian Cai, Joe Perches,
Keith Packard, Linus Walleij, linux-arm-kernel, Maninder Singh,
Manivannan Sadhasivam, Marc Zyngier, Masahiro Yamada,
Mike Rapoport, Nick Desaulniers, Nick Desaulniers, Nicolas Pitre,
Peter Zijlstra, Russell King, Thomas Gleixner,
Uwe Kleine-König, Valentin Schneider, Vaneet Narang,
Wolfram Sang (Renesas),
YiFei Zhu, Keith Packard
This avoids many stack overflow attacks which modified the thread_info
structure by moving that into the task_struct as is done is almost all
other architectures.
The task_struct is now referenced by a per-cpu variable,
'current_task', allowing the current one on each cpu to be located
from both C and assembly.
This also involved removing the 'cpu' member from the thread_info
struct and using the one found in the task_struct instead. That is
mostly used in asm code, where it might reasonably be replaced with
the recent per-cpu 'cpu_number' variable.
Signed-off-by: Keith Packard <keithpac@amazon.com>
---
arch/arm/Kconfig | 1 +
arch/arm/include/asm/assembler.h | 63 ++++++++++++++++++++++++------
arch/arm/include/asm/current.h | 36 +++++++++++++++++
arch/arm/include/asm/smp.h | 1 +
arch/arm/include/asm/thread_info.h | 14 -------
arch/arm/include/asm/tls.h | 4 +-
arch/arm/include/asm/uaccess-asm.h | 6 +--
arch/arm/kernel/asm-offsets.c | 31 ++++++++-------
arch/arm/kernel/entry-armv.S | 45 ++++++++++-----------
arch/arm/kernel/entry-common.S | 20 +++++-----
arch/arm/kernel/entry-v7m.S | 12 +++---
arch/arm/kernel/iwmmxt.S | 14 +++----
arch/arm/kernel/process.c | 1 +
arch/arm/kernel/setup.c | 9 ++---
arch/arm/kernel/smp.c | 12 +++++-
arch/arm/lib/copy_from_user.S | 4 +-
arch/arm/lib/copy_to_user.S | 4 +-
arch/arm/mach-ep93xx/crunch-bits.S | 2 +-
arch/arm/vfp/entry.S | 4 +-
arch/arm/vfp/vfpmodule.c | 29 +++++++-------
20 files changed, 193 insertions(+), 119 deletions(-)
create mode 100644 arch/arm/include/asm/current.h
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 24804f11302d..1be16c7d7360 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -128,6 +128,7 @@ config ARM
select RTC_LIB
select SET_FS
select SYS_SUPPORTS_APM_EMULATION
+ select THREAD_INFO_IN_TASK
# Above selects are sorted alphabetically; please add new ones
# according to that. Thanks.
help
diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h
index e2b1fd558bf3..7723beed5cd9 100644
--- a/arch/arm/include/asm/assembler.h
+++ b/arch/arm/include/asm/assembler.h
@@ -200,13 +200,54 @@
.endr
/*
- * Get current thread_info.
+ * Get per-CPU offset
+ * rd: Destination register
*/
- .macro get_thread_info, rd
- ARM( mov \rd, sp, lsr #THREAD_SIZE_ORDER + PAGE_SHIFT )
- THUMB( mov \rd, sp )
- THUMB( lsr \rd, \rd, #THREAD_SIZE_ORDER + PAGE_SHIFT )
- mov \rd, \rd, lsl #THREAD_SIZE_ORDER + PAGE_SHIFT
+ .macro this_cpu_offset rd:req
+ mrc p15, 0, \rd, c13, c0, 4
+ .endm
+
+/*
+ * Load a per-cpu variable
+ * @dst: Destination register to receive value
+ * @sym: The name of the per-cpu variable
+ * @tmp: scratch register
+ */
+ .macro ldr_this_cpu dst : req, sym : req, tmp : req
+ movw \dst, #:lower16:\sym
+ movt \dst, #:upper16:\sym
+ this_cpu_offset \tmp
+ ldr \dst, [\dst, \tmp]
+ .endm
+
+/*
+ * Store a value in a per-cpu variable
+ * @src: Source register with value
+ * @sym: The name of the per-cpu variable
+ * @t1: scratch register 1
+ * @t2: scratch register 2
+ */
+ .macro str_this_cpu src : req, sym : req, t1 : req, t2 : req
+ movw \t1, #:lower16:\sym
+ movt \t1, #:upper16:\sym
+ this_cpu_offset \t2
+ str \src, [\t1, \t2]
+ .endm
+
+/*
+ * Get current task_info
+ * @dst: Destination register to receive current task
+ * @tmp: scratch register
+ */
+ .macro get_current, dst : req, tmp : req
+ ldr_this_cpu \dst, current_task, \tmp
+ .endm
+
+/*
+ * Set current task info
+ */
+ .macro set_current_task rs : req, t1 : req, t2 : req
+ str_this_cpu \rs, current_task, \t1, \t2
.endm
/*
@@ -214,19 +255,19 @@
*/
#ifdef CONFIG_PREEMPT_COUNT
.macro inc_preempt_count, ti, tmp
- ldr \tmp, [\ti, #TI_PREEMPT] @ get preempt count
+ ldr \tmp, [\ti, #TSK_TI_PREEMPT] @ get preempt count
add \tmp, \tmp, #1 @ increment it
- str \tmp, [\ti, #TI_PREEMPT]
+ str \tmp, [\ti, #TSK_TI_PREEMPT]
.endm
.macro dec_preempt_count, ti, tmp
- ldr \tmp, [\ti, #TI_PREEMPT] @ get preempt count
+ ldr \tmp, [\ti, #TSK_TI_PREEMPT] @ get preempt count
sub \tmp, \tmp, #1 @ decrement it
- str \tmp, [\ti, #TI_PREEMPT]
+ str \tmp, [\ti, #TSK_TI_PREEMPT]
.endm
.macro dec_preempt_count_ti, ti, tmp
- get_thread_info \ti
+ get_task_info \ti, \tmp
dec_preempt_count \ti, \tmp
.endm
#else
diff --git a/arch/arm/include/asm/current.h b/arch/arm/include/asm/current.h
new file mode 100644
index 000000000000..b389c4c0005c
--- /dev/null
+++ b/arch/arm/include/asm/current.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright © 2021 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef _ASM_ARM_CURRENT_H
+#define _ASM_ARM_CURRENT_H
+
+#include <linux/compiler.h>
+#include <linux/thread_info.h>
+#include <asm/percpu.h>
+
+#ifndef __ASSEMBLY__
+struct task_struct;
+
+DECLARE_PER_CPU(struct task_struct *, current_task);
+
+static __always_inline struct task_struct *get_current(void)
+{
+ return raw_cpu_read(current_task);
+}
+
+#define current get_current()
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_ARM_CURRENT_H */
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 3aca2c2089bc..02989d094fd8 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -64,6 +64,7 @@ struct secondary_data {
};
unsigned long swapper_pg_dir;
void *stack;
+ unsigned int cpu;
};
extern struct secondary_data secondary_data;
extern void secondary_startup(void);
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h
index 70d4cbc49ae1..995ca0bcb7b1 100644
--- a/arch/arm/include/asm/thread_info.h
+++ b/arch/arm/include/asm/thread_info.h
@@ -55,8 +55,6 @@ struct thread_info {
unsigned long flags; /* low level flags */
int preempt_count; /* 0 => preemptable, <0 => bug */
mm_segment_t addr_limit; /* address limit */
- struct task_struct *task; /* main task structure */
- __u32 cpu; /* cpu */
__u32 cpu_domain; /* cpu domain */
#ifdef CONFIG_STACKPROTECTOR_PER_TASK
unsigned long stack_canary;
@@ -77,23 +75,11 @@ struct thread_info {
#define INIT_THREAD_INFO(tsk) \
{ \
- .task = &tsk, \
.flags = 0, \
.preempt_count = INIT_PREEMPT_COUNT, \
.addr_limit = KERNEL_DS, \
}
-/*
- * how to get the thread information struct from C
- */
-static inline struct thread_info *current_thread_info(void) __attribute_const__;
-
-static inline struct thread_info *current_thread_info(void)
-{
- return (struct thread_info *)
- (current_stack_pointer & ~(THREAD_SIZE - 1));
-}
-
#define thread_saved_pc(tsk) \
((unsigned long)(task_thread_info(tsk)->cpu_context.pc))
#define thread_saved_sp(tsk) \
diff --git a/arch/arm/include/asm/tls.h b/arch/arm/include/asm/tls.h
index 5a66c3b13c92..309e870e70a3 100644
--- a/arch/arm/include/asm/tls.h
+++ b/arch/arm/include/asm/tls.h
@@ -14,7 +14,7 @@
mrc p15, 0, \tmp2, c13, c0, 2 @ get the user r/w register
mcr p15, 0, \tp, c13, c0, 3 @ set TLS register
mcr p15, 0, \tpuser, c13, c0, 2 @ and the user r/w register
- str \tmp2, [\base, #TI_TP_VALUE + 4] @ save it
+ str \tmp2, [\base, #TSK_TI_TP_VALUE + 4] @ save it
.endm
.macro switch_tls_v6, base, tp, tpuser, tmp1, tmp2
@@ -26,7 +26,7 @@
mrcne p15, 0, \tmp2, c13, c0, 2 @ get the user r/w register
mcrne p15, 0, \tp, c13, c0, 3 @ yes, set TLS 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, #TSK_TI_TP_VALUE + 4] @ save it
.endm
.macro switch_tls_software, base, tp, tpuser, tmp1, tmp2
diff --git a/arch/arm/include/asm/uaccess-asm.h b/arch/arm/include/asm/uaccess-asm.h
index e6eb7a2aaf1e..1c79d851a396 100644
--- a/arch/arm/include/asm/uaccess-asm.h
+++ b/arch/arm/include/asm/uaccess-asm.h
@@ -84,9 +84,9 @@
* if \disable is set.
*/
.macro uaccess_entry, tsk, tmp0, tmp1, tmp2, disable
- ldr \tmp1, [\tsk, #TI_ADDR_LIMIT]
+ ldr \tmp1, [\tsk, #TSK_TI_ADDR_LIMIT]
ldr \tmp2, =TASK_SIZE
- str \tmp2, [\tsk, #TI_ADDR_LIMIT]
+ str \tmp2, [\tsk, #TSK_TI_ADDR_LIMIT]
DACR( mrc p15, 0, \tmp0, c3, c0, 0)
DACR( str \tmp0, [sp, #SVC_DACR])
str \tmp1, [sp, #SVC_ADDR_LIMIT]
@@ -108,7 +108,7 @@
.macro uaccess_exit, tsk, tmp0, tmp1
ldr \tmp1, [sp, #SVC_ADDR_LIMIT]
DACR( ldr \tmp0, [sp, #SVC_DACR])
- str \tmp1, [\tsk, #TI_ADDR_LIMIT]
+ str \tmp1, [\tsk, #TSK_TI_ADDR_LIMIT]
DACR( mcr p15, 0, \tmp0, c3, c0, 0)
.endm
diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c
index 70993af22d80..9de799481fb2 100644
--- a/arch/arm/kernel/asm-offsets.c
+++ b/arch/arm/kernel/asm-offsets.c
@@ -41,33 +41,34 @@ int main(void)
DEFINE(TSK_STACK_CANARY, offsetof(struct task_struct, stack_canary));
#endif
BLANK();
- DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
- DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count));
- DEFINE(TI_ADDR_LIMIT, offsetof(struct thread_info, addr_limit));
- DEFINE(TI_TASK, offsetof(struct thread_info, task));
- DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
- DEFINE(TI_CPU_DOMAIN, offsetof(struct thread_info, cpu_domain));
- DEFINE(TI_CPU_SAVE, offsetof(struct thread_info, cpu_context));
- DEFINE(TI_USED_CP, offsetof(struct thread_info, used_cp));
- DEFINE(TI_TP_VALUE, offsetof(struct thread_info, tp_value));
- DEFINE(TI_FPSTATE, offsetof(struct thread_info, fpstate));
+ DEFINE(TSK_TI_FLAGS, offsetof(struct task_struct, thread_info.flags));
+ DEFINE(TSK_TI_PREEMPT, offsetof(struct task_struct, thread_info.preempt_count));
+ DEFINE(TSK_TI_ADDR_LIMIT, offsetof(struct task_struct, thread_info.addr_limit));
+ DEFINE(TSK_TI_CPU_DOMAIN, offsetof(struct task_struct, thread_info.cpu_domain));
+ DEFINE(TSK_TI_CPU_SAVE, offsetof(struct task_struct, thread_info.cpu_context));
+ DEFINE(TSK_TI_USED_CP, offsetof(struct task_struct, thread_info.used_cp));
+ DEFINE(TSK_TI_TP_VALUE, offsetof(struct task_struct, thread_info.tp_value));
+ DEFINE(TSK_TI_FPSTATE, offsetof(struct task_struct, thread_info.fpstate));
+#ifdef CONFIG_SMP
+ DEFINE(TSK_CPU, offsetof(struct task_struct, cpu));
+#endif
#ifdef CONFIG_VFP
- DEFINE(TI_VFPSTATE, offsetof(struct thread_info, vfpstate));
+ DEFINE(TSK_TI_VFPSTATE, offsetof(struct task_struct, thread_info.vfpstate));
#ifdef CONFIG_SMP
DEFINE(VFP_CPU, offsetof(union vfp_state, hard.cpu));
#endif
#endif
#ifdef CONFIG_ARM_THUMBEE
- DEFINE(TI_THUMBEE_STATE, offsetof(struct thread_info, thumbee_state));
+ DEFINE(TSK_TI_THUMBEE_STATE, offsetof(struct task_struct, thread_info.thumbee_state));
#endif
#ifdef CONFIG_IWMMXT
- DEFINE(TI_IWMMXT_STATE, offsetof(struct thread_info, fpstate.iwmmxt));
+ DEFINE(TSK_TI_IWMMXT_STATE, offsetof(struct task_struct, thread_info.fpstate.iwmmxt));
#endif
#ifdef CONFIG_CRUNCH
- DEFINE(TI_CRUNCH_STATE, offsetof(struct thread_info, crunchstate));
+ DEFINE(TSK_TI_CRUNCH_STATE, offsetof(struct task_struct, thread_info.crunchstate));
#endif
#ifdef CONFIG_STACKPROTECTOR_PER_TASK
- DEFINE(TI_STACK_CANARY, offsetof(struct thread_info, stack_canary));
+ DEFINE(TSK_TI_STACK_CANARY, offsetof(struct task_struct, thread_info.stack_canary));
#endif
DEFINE(THREAD_SZ_ORDER, THREAD_SIZE_ORDER);
BLANK();
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 0ea8529a4872..2196e4dd7877 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -179,7 +179,7 @@ ENDPROC(__und_invalid)
@
stmia r7, {r2 - r6}
- get_thread_info tsk
+ get_current tsk, r0
uaccess_entry tsk, r0, r1, r2, \uaccess
.if \trace
@@ -205,8 +205,8 @@ __irq_svc:
irq_handler
#ifdef CONFIG_PREEMPTION
- ldr r8, [tsk, #TI_PREEMPT] @ get preempt count
- ldr r0, [tsk, #TI_FLAGS] @ get flags
+ ldr r8, [tsk, #TSK_TI_PREEMPT] @ get preempt count
+ ldr r0, [tsk, #TSK_TI_FLAGS] @ get flags
teq r8, #0 @ if preempt count != 0
movne r0, #0 @ force flags to 0
tst r0, #_TIF_NEED_RESCHED
@@ -223,7 +223,7 @@ ENDPROC(__irq_svc)
svc_preempt:
mov r8, lr
1: bl preempt_schedule_irq @ irq en/disable is done inside
- ldr r0, [tsk, #TI_FLAGS] @ get new tasks TI_FLAGS
+ ldr r0, [tsk, #TSK_TI_FLAGS] @ get new tasks TI_FLAGS
tst r0, #_TIF_NEED_RESCHED
reteq r8 @ go again
b 1b
@@ -260,7 +260,7 @@ __und_svc:
bl __und_fault
__und_svc_finish:
- get_thread_info tsk
+ get_current tsk, r5
ldr r5, [sp, #S_PSR] @ Get SVC cpsr
svc_exit r5 @ return from exception
UNWIND(.fnend )
@@ -428,7 +428,7 @@ __irq_usr:
usr_entry
kuser_cmpxchg_check
irq_handler
- get_thread_info tsk
+ get_current tsk, why
mov why, #0
b ret_to_user_from_irq
UNWIND(.fnend )
@@ -572,12 +572,12 @@ ENDPROC(__und_usr)
@ Fall-through from Thumb-2 __und_usr
@
#ifdef CONFIG_NEON
- get_thread_info r10 @ get current thread
+ get_current r10, r6 @ get current thread
adr r6, .LCneon_thumb_opcodes
b 2f
#endif
call_fpe:
- get_thread_info r10 @ get current thread
+ get_current r10, r6 @ get current thread
#ifdef CONFIG_NEON
adr r6, .LCneon_arm_opcodes
2: ldr r5, [r6], #4 @ mask value
@@ -588,8 +588,8 @@ call_fpe:
cmp r8, r7 @ NEON instruction?
bne 2b
mov r7, #1
- strb r7, [r10, #TI_USED_CP + 10] @ mark CP#10 as used
- strb r7, [r10, #TI_USED_CP + 11] @ mark CP#11 as used
+ strb r7, [r10, #TSK_TI_USED_CP + 10] @ mark CP#10 as used
+ strb r7, [r10, #TSK_TI_USED_CP + 11] @ mark CP#11 as used
b do_vfp @ let VFP handler handle this
1:
#endif
@@ -599,12 +599,12 @@ call_fpe:
and r8, r0, #0x00000f00 @ mask out CP number
THUMB( lsr r8, r8, #8 )
mov r7, #1
- add r6, r10, #TI_USED_CP
+ add r6, r10, #TSK_TI_USED_CP
ARM( strb r7, [r6, r8, lsr #8] ) @ set appropriate used_cp[]
THUMB( strb r7, [r6, r8] ) @ set appropriate used_cp[]
#ifdef CONFIG_IWMMXT
@ Test if we need to give access to iWMMXt coprocessors
- ldr r5, [r10, #TI_FLAGS]
+ ldr r5, [r10, #TSK_TI_FLAGS]
rsbs r7, r8, #(1 << 8) @ CP 0 or 1 only
movscs r7, r5, lsr #(TIF_USING_IWMMXT + 1)
bcs iwmmxt_task_enable
@@ -674,7 +674,7 @@ call_fpe:
do_fpe:
ldr r4, .LCfp
- add r10, r10, #TI_FPSTATE @ r10 = workspace
+ add r10, r10, #TSK_TI_FPSTATE @ r10 = workspace
ldr pc, [r4] @ Call FP module USR entry point
/*
@@ -722,7 +722,7 @@ __pabt_usr:
ENTRY(ret_from_exception)
UNWIND(.fnstart )
UNWIND(.cantunwind )
- get_thread_info tsk
+ get_current tsk, why
mov why, #0
b ret_to_user
UNWIND(.fnend )
@@ -735,7 +735,7 @@ __fiq_usr:
kuser_cmpxchg_check
mov r0, sp @ struct pt_regs *regs
bl handle_fiq_as_nmi
- get_thread_info tsk
+ get_current tsk, r0
restore_user_regs fast = 0, offset = 0
UNWIND(.fnend )
ENDPROC(__fiq_usr)
@@ -748,21 +748,21 @@ ENDPROC(__fiq_usr)
ENTRY(__switch_to)
UNWIND(.fnstart )
UNWIND(.cantunwind )
- add ip, r1, #TI_CPU_SAVE
+ add ip, r1, #TSK_TI_CPU_SAVE
ARM( stmia ip!, {r4 - sl, fp, sp, lr} ) @ Store most regs on stack
THUMB( stmia ip!, {r4 - sl, fp} ) @ Store most regs on stack
THUMB( str sp, [ip], #4 )
THUMB( str lr, [ip], #4 )
- ldr r4, [r2, #TI_TP_VALUE]
- ldr r5, [r2, #TI_TP_VALUE + 4]
+ ldr r4, [r2, #TSK_TI_TP_VALUE]
+ ldr r5, [r2, #TSK_TI_TP_VALUE + 4]
#ifdef CONFIG_CPU_USE_DOMAINS
mrc p15, 0, r6, c3, c0, 0 @ Get domain register
- str r6, [r1, #TI_CPU_DOMAIN] @ Save old domain register
- ldr r6, [r2, #TI_CPU_DOMAIN]
+ str r6, [r1, #TSK_TI_CPU_DOMAIN] @ Save old domain register
+ ldr r6, [r2, #TSK_TI_CPU_DOMAIN]
#endif
switch_tls r1, r4, r5, r3, r7
#if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_SMP)
- ldr r7, [r2, #TI_TASK]
+ ldr r7, [r2, #TSK_TI_TASK]
ldr r8, =__stack_chk_guard
.if (TSK_STACK_CANARY > IMM12_MASK)
add r7, r7, #TSK_STACK_CANARY & ~IMM12_MASK
@@ -772,8 +772,9 @@ ENTRY(__switch_to)
#ifdef CONFIG_CPU_USE_DOMAINS
mcr p15, 0, r6, c3, c0, 0 @ Set domain register
#endif
+ set_current_task r2, r4, r5
mov r5, r0
- add r4, r2, #TI_CPU_SAVE
+ add r4, r2, #TSK_TI_CPU_SAVE
ldr r0, =thread_notify_head
mov r1, #THREAD_NOTIFY_SWITCH
bl atomic_notifier_call_chain
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 7f0b7aba1498..7a5044dbfc24 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -49,11 +49,11 @@ __ret_fast_syscall:
UNWIND(.fnstart )
UNWIND(.cantunwind )
disable_irq_notrace @ disable interrupts
- ldr r2, [tsk, #TI_ADDR_LIMIT]
+ ldr r2, [tsk, #TSK_TI_ADDR_LIMIT]
ldr r1, =TASK_SIZE
cmp r2, r1
blne addr_limit_check_failed
- ldr r1, [tsk, #TI_FLAGS] @ re-check for syscall tracing
+ ldr r1, [tsk, #TSK_TI_FLAGS] @ re-check for syscall tracing
movs r1, r1, lsl #16
bne fast_work_pending
@@ -87,11 +87,11 @@ __ret_fast_syscall:
bl do_rseq_syscall
#endif
disable_irq_notrace @ disable interrupts
- ldr r2, [tsk, #TI_ADDR_LIMIT]
+ ldr r2, [tsk, #TSK_TI_ADDR_LIMIT]
ldr r1, =TASK_SIZE
cmp r2, r1
blne addr_limit_check_failed
- ldr r1, [tsk, #TI_FLAGS] @ re-check for syscall tracing
+ ldr r1, [tsk, #TSK_TI_FLAGS] @ re-check for syscall tracing
movs r1, r1, lsl #16
beq no_work_pending
UNWIND(.fnend )
@@ -129,11 +129,11 @@ ret_slow_syscall:
#endif
disable_irq_notrace @ disable interrupts
ENTRY(ret_to_user_from_irq)
- ldr r2, [tsk, #TI_ADDR_LIMIT]
+ ldr r2, [tsk, #TSK_TI_ADDR_LIMIT]
ldr r1, =TASK_SIZE
cmp r2, r1
blne addr_limit_check_failed
- ldr r1, [tsk, #TI_FLAGS]
+ ldr r1, [tsk, #TSK_TI_FLAGS]
movs r1, r1, lsl #16
bne slow_work_pending
no_work_pending:
@@ -156,7 +156,7 @@ ENTRY(ret_from_fork)
movne r0, r4
badrne lr, 1f
retne r5
-1: get_thread_info tsk
+1: get_current tsk, r1
b ret_slow_syscall
ENDPROC(ret_from_fork)
@@ -243,7 +243,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
+ get_current tsk, r10
/*
* Reload the registers that may have been corrupted on entry to
* the syscall assembly (by tracing or context tracking.)
@@ -251,7 +251,7 @@ ENTRY(vector_swi)
TRACE( ldmia sp, {r0 - r3} )
local_restart:
- ldr r10, [tsk, #TI_FLAGS] @ check for syscall tracing
+ ldr r10, [tsk, #TSK_TI_FLAGS] @ check for syscall tracing
stmdb sp!, {r4, r5} @ push fifth and sixth args
tst r10, #_TIF_SYSCALL_WORK @ are we tracing syscalls?
@@ -278,7 +278,7 @@ local_restart:
9001:
sub lr, saved_pc, #4
str lr, [sp, #S_PC]
- get_thread_info tsk
+ get_current tsk, r1
b ret_fast_syscall
#endif
ENDPROC(vector_swi)
diff --git a/arch/arm/kernel/entry-v7m.S b/arch/arm/kernel/entry-v7m.S
index d0e898608d30..4de5ee2a432d 100644
--- a/arch/arm/kernel/entry-v7m.S
+++ b/arch/arm/kernel/entry-v7m.S
@@ -57,8 +57,8 @@ __irq_entry:
tst r0, V7M_SCB_ICSR_RETTOBASE
beq 2f
- get_thread_info tsk
- ldr r2, [tsk, #TI_FLAGS]
+ get_current tsk, r2
+ ldr r2, [tsk, #TSK_TI_FLAGS]
movs r2, r2, lsl #16
beq 2f @ no work pending
mov r0, #V7M_SCB_ICSR_PENDSVSET
@@ -83,7 +83,7 @@ __pendsv_entry:
str r0, [r1, V7M_SCB_ICSR] @ clear PendSV
@ execute the pending work, including reschedule
- get_thread_info tsk
+ get_current tsk, why
mov why, #0
b ret_to_user_from_irq
ENDPROC(__pendsv_entry)
@@ -96,17 +96,19 @@ ENDPROC(__pendsv_entry)
ENTRY(__switch_to)
.fnstart
.cantunwind
- add ip, r1, #TI_CPU_SAVE
+ add ip, r1, #TSK_TI_CPU_SAVE
stmia ip!, {r4 - r11} @ Store most regs on stack
str sp, [ip], #4
str lr, [ip], #4
mov r5, r0
- add r4, r2, #TI_CPU_SAVE
+ add r4, r2, #TSK_TI_CPU_SAVE
ldr r0, =thread_notify_head
mov r1, #THREAD_NOTIFY_SWITCH
bl atomic_notifier_call_chain
mov ip, r4
mov r0, r5
+ ldr r7, [r2, #TSK_TI_TASK]
+ set_current_task r7, r4, r5
ldmia ip!, {r4 - r11} @ Load all regs saved previously
ldr sp, [ip]
ldr pc, [ip, #4]!
diff --git a/arch/arm/kernel/iwmmxt.S b/arch/arm/kernel/iwmmxt.S
index d2b4ac06e4ed..f709914b9029 100644
--- a/arch/arm/kernel/iwmmxt.S
+++ b/arch/arm/kernel/iwmmxt.S
@@ -84,7 +84,7 @@ ENTRY(iwmmxt_task_enable)
PJ4(mcr p15, 0, r2, c1, c0, 2)
ldr r3, =concan_owner
- add r0, r10, #TI_IWMMXT_STATE @ get task Concan save area
+ add r0, r10, #TSK_TI_IWMMXT_STATE @ get task Concan save area
ldr r2, [sp, #60] @ current task pc value
ldr r1, [r3] @ get current Concan owner
str r0, [r3] @ this task now owns Concan regs
@@ -96,7 +96,7 @@ ENTRY(iwmmxt_task_enable)
bl concan_save
#ifdef CONFIG_PREEMPT_COUNT
- get_thread_info r10
+ get_current r10, r3
#endif
4: dec_preempt_count r10, r3
ret r9 @ normal exit from exception
@@ -199,7 +199,7 @@ ENTRY(iwmmxt_task_disable)
msr cpsr_c, r2
ldr r3, =concan_owner
- add r2, r0, #TI_IWMMXT_STATE @ get task Concan save area
+ add r2, r0, #TSK_TI_IWMMXT_STATE @ get task Concan save area
ldr r1, [r3] @ get current Concan owner
teq r1, #0 @ any current owner?
beq 1f @ no: quit
@@ -251,7 +251,7 @@ ENTRY(iwmmxt_task_copy)
msr cpsr_c, r2
ldr r3, =concan_owner
- add r2, r0, #TI_IWMMXT_STATE @ get task Concan save area
+ add r2, r0, #TSK_TI_IWMMXT_STATE @ get task Concan save area
ldr r3, [r3] @ get current Concan owner
teq r2, r3 @ does this task own it...
beq 1f
@@ -289,7 +289,7 @@ ENTRY(iwmmxt_task_restore)
msr cpsr_c, r2
ldr r3, =concan_owner
- add r2, r0, #TI_IWMMXT_STATE @ get task Concan save area
+ add r2, r0, #TSK_TI_IWMMXT_STATE @ get task Concan save area
ldr r3, [r3] @ get current Concan owner
bic r2, r2, #0x7 @ 64-bit alignment
teq r2, r3 @ does this task own it...
@@ -328,7 +328,7 @@ ENTRY(iwmmxt_task_switch)
bne 1f @ yes: block them for next task
ldr r2, =concan_owner
- add r3, r0, #TI_IWMMXT_STATE @ get next task Concan save area
+ add r3, r0, #TSK_TI_IWMMXT_STATE @ get next task Concan save area
ldr r2, [r2] @ get current Concan owner
teq r2, r3 @ next task owns it?
retne lr @ no: leave Concan disabled
@@ -355,7 +355,7 @@ ENTRY(iwmmxt_task_release)
orr ip, r2, #PSR_I_BIT @ disable interrupts
msr cpsr_c, ip
ldr r3, =concan_owner
- add r0, r0, #TI_IWMMXT_STATE @ get task Concan save area
+ add r0, r0, #TSK_TI_IWMMXT_STATE @ get task Concan save area
ldr r1, [r3] @ get current Concan owner
eors r0, r0, r1 @ if equal...
streq r0, [r3] @ then clear ownership
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 6324f4db9b02..c7539f319f96 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -27,6 +27,7 @@
#include <linux/random.h>
#include <linux/hw_breakpoint.h>
#include <linux/leds.h>
+#include <linux/percpu.h>
#include <asm/processor.h>
#include <asm/thread_notify.h>
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 73ca7797b92f..a5a52817948a 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -532,12 +532,6 @@ void notrace cpu_init(void)
BUG();
}
- /*
- * This only works on resume and secondary cores. For booting on the
- * boot cpu, smp_prepare_boot_cpu is called after percpu area setup.
- */
- set_my_cpu_offset(per_cpu_offset(cpu));
-
cpu_proc_init();
/*
@@ -733,6 +727,9 @@ static void __init setup_processor(void)
elf_hwcap_fixup();
cacheid_init();
+
+ set_my_cpu_offset(per_cpu_offset(0));
+
cpu_init();
}
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 0457e25109c6..9b584811baad 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -51,6 +51,10 @@
#define CREATE_TRACE_POINTS
#include <trace/events/ipi.h>
+DEFINE_PER_CPU(struct task_struct *, current_task) ____cacheline_aligned =
+ &init_task;
+EXPORT_PER_CPU_SYMBOL(current_task);
+
DEFINE_PER_CPU_READ_MOSTLY(unsigned int, cpu_number);
EXPORT_PER_CPU_SYMBOL(cpu_number);
@@ -156,8 +160,11 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
secondary_data.pgdir = virt_to_phys(idmap_pgd);
secondary_data.swapper_pg_dir = get_arch_pgd(swapper_pg_dir);
#endif
+ secondary_data.cpu = cpu;
sync_cache_w(&secondary_data);
+ per_cpu(current_task, cpu) = idle;
+
/*
* Now bring the CPU into our world.
*/
@@ -406,7 +413,9 @@ static void smp_store_cpu_info(unsigned int cpuid)
asmlinkage void secondary_start_kernel(void)
{
struct mm_struct *mm = &init_mm;
- unsigned int cpu;
+ unsigned int cpu = secondary_data.cpu;
+
+ set_my_cpu_offset(per_cpu_offset(cpu));
secondary_biglittle_init();
@@ -423,7 +432,6 @@ asmlinkage void secondary_start_kernel(void)
* All kernel threads share the same mm context; grab a
* reference and switch to it.
*/
- cpu = smp_processor_id();
mmgrab(mm);
current->active_mm = mm;
cpumask_set_cpu(cpu, mm_cpumask(mm));
diff --git a/arch/arm/lib/copy_from_user.S b/arch/arm/lib/copy_from_user.S
index f8016e3db65d..4ed04f91ed0d 100644
--- a/arch/arm/lib/copy_from_user.S
+++ b/arch/arm/lib/copy_from_user.S
@@ -109,8 +109,8 @@
ENTRY(arm_copy_from_user)
#ifdef CONFIG_CPU_SPECTRE
- get_thread_info r3
- ldr r3, [r3, #TI_ADDR_LIMIT]
+ get_current r3, ip
+ ldr r3, [r3, #TSK_TI_ADDR_LIMIT]
uaccess_mask_range_ptr r1, r2, r3, ip
#endif
diff --git a/arch/arm/lib/copy_to_user.S b/arch/arm/lib/copy_to_user.S
index ebfe4cb3d912..229061cfb5b0 100644
--- a/arch/arm/lib/copy_to_user.S
+++ b/arch/arm/lib/copy_to_user.S
@@ -109,8 +109,8 @@
ENTRY(__copy_to_user_std)
WEAK(arm_copy_to_user)
#ifdef CONFIG_CPU_SPECTRE
- get_thread_info r3
- ldr r3, [r3, #TI_ADDR_LIMIT]
+ get_current r3, ip
+ ldr r3, [r3, #TSK_TI_ADDR_LIMIT]
uaccess_mask_range_ptr r0, r2, r3, ip
#endif
diff --git a/arch/arm/mach-ep93xx/crunch-bits.S b/arch/arm/mach-ep93xx/crunch-bits.S
index fb2dbf76f09e..dad62e3d4b03 100644
--- a/arch/arm/mach-ep93xx/crunch-bits.S
+++ b/arch/arm/mach-ep93xx/crunch-bits.S
@@ -192,7 +192,7 @@ crunch_load:
1:
#ifdef CONFIG_PREEMPT_COUNT
- get_thread_info r10
+ get_task_info r10, r3
#endif
2: dec_preempt_count r10, r3
ret lr
diff --git a/arch/arm/vfp/entry.S b/arch/arm/vfp/entry.S
index 27b0a1f27fbd..003554f8393d 100644
--- a/arch/arm/vfp/entry.S
+++ b/arch/arm/vfp/entry.S
@@ -24,8 +24,8 @@
ENTRY(do_vfp)
inc_preempt_count r10, r4
ldr r4, .LCvfp
- ldr r11, [r10, #TI_CPU] @ CPU number
- add r10, r10, #TI_VFPSTATE @ r10 = workspace
+ ldr r11, [r10, #TSK_CPU] @ CPU number
+ add r10, r10, #TSK_TI_VFPSTATE @ r10 = workspace
ldr pc, [r4] @ call VFP entry point
ENDPROC(do_vfp)
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 2cb355c1b5b7..4e2707fba8fd 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -143,22 +143,22 @@ static void vfp_thread_copy(struct thread_info *thread)
* THREAD_NOFTIFY_SWTICH:
* - the previously running thread will not be scheduled onto another CPU.
* - the next thread to be run (v) will not be running on another CPU.
- * - thread->cpu is the local CPU number
+ * - tsk->cpu is the local CPU number
* - not preemptible as we're called in the middle of a thread switch
* THREAD_NOTIFY_FLUSH:
* - the thread (v) will be running on the local CPU, so
- * v === current_thread_info()
- * - thread->cpu is the local CPU number at the time it is accessed,
+ * v === current
+ * - tsk->cpu is the local CPU number at the time it is accessed,
* but may change at any time.
* - we could be preempted if tree preempt rcu is enabled, so
- * it is unsafe to use thread->cpu.
+ * it is unsafe to use tsk->cpu.
* THREAD_NOTIFY_EXIT
* - we could be preempted if tree preempt rcu is enabled, so
- * it is unsafe to use thread->cpu.
+ * it is unsafe to use tsk->cpu.
*/
static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
{
- struct thread_info *thread = v;
+ struct task_struct *tsk = v;
u32 fpexc;
#ifdef CONFIG_SMP
unsigned int cpu;
@@ -169,7 +169,7 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
fpexc = fmrx(FPEXC);
#ifdef CONFIG_SMP
- cpu = thread->cpu;
+ cpu = tsk->cpu;
/*
* On SMP, if VFP is enabled, save the old state in
@@ -188,15 +188,15 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
break;
case THREAD_NOTIFY_FLUSH:
- vfp_thread_flush(thread);
+ vfp_thread_flush(&tsk->thread_info);
break;
case THREAD_NOTIFY_EXIT:
- vfp_thread_exit(thread);
+ vfp_thread_exit(&tsk->thread_info);
break;
case THREAD_NOTIFY_COPY:
- vfp_thread_copy(thread);
+ vfp_thread_copy(&tsk->thread_info);
break;
}
@@ -448,26 +448,25 @@ void __init vfp_disable(void)
#ifdef CONFIG_CPU_PM
static int vfp_pm_suspend(void)
{
- struct thread_info *ti = current_thread_info();
u32 fpexc = fmrx(FPEXC);
/* if vfp is on, then save state for resumption */
if (fpexc & FPEXC_EN) {
pr_debug("%s: saving vfp state\n", __func__);
- vfp_save_state(&ti->vfpstate, fpexc);
+ vfp_save_state(¤t->thread_info.vfpstate, fpexc);
/* disable, just in case */
fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
- } else if (vfp_current_hw_state[ti->cpu]) {
+ } else if (vfp_current_hw_state[current->cpu]) {
#ifndef CONFIG_SMP
fmxr(FPEXC, fpexc | FPEXC_EN);
- vfp_save_state(vfp_current_hw_state[ti->cpu], fpexc);
+ vfp_save_state(vfp_current_hw_state[current->cpu], fpexc);
fmxr(FPEXC, fpexc);
#endif
}
/* clear any information we had about last context state */
- vfp_current_hw_state[ti->cpu] = NULL;
+ vfp_current_hw_state[current->cpu] = NULL;
return 0;
}
--
2.33.0
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH 0/2]: ARM: Enable THREAD_INFO_IN_TASK
2021-09-02 15:54 [PATCH 0/2]: ARM: Enable THREAD_INFO_IN_TASK Keith Packard
2021-09-02 15:54 ` [PATCH 1/2] ARM: Add per-cpu variable holding cpu number Keith Packard
2021-09-02 15:54 ` [PATCH 2/2] ARM: Move thread_info into task_struct Keith Packard
@ 2021-09-02 16:07 ` Kees Cook
2021-09-02 16:18 ` Ard Biesheuvel
2021-09-02 16:54 ` Russell King (Oracle)
2021-09-02 16:53 ` Russell King (Oracle)
2021-09-04 6:09 ` [PATCH 0/2] ARM: support THREAD_INFO_IN_TASK (v7 only) (v2) Keith Packard
4 siblings, 2 replies; 36+ messages in thread
From: Kees Cook @ 2021-09-02 16:07 UTC (permalink / raw)
To: Keith Packard
Cc: linux-kernel, Abbott Liu, Alexander Sverdlin, Al Viro,
Andrew Morton, Anshuman Khandual, Ard Biesheuvel, Arnd Bergmann,
Bjorn Andersson, Florian Fainelli, Geert Uytterhoeven,
Hartley Sweeten, Jens Axboe, Jian Cai, Joe Perches,
Linus Walleij, linux-arm-kernel, Maninder Singh,
Manivannan Sadhasivam, Marc Zyngier, Masahiro Yamada,
Mike Rapoport, Nick Desaulniers, Nick Desaulniers, Nicolas Pitre,
Peter Zijlstra, Russell King, Thomas Gleixner,
Uwe Kleine-König, Valentin Schneider, Vaneet Narang,
Wolfram Sang (Renesas),
YiFei Zhu, Keith Packard, linux-hardening
On Thu, Sep 02, 2021 at 08:54:26AM -0700, Keith Packard wrote:
> Placing thread_info in the kernel stack leaves it vulnerable to stack
> overflow attacks. This short series addresses that by using the
> existing THREAD_INFO_IN_TASK infrastructure.
Very cool! Thanks for working on this. If you want, you can refer to the
KSPP bug for this too:
https://github.com/KSPP/linux/issues/1
(Anyone want to do MIPS?)
-Kees
--
Kees Cook
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH 0/2]: ARM: Enable THREAD_INFO_IN_TASK
2021-09-02 16:07 ` [PATCH 0/2]: ARM: Enable THREAD_INFO_IN_TASK Kees Cook
@ 2021-09-02 16:18 ` Ard Biesheuvel
2021-09-02 17:37 ` Kees Cook
2021-09-02 16:54 ` Russell King (Oracle)
1 sibling, 1 reply; 36+ messages in thread
From: Ard Biesheuvel @ 2021-09-02 16:18 UTC (permalink / raw)
To: Kees Cook
Cc: Keith Packard, Linux Kernel Mailing List, Abbott Liu,
Alexander Sverdlin, Al Viro, Andrew Morton, Anshuman Khandual,
Arnd Bergmann, Bjorn Andersson, Florian Fainelli,
Geert Uytterhoeven, Hartley Sweeten, Jens Axboe, Jian Cai,
Joe Perches, Linus Walleij, Linux ARM, Maninder Singh,
Manivannan Sadhasivam, Marc Zyngier, Masahiro Yamada,
Mike Rapoport, Nick Desaulniers, Nick Desaulniers, Nicolas Pitre,
Peter Zijlstra, Russell King, Thomas Gleixner,
Uwe Kleine-König, Valentin Schneider, Vaneet Narang,
Wolfram Sang (Renesas),
YiFei Zhu, Keith Packard, linux-hardening
On Thu, 2 Sept 2021 at 18:07, Kees Cook <keescook@chromium.org> wrote:
>
> On Thu, Sep 02, 2021 at 08:54:26AM -0700, Keith Packard wrote:
> > Placing thread_info in the kernel stack leaves it vulnerable to stack
> > overflow attacks. This short series addresses that by using the
> > existing THREAD_INFO_IN_TASK infrastructure.
>
> Very cool! Thanks for working on this. If you want, you can refer to the
> KSPP bug for this too:
> https://github.com/KSPP/linux/issues/1
>
> (Anyone want to do MIPS?)
>
I take it this breaks the GCC plugin based per-task stack protector,
given that it emits code to mask the stack pointer and apply an offset
to the resulting value.
It would be nice if we could replace this with something suitable for
THREAD_INFO_IN_TASK, and if it is suitable enough, try and get the
GCC/Clang folks to adopt it as well (which was never going to happen
for the stack pointer mask/offset approach)
Where can I find these patches? I don't see them on linux-arm-kernel@
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH 0/2]: ARM: Enable THREAD_INFO_IN_TASK
2021-09-02 15:54 [PATCH 0/2]: ARM: Enable THREAD_INFO_IN_TASK Keith Packard
` (2 preceding siblings ...)
2021-09-02 16:07 ` [PATCH 0/2]: ARM: Enable THREAD_INFO_IN_TASK Kees Cook
@ 2021-09-02 16:53 ` Russell King (Oracle)
2021-09-02 17:35 ` Kees Cook
2021-09-02 17:58 ` Keith Packard
2021-09-04 6:09 ` [PATCH 0/2] ARM: support THREAD_INFO_IN_TASK (v7 only) (v2) Keith Packard
4 siblings, 2 replies; 36+ messages in thread
From: Russell King (Oracle) @ 2021-09-02 16:53 UTC (permalink / raw)
To: Keith Packard
Cc: linux-kernel, Abbott Liu, Alexander Sverdlin, Al Viro,
Andrew Morton, Anshuman Khandual, Ard Biesheuvel, Arnd Bergmann,
Bjorn Andersson, Florian Fainelli, Geert Uytterhoeven,
Hartley Sweeten, Jens Axboe, Jian Cai, Joe Perches,
Linus Walleij, linux-arm-kernel, Maninder Singh,
Manivannan Sadhasivam, Marc Zyngier, Masahiro Yamada,
Mike Rapoport, Nick Desaulniers, Nick Desaulniers, Nicolas Pitre,
Peter Zijlstra, Thomas Gleixner, Uwe Kleine-König,
Valentin Schneider, Vaneet Narang, Wolfram Sang (Renesas),
YiFei Zhu, Keith Packard
On Thu, Sep 02, 2021 at 08:54:26AM -0700, Keith Packard wrote:
> Placing thread_info in the kernel stack leaves it vulnerable to stack
> overflow attacks. This short series addresses that by using the
> existing THREAD_INFO_IN_TASK infrastructure.
>
> As this is my first patch in this part of the kernel, I'm looking for
> feedback about the general approach as well as specific comments on
> places where I've missed something.
>
> I've only run this on armhf running under qemu, so while I've tried to
> make patches for other code paths, I haven't been able to test those.
>
> (yes, I know checkpatch.pl complains about whitespace in asm-offsets.c, I
> decided to leave the existing whitespace alone)
>
> Signed-off-by: Keith Packard <keithpac@amazon.com>
I think you're introducing a circular dependency with this for
certain kernel configurations:
E.g. Have you tried running this with CONFIG_CPU_V6 enabled?
+#define raw_smp_processor_id() this_cpu_read(cpu_number)
+#define __smp_processor_id() __this_cpu_read(cpu_number)
+
+DECLARE_PER_CPU_READ_MOSTLY(unsigned int, cpu_number);
this_cpu_read() is defined as:
#define this_cpu_read(pcp) __pcpu_size_call_return(this_cpu_read_, pcp)
(which will call this_cpu_read_4)
#define this_cpu_read_4(pcp) this_cpu_generic_read(pcp)
=> __this_cpu_generic_read_nopreempt()
=> ___ret = READ_ONCE(*raw_cpu_ptr(&(pcp)));
#define raw_cpu_ptr(ptr) \
({ \
__verify_pcpu_ptr(ptr); \
arch_raw_cpu_ptr(ptr); \
})
#ifndef arch_raw_cpu_ptr
#define arch_raw_cpu_ptr(ptr) SHIFT_PERCPU_PTR(ptr, __my_cpu_offset)
#endif
#ifndef __my_cpu_offset
#define __my_cpu_offset per_cpu_offset(raw_smp_processor_id())
#endif
... which then leads back to a use of raw_smp_processor_id(), thereby
creating a circular loop of preprocessor definitions that the compiler
can't resolve.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH 0/2]: ARM: Enable THREAD_INFO_IN_TASK
2021-09-02 16:07 ` [PATCH 0/2]: ARM: Enable THREAD_INFO_IN_TASK Kees Cook
2021-09-02 16:18 ` Ard Biesheuvel
@ 2021-09-02 16:54 ` Russell King (Oracle)
1 sibling, 0 replies; 36+ messages in thread
From: Russell King (Oracle) @ 2021-09-02 16:54 UTC (permalink / raw)
To: Kees Cook
Cc: Keith Packard, linux-kernel, Abbott Liu, Alexander Sverdlin,
Al Viro, Andrew Morton, Anshuman Khandual, Ard Biesheuvel,
Arnd Bergmann, Bjorn Andersson, Florian Fainelli,
Geert Uytterhoeven, Hartley Sweeten, Jens Axboe, Jian Cai,
Joe Perches, Linus Walleij, linux-arm-kernel, Maninder Singh,
Manivannan Sadhasivam, Marc Zyngier, Masahiro Yamada,
Mike Rapoport, Nick Desaulniers, Nick Desaulniers, Nicolas Pitre,
Peter Zijlstra, Thomas Gleixner, Uwe Kleine-König,
Valentin Schneider, Vaneet Narang, Wolfram Sang (Renesas),
YiFei Zhu, Keith Packard, linux-hardening
On Thu, Sep 02, 2021 at 09:07:42AM -0700, Kees Cook wrote:
> On Thu, Sep 02, 2021 at 08:54:26AM -0700, Keith Packard wrote:
> > Placing thread_info in the kernel stack leaves it vulnerable to stack
> > overflow attacks. This short series addresses that by using the
> > existing THREAD_INFO_IN_TASK infrastructure.
>
> Very cool! Thanks for working on this. If you want, you can refer to the
> KSPP bug for this too:
> https://github.com/KSPP/linux/issues/1
Not so fast. It's buggy. I've rejected this "solution" before.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH 0/2]: ARM: Enable THREAD_INFO_IN_TASK
2021-09-02 16:53 ` Russell King (Oracle)
@ 2021-09-02 17:35 ` Kees Cook
2021-09-02 17:58 ` Keith Packard
1 sibling, 0 replies; 36+ messages in thread
From: Kees Cook @ 2021-09-02 17:35 UTC (permalink / raw)
To: Russell King (Oracle)
Cc: Keith Packard, linux-kernel, Abbott Liu, Alexander Sverdlin,
Al Viro, Andrew Morton, Anshuman Khandual, Ard Biesheuvel,
Arnd Bergmann, Bjorn Andersson, Florian Fainelli,
Geert Uytterhoeven, Hartley Sweeten, Jens Axboe, Jian Cai,
Joe Perches, Linus Walleij, linux-arm-kernel, Maninder Singh,
Manivannan Sadhasivam, Marc Zyngier, Masahiro Yamada,
Mike Rapoport, Nick Desaulniers, Nicolas Pitre, Peter Zijlstra,
Thomas Gleixner, Uwe Kleine-König, Valentin Schneider,
Vaneet Narang, Wolfram Sang (Renesas),
YiFei Zhu, Keith Packard
On Thu, Sep 02, 2021 at 05:53:53PM +0100, Russell King (Oracle) wrote:
> On Thu, Sep 02, 2021 at 08:54:26AM -0700, Keith Packard wrote:
> > Placing thread_info in the kernel stack leaves it vulnerable to stack
> > overflow attacks. This short series addresses that by using the
> > existing THREAD_INFO_IN_TASK infrastructure.
> >
> > As this is my first patch in this part of the kernel, I'm looking for
> > feedback about the general approach as well as specific comments on
> > places where I've missed something.
> >
> > I've only run this on armhf running under qemu, so while I've tried to
> > make patches for other code paths, I haven't been able to test those.
> >
> > (yes, I know checkpatch.pl complains about whitespace in asm-offsets.c, I
> > decided to leave the existing whitespace alone)
> >
> > Signed-off-by: Keith Packard <keithpac@amazon.com>
>
> I think you're introducing a circular dependency with this for
> certain kernel configurations:
>
> E.g. Have you tried running this with CONFIG_CPU_V6 enabled?
>
> +#define raw_smp_processor_id() this_cpu_read(cpu_number)
> +#define __smp_processor_id() __this_cpu_read(cpu_number)
> +
> +DECLARE_PER_CPU_READ_MOSTLY(unsigned int, cpu_number);
>
> this_cpu_read() is defined as:
>
> #define this_cpu_read(pcp) __pcpu_size_call_return(this_cpu_read_, pcp)
> (which will call this_cpu_read_4)
>
> #define this_cpu_read_4(pcp) this_cpu_generic_read(pcp)
> => __this_cpu_generic_read_nopreempt()
> => ___ret = READ_ONCE(*raw_cpu_ptr(&(pcp)));
>
> #define raw_cpu_ptr(ptr) \
> ({ \
> __verify_pcpu_ptr(ptr); \
> arch_raw_cpu_ptr(ptr); \
> })
>
> #ifndef arch_raw_cpu_ptr
> #define arch_raw_cpu_ptr(ptr) SHIFT_PERCPU_PTR(ptr, __my_cpu_offset)
> #endif
>
> #ifndef __my_cpu_offset
> #define __my_cpu_offset per_cpu_offset(raw_smp_processor_id())
> #endif
>
> ... which then leads back to a use of raw_smp_processor_id(), thereby
> creating a circular loop of preprocessor definitions that the compiler
> can't resolve.
If this isn't easy to fix, perhaps this can be a V7-only feature?
--
Kees Cook
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH 0/2]: ARM: Enable THREAD_INFO_IN_TASK
2021-09-02 16:18 ` Ard Biesheuvel
@ 2021-09-02 17:37 ` Kees Cook
0 siblings, 0 replies; 36+ messages in thread
From: Kees Cook @ 2021-09-02 17:37 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: Keith Packard, Linux Kernel Mailing List, Abbott Liu,
Alexander Sverdlin, Al Viro, Andrew Morton, Anshuman Khandual,
Arnd Bergmann, Bjorn Andersson, Florian Fainelli,
Geert Uytterhoeven, Hartley Sweeten, Jens Axboe, Jian Cai,
Joe Perches, Linus Walleij, Linux ARM, Maninder Singh,
Manivannan Sadhasivam, Marc Zyngier, Masahiro Yamada,
Mike Rapoport, Nick Desaulniers, Nick Desaulniers, Nicolas Pitre,
Peter Zijlstra, Russell King, Thomas Gleixner,
Uwe Kleine-König, Valentin Schneider, Vaneet Narang,
Wolfram Sang (Renesas),
YiFei Zhu, Keith Packard, linux-hardening
On Thu, Sep 02, 2021 at 06:18:29PM +0200, Ard Biesheuvel wrote:
> On Thu, 2 Sept 2021 at 18:07, Kees Cook <keescook@chromium.org> wrote:
> >
> > On Thu, Sep 02, 2021 at 08:54:26AM -0700, Keith Packard wrote:
> > > Placing thread_info in the kernel stack leaves it vulnerable to stack
> > > overflow attacks. This short series addresses that by using the
> > > existing THREAD_INFO_IN_TASK infrastructure.
> >
> > Very cool! Thanks for working on this. If you want, you can refer to the
> > KSPP bug for this too:
> > https://github.com/KSPP/linux/issues/1
> >
> > (Anyone want to do MIPS?)
> >
>
> I take it this breaks the GCC plugin based per-task stack protector,
> given that it emits code to mask the stack pointer and apply an offset
> to the resulting value.
>
> It would be nice if we could replace this with something suitable for
> THREAD_INFO_IN_TASK, and if it is suitable enough, try and get the
> GCC/Clang folks to adopt it as well (which was never going to happen
> for the stack pointer mask/offset approach)
I'd love to see the native GCC offset stuff work on arm32, but it's not
clear to me how much work that would be. It's implemented for several
architectures already. I've tried to capture the matrix here:
https://github.com/KSPP/linux/issues/29
-Kees
--
Kees Cook
^ permalink raw reply [flat|nested] 36+ messages in thread
* RE: [PATCH 0/2]: ARM: Enable THREAD_INFO_IN_TASK
2021-09-02 16:53 ` Russell King (Oracle)
2021-09-02 17:35 ` Kees Cook
@ 2021-09-02 17:58 ` Keith Packard
1 sibling, 0 replies; 36+ messages in thread
From: Keith Packard @ 2021-09-02 17:58 UTC (permalink / raw)
To: Russell King (Oracle)
Cc: linux-kernel, Abbott Liu, Alexander Sverdlin, Al Viro,
Andrew Morton, Anshuman Khandual, Ard Biesheuvel, Arnd Bergmann,
Bjorn Andersson, Florian Fainelli, Geert Uytterhoeven,
Hartley Sweeten, Jens Axboe, Jian Cai, Joe Perches,
Linus Walleij, linux-arm-kernel, Maninder Singh,
Manivannan Sadhasivam, Marc Zyngier, Masahiro Yamada,
Mike Rapoport, Nick Desaulniers, Nick Desaulniers, Nicolas Pitre,
Peter Zijlstra, Thomas Gleixner, Uwe Kleine-König,
Valentin Schneider, Vaneet Narang, Wolfram Sang (Renesas),
YiFei Zhu
[-- Attachment #1: Type: text/plain, Size: 856 bytes --]
"Russell King (Oracle)" <linux@armlinux.org.uk> writes:
> I think you're introducing a circular dependency with this for
> certain kernel configurations:
>
> E.g. Have you tried running this with CONFIG_CPU_V6 enabled?
That's very useful feedback -- no, I hadn't ever tried this
configuration (presumably the compiler would have complained).
> #define __my_cpu_offset per_cpu_offset(raw_smp_processor_id())
I've read through the v6 architecture reference manual (again) and
cannot find any place to store either a per_cpu_offset or even a small
processor id, which I didn't find surprising as I would have expected it
to already be used for this purpose.
I'll re-spin the changes making them conditional on !CONFIG_CPU_V6,
unless someone has an idea of how to identify the current core in a
multi-core ARMv6 system.
--
-keith
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH 0/2] ARM: support THREAD_INFO_IN_TASK (v7 only) (v2)
2021-09-02 15:54 [PATCH 0/2]: ARM: Enable THREAD_INFO_IN_TASK Keith Packard
` (3 preceding siblings ...)
2021-09-02 16:53 ` Russell King (Oracle)
@ 2021-09-04 6:09 ` Keith Packard
2021-09-04 6:09 ` [PATCH 1/3] ARM: Pass cpu number to secondary_start_kernel Keith Packard
` (3 more replies)
4 siblings, 4 replies; 36+ messages in thread
From: Keith Packard @ 2021-09-04 6:09 UTC (permalink / raw)
To: linux-kernel
Cc: Abbott Liu, Alexander Sverdlin, Andrew Morton, Anshuman Khandual,
Ard Biesheuvel, Arnd Bergmann, Bjorn Andersson, Florian Fainelli,
Geert Uytterhoeven, Hartley Sweeten, Jens Axboe, Jian Cai,
Joe Perches, Kees Cook, Keith Packard, Krzysztof Kozlowski,
Linus Walleij, linux-arm-kernel, Manivannan Sadhasivam,
Marc Zyngier, Masahiro Yamada, Miguel Ojeda, Mike Rapoport,
Nathan Chancellor, Nick Desaulniers, Nicolas Pitre, Rob Herring,
Russell King, Thomas Gleixner, Uwe Kleine-König,
Valentin Schneider, Viresh Kumar, Wolfram Sang (Renesas),
YiFei Zhu, Keith Packard
Placing thread_info in the kernel stack leaves it vulnerable to stack
overflow attacks. This short series addresses that by using the
existing THREAD_INFO_IN_TASK infrastructure.
This is the second version of this series, in this version the changes
are restricted to v7 hardware which offers a way to identify each cpu
in the system without reference to the stack it is using.
The series is broken into three pieces:
1) Change the secondary_start_kernel API to pass the cpu number to
this function. This is required for the following patch because the
raw_smp_processor_id() macro will use the per_cpu_offset value which
needs to have the cpu number to get the right value.
2) Enable THREAD_INFO_IN_TASK by creating a new per-cpu variable,
current_task, just like the x86 architecture. The largest changes
are in the assembly code where fetching the current_task value
requires a temporary register. Fortunately, each location in the
code performing this had a reasonably obvious register to use.
3) Optimize access to the cpu number using another new per-cpu
variable. This is not functionally necessary, but avoids
de-referencing through two pointers at modest memory cost.
Signed-off-by: Keith Packard <keithpac@amazon.com>
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH 1/3] ARM: Pass cpu number to secondary_start_kernel
2021-09-04 6:09 ` [PATCH 0/2] ARM: support THREAD_INFO_IN_TASK (v7 only) (v2) Keith Packard
@ 2021-09-04 6:09 ` Keith Packard
2021-09-05 20:25 ` Ard Biesheuvel
2021-09-04 6:09 ` [PATCH 2/3] ARM: Move thread_info into task_struct (v7 only) Keith Packard
` (2 subsequent siblings)
3 siblings, 1 reply; 36+ messages in thread
From: Keith Packard @ 2021-09-04 6:09 UTC (permalink / raw)
To: linux-kernel
Cc: Abbott Liu, Alexander Sverdlin, Andrew Morton, Anshuman Khandual,
Ard Biesheuvel, Arnd Bergmann, Bjorn Andersson, Florian Fainelli,
Geert Uytterhoeven, Hartley Sweeten, Jens Axboe, Jian Cai,
Joe Perches, Kees Cook, Keith Packard, Krzysztof Kozlowski,
Linus Walleij, linux-arm-kernel, Manivannan Sadhasivam,
Marc Zyngier, Masahiro Yamada, Miguel Ojeda, Mike Rapoport,
Nathan Chancellor, Nick Desaulniers, Nicolas Pitre, Rob Herring,
Russell King, Thomas Gleixner, Uwe Kleine-König,
Valentin Schneider, Viresh Kumar, Wolfram Sang (Renesas),
YiFei Zhu, Keith Packard
Instead of pulling the CPU value out of the thread_info struct, pass
it as an argument. When first initializing secondary processors, this
is done by stashing the value in the secondary_data struct. When
restarting idle processors, the previous CPU value is passed.
Because the cpu is now known at the top of secondary_start_kernel, the
per_cpu_offset value can now be set at this point, instead of in
cpu_init where it was also incorrectly setting the per_cpu_offset for
the boot processor before that value had been computed.
Signed-off-by: Keith Packard <keithpac@amazon.com>
---
arch/arm/include/asm/smp.h | 3 ++-
arch/arm/kernel/head-nommu.S | 1 +
arch/arm/kernel/head.S | 1 +
arch/arm/kernel/setup.c | 6 ------
arch/arm/kernel/smp.c | 14 +++++++++-----
5 files changed, 13 insertions(+), 12 deletions(-)
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 5d508f5d56c4..86a7fd721556 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -48,7 +48,7 @@ extern void set_smp_ipi_range(int ipi_base, int nr_ipi);
* Called from platform specific assembly code, this is the
* secondary CPU entry point.
*/
-asmlinkage void secondary_start_kernel(void);
+asmlinkage void secondary_start_kernel(unsigned int cpu);
/*
@@ -61,6 +61,7 @@ struct secondary_data {
};
unsigned long swapper_pg_dir;
void *stack;
+ unsigned int cpu;
};
extern struct secondary_data secondary_data;
extern void secondary_startup(void);
diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S
index 0fc814bbc34b..5aa8ef42717f 100644
--- a/arch/arm/kernel/head-nommu.S
+++ b/arch/arm/kernel/head-nommu.S
@@ -114,6 +114,7 @@ ENTRY(secondary_startup)
add r12, r12, r10
ret r12
1: bl __after_proc_init
+ ldr r0, [r7, #16] @ set up cpu number
ldr sp, [r7, #12] @ set up the stack pointer
mov fp, #0
b secondary_start_kernel
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index 7f62c5eccdf3..0e541af738e2 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -394,6 +394,7 @@ ENDPROC(secondary_startup_arm)
ENTRY(__secondary_switched)
ldr_l r7, secondary_data + 12 @ get secondary_data.stack
+ ldr_l r0, secondary_data + 16 @ get secondary_data.cpu
mov sp, r7
mov fp, #0
b secondary_start_kernel
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 73ca7797b92f..ca0201635fac 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -532,12 +532,6 @@ void notrace cpu_init(void)
BUG();
}
- /*
- * This only works on resume and secondary cores. For booting on the
- * boot cpu, smp_prepare_boot_cpu is called after percpu area setup.
- */
- set_my_cpu_offset(per_cpu_offset(cpu));
-
cpu_proc_init();
/*
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 74679240a9d8..55cb1689a4b3 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -153,6 +153,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
secondary_data.pgdir = virt_to_phys(idmap_pgd);
secondary_data.swapper_pg_dir = get_arch_pgd(swapper_pg_dir);
#endif
+ secondary_data.cpu = cpu;
sync_cache_w(&secondary_data);
/*
@@ -373,11 +374,14 @@ void arch_cpu_idle_dead(void)
* cpu initialisation. There's some initialisation which needs
* to be repeated to undo the effects of taking the CPU offline.
*/
- __asm__("mov sp, %0\n"
+ __asm__("mov r0, %1\n"
+ " mov sp, %0\n"
" mov fp, #0\n"
" b secondary_start_kernel"
:
- : "r" (task_stack_page(current) + THREAD_SIZE - 8));
+ : "r" (task_stack_page(current) + THREAD_SIZE - 8),
+ "r" (cpu)
+ : "r0");
}
#endif /* CONFIG_HOTPLUG_CPU */
@@ -400,10 +404,11 @@ static void smp_store_cpu_info(unsigned int cpuid)
* This is the secondary CPU boot entry. We're using this CPUs
* idle thread stack, but a set of temporary page tables.
*/
-asmlinkage void secondary_start_kernel(void)
+asmlinkage void secondary_start_kernel(unsigned int cpu)
{
struct mm_struct *mm = &init_mm;
- unsigned int cpu;
+
+ set_my_cpu_offset(per_cpu_offset(cpu));
secondary_biglittle_init();
@@ -420,7 +425,6 @@ asmlinkage void secondary_start_kernel(void)
* All kernel threads share the same mm context; grab a
* reference and switch to it.
*/
- cpu = smp_processor_id();
mmgrab(mm);
current->active_mm = mm;
cpumask_set_cpu(cpu, mm_cpumask(mm));
--
2.33.0
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH 2/3] ARM: Move thread_info into task_struct (v7 only)
2021-09-04 6:09 ` [PATCH 0/2] ARM: support THREAD_INFO_IN_TASK (v7 only) (v2) Keith Packard
2021-09-04 6:09 ` [PATCH 1/3] ARM: Pass cpu number to secondary_start_kernel Keith Packard
@ 2021-09-04 6:09 ` Keith Packard
2021-09-05 20:56 ` Ard Biesheuvel
2021-09-04 6:09 ` [PATCH 3/3] ARM: Add per-cpu variable cpu_number " Keith Packard
2021-09-07 22:00 ` [PATCH 0/7] ARM: support THREAD_INFO_IN_TASK (v3) Keith Packard
3 siblings, 1 reply; 36+ messages in thread
From: Keith Packard @ 2021-09-04 6:09 UTC (permalink / raw)
To: linux-kernel
Cc: Abbott Liu, Alexander Sverdlin, Andrew Morton, Anshuman Khandual,
Ard Biesheuvel, Arnd Bergmann, Bjorn Andersson, Florian Fainelli,
Geert Uytterhoeven, Hartley Sweeten, Jens Axboe, Jian Cai,
Joe Perches, Kees Cook, Keith Packard, Krzysztof Kozlowski,
Linus Walleij, linux-arm-kernel, Manivannan Sadhasivam,
Marc Zyngier, Masahiro Yamada, Miguel Ojeda, Mike Rapoport,
Nathan Chancellor, Nick Desaulniers, Nicolas Pitre, Rob Herring,
Russell King, Thomas Gleixner, Uwe Kleine-König,
Valentin Schneider, Viresh Kumar, Wolfram Sang (Renesas),
YiFei Zhu, Keith Packard
This avoids many stack overflow attacks which modified the thread_info
structure by moving that into the task_struct as is done is almost all
other architectures.
The task_struct is now referenced by a per-cpu variable,
'current_task', allowing the current one on each cpu to be located
from both C and assembly.
This also involved removing the 'cpu' member from the thread_info
struct and using the one added to the task_struct instead by the
THREAD_INFO_IN_TASK code.
This code is currently enabled only for v7 hardware as other ARM
architectures do not make the c13 register in the p15 co-processor
available for general OS use, leaving identifying the current cpu to
the 'cpu' field in the thread_info located off the stack pointer.
Signed-off-by: Keith Packard <keithpac@amazon.com>
---
arch/arm/Kconfig | 1 +
arch/arm/Makefile | 8 ++++
arch/arm/include/asm/assembler.h | 66 ++++++++++++++++++++++++++----
arch/arm/include/asm/current.h | 41 +++++++++++++++++++
arch/arm/include/asm/smp.h | 18 ++++++++
arch/arm/include/asm/thread_info.h | 17 ++++++++
arch/arm/kernel/asm-offsets.c | 4 ++
arch/arm/kernel/entry-armv.S | 17 ++++----
arch/arm/kernel/entry-common.S | 6 +--
arch/arm/kernel/entry-v7m.S | 7 +++-
arch/arm/kernel/iwmmxt.S | 2 +-
arch/arm/kernel/smp.c | 12 ++++++
arch/arm/lib/copy_from_user.S | 2 +-
arch/arm/lib/copy_to_user.S | 2 +-
arch/arm/mach-ep93xx/crunch-bits.S | 2 +-
arch/arm/mm/proc-macros.S | 2 +-
arch/arm/vfp/entry.S | 4 ++
arch/arm/vfp/vfpmodule.c | 25 +++++++----
18 files changed, 204 insertions(+), 32 deletions(-)
create mode 100644 arch/arm/include/asm/current.h
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 24804f11302d..1c1ded500a2b 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -128,6 +128,7 @@ config ARM
select RTC_LIB
select SET_FS
select SYS_SUPPORTS_APM_EMULATION
+ select THREAD_INFO_IN_TASK if CPU_V7
# Above selects are sorted alphabetically; please add new ones
# according to that. Thanks.
help
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 415c3514573a..71a2ba4549d3 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -284,6 +284,14 @@ stack_protector_prepare: prepare0
$(eval GCC_PLUGINS_CFLAGS += $(SSP_PLUGIN_CFLAGS))
endif
+ifdef CONFIG_SMP
+prepare: task_cpu_prepare
+
+PHONY += task_cpu_prepare
+task_cpu_prepare: prepare0
+ $(eval KBUILD_CFLAGS += -D_TSK_CPU=$(shell awk '{if ($$2 == "TSK_CPU") print $$3;}' include/generated/asm-offsets.h))
+endif
+
all: $(notdir $(KBUILD_IMAGE))
diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h
index e2b1fd558bf3..2ce7403f9298 100644
--- a/arch/arm/include/asm/assembler.h
+++ b/arch/arm/include/asm/assembler.h
@@ -199,16 +199,68 @@
.endm
.endr
+#ifdef CONFIG_THREAD_INFO_IN_TASK
/*
- * Get current thread_info.
+ * Get per-CPU offset
+ * rd: Destination register
*/
- .macro get_thread_info, rd
- ARM( mov \rd, sp, lsr #THREAD_SIZE_ORDER + PAGE_SHIFT )
- THUMB( mov \rd, sp )
- THUMB( lsr \rd, \rd, #THREAD_SIZE_ORDER + PAGE_SHIFT )
- mov \rd, \rd, lsl #THREAD_SIZE_ORDER + PAGE_SHIFT
+ .macro this_cpu_offset rd:req
+ mrc p15, 0, \rd, c13, c0, 4
.endm
+/*
+ * Load a per-cpu variable
+ * @dst: Destination register to receive value
+ * @sym: The name of the per-cpu variable
+ * @tmp: scratch register
+ */
+ .macro ldr_this_cpu dst : req, sym : req, tmp : req
+ movw \dst, #:lower16:\sym
+ movt \dst, #:upper16:\sym
+ this_cpu_offset \tmp
+ ldr \dst, [\dst, \tmp]
+ .endm
+
+/*
+ * Store a value in a per-cpu variable
+ * @src: Source register with value
+ * @sym: The name of the per-cpu variable
+ * @t1: scratch register 1
+ * @t2: scratch register 2
+ */
+ .macro str_this_cpu src : req, sym : req, t1 : req, t2 : req
+ movw \t1, #:lower16:\sym
+ movt \t1, #:upper16:\sym
+ this_cpu_offset \t2
+ str \src, [\t1, \t2]
+ .endm
+#endif
+
+/*
+ * Get current thread_info
+ * @dst: Destination register to receive current thread info
+ * @tmp: scratch register
+ */
+ .macro get_current, dst : req, tmp : req
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+ ldr_this_cpu \dst, current_task, \tmp
+#else
+ ARM( mov \dst, sp, lsr #THREAD_SIZE_ORDER + PAGE_SHIFT )
+ THUMB( mov \dst, sp )
+ THUMB( lsr \dst, \dst, #THREAD_SIZE_ORDER + PAGE_SHIFT )
+ mov \dst, \dst, lsl #THREAD_SIZE_ORDER + PAGE_SHIFT
+#endif
+ .endm
+
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+/*
+ * Set current task info
+ */
+ .macro set_current_task rs : req, t1 : req, t2 : req
+ str_this_cpu \rs, current_task, \t1, \t2
+ .endm
+#endif
+
/*
* Increment/decrement the preempt count.
*/
@@ -226,7 +278,7 @@
.endm
.macro dec_preempt_count_ti, ti, tmp
- get_thread_info \ti
+ get_current \ti, \tmp
dec_preempt_count \ti, \tmp
.endm
#else
diff --git a/arch/arm/include/asm/current.h b/arch/arm/include/asm/current.h
new file mode 100644
index 000000000000..7160315eb569
--- /dev/null
+++ b/arch/arm/include/asm/current.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright © 2021 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef _ASM_ARM_CURRENT_H
+#define _ASM_ARM_CURRENT_H
+
+#include <linux/compiler.h>
+#include <linux/thread_info.h>
+#include <asm/percpu.h>
+
+#ifndef __ASSEMBLY__
+
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+struct task_struct;
+
+DECLARE_PER_CPU(struct task_struct *, current_task);
+
+static __always_inline struct task_struct *get_current(void)
+{
+ return raw_cpu_read(current_task);
+}
+
+#define current get_current()
+#else
+#include <asm-generic/current.h>
+#endif
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_ARM_CURRENT_H */
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 86a7fd721556..1c38d1fde641 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -15,7 +15,25 @@
# error "<asm/smp.h> included in non-SMP build"
#endif
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+/*
+ * This is particularly ugly: it appears we can't actually get the definition
+ * of task_struct here, but we need access to the CPU this task is running on.
+ * Instead of using task_struct we're using TSK_CPU which is extracted from
+ * asm-offsets.h by kbuild to get the current processor ID.
+ *
+ * This also needs to be safeguarded when building asm-offsets.s because at
+ * that time TSK_CPU is not defined yet.
+ */
+#ifndef _TSK_CPU
+#define raw_smp_processor_id() (0)
+#else
+#define raw_smp_processor_id() (*(unsigned int *)((void *)current + _TSK_CPU))
+#endif
+
+#else
#define raw_smp_processor_id() (current_thread_info()->cpu)
+#endif
struct seq_file;
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h
index 70d4cbc49ae1..cbcd476a095b 100644
--- a/arch/arm/include/asm/thread_info.h
+++ b/arch/arm/include/asm/thread_info.h
@@ -55,8 +55,10 @@ struct thread_info {
unsigned long flags; /* low level flags */
int preempt_count; /* 0 => preemptable, <0 => bug */
mm_segment_t addr_limit; /* address limit */
+#ifndef CONFIG_THREAD_INFO_IN_TASK
struct task_struct *task; /* main task structure */
__u32 cpu; /* cpu */
+#endif
__u32 cpu_domain; /* cpu domain */
#ifdef CONFIG_STACKPROTECTOR_PER_TASK
unsigned long stack_canary;
@@ -75,6 +77,17 @@ struct thread_info {
#endif
};
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+
+#define INIT_THREAD_INFO(tsk) \
+{ \
+ .flags = 0, \
+ .preempt_count = INIT_PREEMPT_COUNT, \
+ .addr_limit = KERNEL_DS, \
+}
+
+#else
+
#define INIT_THREAD_INFO(tsk) \
{ \
.task = &tsk, \
@@ -83,6 +96,9 @@ struct thread_info {
.addr_limit = KERNEL_DS, \
}
+#endif
+
+#ifndef CONFIG_THREAD_INFO_IN_TASK
/*
* how to get the thread information struct from C
*/
@@ -93,6 +109,7 @@ static inline struct thread_info *current_thread_info(void)
return (struct thread_info *)
(current_stack_pointer & ~(THREAD_SIZE - 1));
}
+#endif
#define thread_saved_pc(tsk) \
((unsigned long)(task_thread_info(tsk)->cpu_context.pc))
diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c
index 70993af22d80..c91dcfe34bdd 100644
--- a/arch/arm/kernel/asm-offsets.c
+++ b/arch/arm/kernel/asm-offsets.c
@@ -44,8 +44,12 @@ int main(void)
DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count));
DEFINE(TI_ADDR_LIMIT, offsetof(struct thread_info, addr_limit));
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+ DEFINE(TSK_CPU, offsetof(struct task_struct, cpu));
+#else
DEFINE(TI_TASK, offsetof(struct thread_info, task));
DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
+#endif
DEFINE(TI_CPU_DOMAIN, offsetof(struct thread_info, cpu_domain));
DEFINE(TI_CPU_SAVE, offsetof(struct thread_info, cpu_context));
DEFINE(TI_USED_CP, offsetof(struct thread_info, used_cp));
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 0ea8529a4872..a5d71b0d8897 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -179,7 +179,7 @@ ENDPROC(__und_invalid)
@
stmia r7, {r2 - r6}
- get_thread_info tsk
+ get_current tsk, r0
uaccess_entry tsk, r0, r1, r2, \uaccess
.if \trace
@@ -260,7 +260,7 @@ __und_svc:
bl __und_fault
__und_svc_finish:
- get_thread_info tsk
+ get_current tsk, r5
ldr r5, [sp, #S_PSR] @ Get SVC cpsr
svc_exit r5 @ return from exception
UNWIND(.fnend )
@@ -428,7 +428,7 @@ __irq_usr:
usr_entry
kuser_cmpxchg_check
irq_handler
- get_thread_info tsk
+ get_current tsk, why
mov why, #0
b ret_to_user_from_irq
UNWIND(.fnend )
@@ -572,12 +572,12 @@ ENDPROC(__und_usr)
@ Fall-through from Thumb-2 __und_usr
@
#ifdef CONFIG_NEON
- get_thread_info r10 @ get current thread
+ get_current r10, r6 @ get current thread
adr r6, .LCneon_thumb_opcodes
b 2f
#endif
call_fpe:
- get_thread_info r10 @ get current thread
+ get_current r10, r6 @ get current thread
#ifdef CONFIG_NEON
adr r6, .LCneon_arm_opcodes
2: ldr r5, [r6], #4 @ mask value
@@ -722,7 +722,7 @@ __pabt_usr:
ENTRY(ret_from_exception)
UNWIND(.fnstart )
UNWIND(.cantunwind )
- get_thread_info tsk
+ get_current tsk, why
mov why, #0
b ret_to_user
UNWIND(.fnend )
@@ -735,7 +735,7 @@ __fiq_usr:
kuser_cmpxchg_check
mov r0, sp @ struct pt_regs *regs
bl handle_fiq_as_nmi
- get_thread_info tsk
+ get_current tsk, r0
restore_user_regs fast = 0, offset = 0
UNWIND(.fnend )
ENDPROC(__fiq_usr)
@@ -771,6 +771,9 @@ ENTRY(__switch_to)
#endif
#ifdef CONFIG_CPU_USE_DOMAINS
mcr p15, 0, r6, c3, c0, 0 @ Set domain register
+#endif
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+ set_current_task r2, r4, r5
#endif
mov r5, r0
add r4, r2, #TI_CPU_SAVE
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 7f0b7aba1498..52580ee463fe 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -156,7 +156,7 @@ ENTRY(ret_from_fork)
movne r0, r4
badrne lr, 1f
retne r5
-1: get_thread_info tsk
+1: get_current tsk, r1
b ret_slow_syscall
ENDPROC(ret_from_fork)
@@ -243,7 +243,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
+ get_current tsk, r10
/*
* Reload the registers that may have been corrupted on entry to
* the syscall assembly (by tracing or context tracking.)
@@ -278,7 +278,7 @@ local_restart:
9001:
sub lr, saved_pc, #4
str lr, [sp, #S_PC]
- get_thread_info tsk
+ get_current tsk, r1
b ret_fast_syscall
#endif
ENDPROC(vector_swi)
diff --git a/arch/arm/kernel/entry-v7m.S b/arch/arm/kernel/entry-v7m.S
index d0e898608d30..f36a7a876085 100644
--- a/arch/arm/kernel/entry-v7m.S
+++ b/arch/arm/kernel/entry-v7m.S
@@ -57,7 +57,7 @@ __irq_entry:
tst r0, V7M_SCB_ICSR_RETTOBASE
beq 2f
- get_thread_info tsk
+ get_current tsk, r2
ldr r2, [tsk, #TI_FLAGS]
movs r2, r2, lsl #16
beq 2f @ no work pending
@@ -83,7 +83,7 @@ __pendsv_entry:
str r0, [r1, V7M_SCB_ICSR] @ clear PendSV
@ execute the pending work, including reschedule
- get_thread_info tsk
+ get_current tsk, why
mov why, #0
b ret_to_user_from_irq
ENDPROC(__pendsv_entry)
@@ -107,6 +107,9 @@ ENTRY(__switch_to)
bl atomic_notifier_call_chain
mov ip, r4
mov r0, r5
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+ set_current_task r2, r4, r5
+#endif
ldmia ip!, {r4 - r11} @ Load all regs saved previously
ldr sp, [ip]
ldr pc, [ip, #4]!
diff --git a/arch/arm/kernel/iwmmxt.S b/arch/arm/kernel/iwmmxt.S
index d2b4ac06e4ed..781f7c7fca90 100644
--- a/arch/arm/kernel/iwmmxt.S
+++ b/arch/arm/kernel/iwmmxt.S
@@ -96,7 +96,7 @@ ENTRY(iwmmxt_task_enable)
bl concan_save
#ifdef CONFIG_PREEMPT_COUNT
- get_thread_info r10
+ get_current r10, r3
#endif
4: dec_preempt_count r10, r3
ret r9 @ normal exit from exception
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 55cb1689a4b3..be0ede16dbb1 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -51,6 +51,13 @@
#define CREATE_TRACE_POINTS
#include <trace/events/ipi.h>
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+DEFINE_PER_CPU(struct task_struct *, current_task) ____cacheline_aligned =
+ &init_task;
+EXPORT_PER_CPU_SYMBOL(current_task);
+
+#endif
+
/*
* as from 2.5, kernels no longer have an init_tasks structure
* so we need some other way of telling a new secondary core
@@ -156,6 +163,10 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
secondary_data.cpu = cpu;
sync_cache_w(&secondary_data);
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+ per_cpu(current_task, cpu) = idle;
+#endif
+
/*
* Now bring the CPU into our world.
*/
@@ -509,6 +520,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
*/
if (max_cpus > ncores)
max_cpus = ncores;
+
if (ncores > 1 && max_cpus) {
/*
* Initialise the present map, which describes the set of CPUs
diff --git a/arch/arm/lib/copy_from_user.S b/arch/arm/lib/copy_from_user.S
index f8016e3db65d..5320950100a2 100644
--- a/arch/arm/lib/copy_from_user.S
+++ b/arch/arm/lib/copy_from_user.S
@@ -109,7 +109,7 @@
ENTRY(arm_copy_from_user)
#ifdef CONFIG_CPU_SPECTRE
- get_thread_info r3
+ get_current r3, ip
ldr r3, [r3, #TI_ADDR_LIMIT]
uaccess_mask_range_ptr r1, r2, r3, ip
#endif
diff --git a/arch/arm/lib/copy_to_user.S b/arch/arm/lib/copy_to_user.S
index ebfe4cb3d912..e7e61c87893a 100644
--- a/arch/arm/lib/copy_to_user.S
+++ b/arch/arm/lib/copy_to_user.S
@@ -109,7 +109,7 @@
ENTRY(__copy_to_user_std)
WEAK(arm_copy_to_user)
#ifdef CONFIG_CPU_SPECTRE
- get_thread_info r3
+ get_current r3, ip
ldr r3, [r3, #TI_ADDR_LIMIT]
uaccess_mask_range_ptr r0, r2, r3, ip
#endif
diff --git a/arch/arm/mach-ep93xx/crunch-bits.S b/arch/arm/mach-ep93xx/crunch-bits.S
index fb2dbf76f09e..d0bb34b3d973 100644
--- a/arch/arm/mach-ep93xx/crunch-bits.S
+++ b/arch/arm/mach-ep93xx/crunch-bits.S
@@ -192,7 +192,7 @@ crunch_load:
1:
#ifdef CONFIG_PREEMPT_COUNT
- get_thread_info r10
+ get_current r10, r3
#endif
2: dec_preempt_count r10, r3
ret lr
diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S
index e2c743aa2eb2..a782c025fdf3 100644
--- a/arch/arm/mm/proc-macros.S
+++ b/arch/arm/mm/proc-macros.S
@@ -30,7 +30,7 @@
* act_mm - get current->active_mm
*/
.macro act_mm, rd
- get_thread_info \rd
+ get_current \rd, unused @ won't build if THREAD_INFO_IN_TASK
ldr \rd, [\rd, #TI_TASK]
.if (TSK_ACTIVE_MM > IMM12_MASK)
add \rd, \rd, #TSK_ACTIVE_MM & ~IMM12_MASK
diff --git a/arch/arm/vfp/entry.S b/arch/arm/vfp/entry.S
index 27b0a1f27fbd..48cb40a3b72d 100644
--- a/arch/arm/vfp/entry.S
+++ b/arch/arm/vfp/entry.S
@@ -24,7 +24,11 @@
ENTRY(do_vfp)
inc_preempt_count r10, r4
ldr r4, .LCvfp
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+ ldr r11, [r10, #TSK_CPU] @ CPU number
+#else
ldr r11, [r10, #TI_CPU] @ CPU number
+#endif
add r10, r10, #TI_VFPSTATE @ r10 = workspace
ldr pc, [r4] @ call VFP entry point
ENDPROC(do_vfp)
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 2cb355c1b5b7..f929a26a05a5 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -143,22 +143,27 @@ static void vfp_thread_copy(struct thread_info *thread)
* THREAD_NOFTIFY_SWTICH:
* - the previously running thread will not be scheduled onto another CPU.
* - the next thread to be run (v) will not be running on another CPU.
- * - thread->cpu is the local CPU number
+ * - tsk->cpu is the local CPU number
* - not preemptible as we're called in the middle of a thread switch
* THREAD_NOTIFY_FLUSH:
* - the thread (v) will be running on the local CPU, so
- * v === current_thread_info()
- * - thread->cpu is the local CPU number at the time it is accessed,
+ * v === current
+ * - tsk->cpu is the local CPU number at the time it is accessed,
* but may change at any time.
* - we could be preempted if tree preempt rcu is enabled, so
- * it is unsafe to use thread->cpu.
+ * it is unsafe to use tsk->cpu.
* THREAD_NOTIFY_EXIT
* - we could be preempted if tree preempt rcu is enabled, so
- * it is unsafe to use thread->cpu.
+ * it is unsafe to use tsk->cpu.
*/
static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
{
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+ struct task_struct *tsk = v;
+ struct thread_info *thread = &tsk->thread_info;
+#else
struct thread_info *thread = v;
+#endif
u32 fpexc;
#ifdef CONFIG_SMP
unsigned int cpu;
@@ -169,7 +174,11 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
fpexc = fmrx(FPEXC);
#ifdef CONFIG_SMP
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+ cpu = tsk->cpu;
+#else
cpu = thread->cpu;
+#endif
/*
* On SMP, if VFP is enabled, save the old state in
@@ -458,16 +467,16 @@ static int vfp_pm_suspend(void)
/* disable, just in case */
fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
- } else if (vfp_current_hw_state[ti->cpu]) {
+ } else if (vfp_current_hw_state[smp_processor_id()]) {
#ifndef CONFIG_SMP
fmxr(FPEXC, fpexc | FPEXC_EN);
- vfp_save_state(vfp_current_hw_state[ti->cpu], fpexc);
+ vfp_save_state(vfp_current_hw_state[smp_processor_id()], fpexc);
fmxr(FPEXC, fpexc);
#endif
}
/* clear any information we had about last context state */
- vfp_current_hw_state[ti->cpu] = NULL;
+ vfp_current_hw_state[smp_processor_id()] = NULL;
return 0;
}
--
2.33.0
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH 3/3] ARM: Add per-cpu variable cpu_number (v7 only)
2021-09-04 6:09 ` [PATCH 0/2] ARM: support THREAD_INFO_IN_TASK (v7 only) (v2) Keith Packard
2021-09-04 6:09 ` [PATCH 1/3] ARM: Pass cpu number to secondary_start_kernel Keith Packard
2021-09-04 6:09 ` [PATCH 2/3] ARM: Move thread_info into task_struct (v7 only) Keith Packard
@ 2021-09-04 6:09 ` Keith Packard
2021-09-07 22:00 ` [PATCH 0/7] ARM: support THREAD_INFO_IN_TASK (v3) Keith Packard
3 siblings, 0 replies; 36+ messages in thread
From: Keith Packard @ 2021-09-04 6:09 UTC (permalink / raw)
To: linux-kernel
Cc: Abbott Liu, Alexander Sverdlin, Andrew Morton, Anshuman Khandual,
Ard Biesheuvel, Arnd Bergmann, Bjorn Andersson, Florian Fainelli,
Geert Uytterhoeven, Hartley Sweeten, Jens Axboe, Jian Cai,
Joe Perches, Kees Cook, Keith Packard, Krzysztof Kozlowski,
Linus Walleij, linux-arm-kernel, Manivannan Sadhasivam,
Marc Zyngier, Masahiro Yamada, Miguel Ojeda, Mike Rapoport,
Nathan Chancellor, Nick Desaulniers, Nicolas Pitre, Rob Herring,
Russell King, Thomas Gleixner, Uwe Kleine-König,
Valentin Schneider, Viresh Kumar, Wolfram Sang (Renesas),
YiFei Zhu, Keith Packard
Holds the cpu value for each cpu to make accessing this variable more
efficient than fetching the current task struct and pulling the cpu
value from there.
This code is only enabled when THREAD_INFO_IN_TASK is selected, which
is currently only enabled for v7 hardware.
Signed-off-by: Keith Packard <keithpac@amazon.com>
---
arch/arm/Makefile | 8 --------
arch/arm/include/asm/smp.h | 17 +++--------------
arch/arm/kernel/smp.c | 16 ++++++++++++++++
3 files changed, 19 insertions(+), 22 deletions(-)
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 71a2ba4549d3..415c3514573a 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -284,14 +284,6 @@ stack_protector_prepare: prepare0
$(eval GCC_PLUGINS_CFLAGS += $(SSP_PLUGIN_CFLAGS))
endif
-ifdef CONFIG_SMP
-prepare: task_cpu_prepare
-
-PHONY += task_cpu_prepare
-task_cpu_prepare: prepare0
- $(eval KBUILD_CFLAGS += -D_TSK_CPU=$(shell awk '{if ($$2 == "TSK_CPU") print $$3;}' include/generated/asm-offsets.h))
-endif
-
all: $(notdir $(KBUILD_IMAGE))
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 1c38d1fde641..67d21233bdfe 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -16,21 +16,10 @@
#endif
#ifdef CONFIG_THREAD_INFO_IN_TASK
-/*
- * This is particularly ugly: it appears we can't actually get the definition
- * of task_struct here, but we need access to the CPU this task is running on.
- * Instead of using task_struct we're using TSK_CPU which is extracted from
- * asm-offsets.h by kbuild to get the current processor ID.
- *
- * This also needs to be safeguarded when building asm-offsets.s because at
- * that time TSK_CPU is not defined yet.
- */
-#ifndef _TSK_CPU
-#define raw_smp_processor_id() (0)
-#else
-#define raw_smp_processor_id() (*(unsigned int *)((void *)current + _TSK_CPU))
-#endif
+#define raw_smp_processor_id() this_cpu_read(cpu_number)
+#define __smp_processor_id() __this_cpu_read(cpu_number)
+DECLARE_PER_CPU_READ_MOSTLY(unsigned int, cpu_number);
#else
#define raw_smp_processor_id() (current_thread_info()->cpu)
#endif
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index be0ede16dbb1..a33397618f1e 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -56,6 +56,8 @@ DEFINE_PER_CPU(struct task_struct *, current_task) ____cacheline_aligned =
&init_task;
EXPORT_PER_CPU_SYMBOL(current_task);
+DEFINE_PER_CPU_READ_MOSTLY(unsigned int, cpu_number);
+EXPORT_PER_CPU_SYMBOL(cpu_number);
#endif
/*
@@ -510,6 +512,9 @@ void __init smp_prepare_boot_cpu(void)
void __init smp_prepare_cpus(unsigned int max_cpus)
{
unsigned int ncores = num_possible_cpus();
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+ unsigned int cpu;
+#endif
init_cpu_topology();
@@ -521,6 +526,17 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
if (max_cpus > ncores)
max_cpus = ncores;
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+ /*
+ * Initialize the cpu_number value for each cpu before we
+ * start it. This ensures that the value is valid during cpu
+ * initialization, even before the idle task_struct cpu member
+ * is set
+ */
+ for_each_possible_cpu(cpu)
+ per_cpu(cpu_number, cpu) = cpu;
+#endif
+
if (ncores > 1 && max_cpus) {
/*
* Initialise the present map, which describes the set of CPUs
--
2.33.0
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH 1/3] ARM: Pass cpu number to secondary_start_kernel
2021-09-04 6:09 ` [PATCH 1/3] ARM: Pass cpu number to secondary_start_kernel Keith Packard
@ 2021-09-05 20:25 ` Ard Biesheuvel
0 siblings, 0 replies; 36+ messages in thread
From: Ard Biesheuvel @ 2021-09-05 20:25 UTC (permalink / raw)
To: Keith Packard
Cc: Linux Kernel Mailing List, Abbott Liu, Alexander Sverdlin,
Andrew Morton, Anshuman Khandual, Arnd Bergmann, Bjorn Andersson,
Florian Fainelli, Geert Uytterhoeven, Hartley Sweeten,
Jens Axboe, Jian Cai, Joe Perches, Kees Cook,
Krzysztof Kozlowski, Linus Walleij, Linux ARM,
Manivannan Sadhasivam, Marc Zyngier, Masahiro Yamada,
Miguel Ojeda, Mike Rapoport, Nathan Chancellor, Nick Desaulniers,
Nicolas Pitre, Rob Herring, Russell King, Thomas Gleixner,
Uwe Kleine-König, Valentin Schneider, Viresh Kumar,
Wolfram Sang (Renesas),
YiFei Zhu, Keith Packard
Hi Keith,
This looks like a worthwhile cleanup to me regardless of the following patches.
On Sat, 4 Sept 2021 at 08:09, Keith Packard <keithp@keithp.com> wrote:
>
> Instead of pulling the CPU value out of the thread_info struct, pass
> it as an argument. When first initializing secondary processors, this
> is done by stashing the value in the secondary_data struct. When
> restarting idle processors, the previous CPU value is passed.
>
> Because the cpu is now known at the top of secondary_start_kernel, the
> per_cpu_offset value can now be set at this point, instead of in
> cpu_init where it was also incorrectly setting the per_cpu_offset for
> the boot processor before that value had been computed.
>
> Signed-off-by: Keith Packard <keithpac@amazon.com>
Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
> ---
> arch/arm/include/asm/smp.h | 3 ++-
> arch/arm/kernel/head-nommu.S | 1 +
> arch/arm/kernel/head.S | 1 +
> arch/arm/kernel/setup.c | 6 ------
> arch/arm/kernel/smp.c | 14 +++++++++-----
> 5 files changed, 13 insertions(+), 12 deletions(-)
>
> diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
> index 5d508f5d56c4..86a7fd721556 100644
> --- a/arch/arm/include/asm/smp.h
> +++ b/arch/arm/include/asm/smp.h
> @@ -48,7 +48,7 @@ extern void set_smp_ipi_range(int ipi_base, int nr_ipi);
> * Called from platform specific assembly code, this is the
> * secondary CPU entry point.
> */
> -asmlinkage void secondary_start_kernel(void);
> +asmlinkage void secondary_start_kernel(unsigned int cpu);
>
>
> /*
> @@ -61,6 +61,7 @@ struct secondary_data {
> };
> unsigned long swapper_pg_dir;
> void *stack;
> + unsigned int cpu;
> };
> extern struct secondary_data secondary_data;
> extern void secondary_startup(void);
> diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S
> index 0fc814bbc34b..5aa8ef42717f 100644
> --- a/arch/arm/kernel/head-nommu.S
> +++ b/arch/arm/kernel/head-nommu.S
> @@ -114,6 +114,7 @@ ENTRY(secondary_startup)
> add r12, r12, r10
> ret r12
> 1: bl __after_proc_init
> + ldr r0, [r7, #16] @ set up cpu number
> ldr sp, [r7, #12] @ set up the stack pointer
> mov fp, #0
> b secondary_start_kernel
> diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
> index 7f62c5eccdf3..0e541af738e2 100644
> --- a/arch/arm/kernel/head.S
> +++ b/arch/arm/kernel/head.S
> @@ -394,6 +394,7 @@ ENDPROC(secondary_startup_arm)
>
> ENTRY(__secondary_switched)
> ldr_l r7, secondary_data + 12 @ get secondary_data.stack
> + ldr_l r0, secondary_data + 16 @ get secondary_data.cpu
> mov sp, r7
> mov fp, #0
> b secondary_start_kernel
> diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
> index 73ca7797b92f..ca0201635fac 100644
> --- a/arch/arm/kernel/setup.c
> +++ b/arch/arm/kernel/setup.c
> @@ -532,12 +532,6 @@ void notrace cpu_init(void)
> BUG();
> }
>
> - /*
> - * This only works on resume and secondary cores. For booting on the
> - * boot cpu, smp_prepare_boot_cpu is called after percpu area setup.
> - */
> - set_my_cpu_offset(per_cpu_offset(cpu));
> -
> cpu_proc_init();
>
> /*
> diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
> index 74679240a9d8..55cb1689a4b3 100644
> --- a/arch/arm/kernel/smp.c
> +++ b/arch/arm/kernel/smp.c
> @@ -153,6 +153,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
> secondary_data.pgdir = virt_to_phys(idmap_pgd);
> secondary_data.swapper_pg_dir = get_arch_pgd(swapper_pg_dir);
> #endif
> + secondary_data.cpu = cpu;
> sync_cache_w(&secondary_data);
>
> /*
> @@ -373,11 +374,14 @@ void arch_cpu_idle_dead(void)
> * cpu initialisation. There's some initialisation which needs
> * to be repeated to undo the effects of taking the CPU offline.
> */
> - __asm__("mov sp, %0\n"
> + __asm__("mov r0, %1\n"
> + " mov sp, %0\n"
> " mov fp, #0\n"
> " b secondary_start_kernel"
> :
> - : "r" (task_stack_page(current) + THREAD_SIZE - 8));
> + : "r" (task_stack_page(current) + THREAD_SIZE - 8),
> + "r" (cpu)
> + : "r0");
> }
> #endif /* CONFIG_HOTPLUG_CPU */
>
> @@ -400,10 +404,11 @@ static void smp_store_cpu_info(unsigned int cpuid)
> * This is the secondary CPU boot entry. We're using this CPUs
> * idle thread stack, but a set of temporary page tables.
> */
> -asmlinkage void secondary_start_kernel(void)
> +asmlinkage void secondary_start_kernel(unsigned int cpu)
> {
> struct mm_struct *mm = &init_mm;
> - unsigned int cpu;
> +
> + set_my_cpu_offset(per_cpu_offset(cpu));
>
> secondary_biglittle_init();
>
> @@ -420,7 +425,6 @@ asmlinkage void secondary_start_kernel(void)
> * All kernel threads share the same mm context; grab a
> * reference and switch to it.
> */
> - cpu = smp_processor_id();
> mmgrab(mm);
> current->active_mm = mm;
> cpumask_set_cpu(cpu, mm_cpumask(mm));
> --
> 2.33.0
>
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH 2/3] ARM: Move thread_info into task_struct (v7 only)
2021-09-04 6:09 ` [PATCH 2/3] ARM: Move thread_info into task_struct (v7 only) Keith Packard
@ 2021-09-05 20:56 ` Ard Biesheuvel
2021-09-06 6:14 ` Keith Packard
2021-09-06 6:20 ` Keith Packard
0 siblings, 2 replies; 36+ messages in thread
From: Ard Biesheuvel @ 2021-09-05 20:56 UTC (permalink / raw)
To: Keith Packard
Cc: Linux Kernel Mailing List, Abbott Liu, Alexander Sverdlin,
Andrew Morton, Anshuman Khandual, Arnd Bergmann, Bjorn Andersson,
Florian Fainelli, Geert Uytterhoeven, Hartley Sweeten,
Jens Axboe, Jian Cai, Joe Perches, Kees Cook,
Krzysztof Kozlowski, Linus Walleij, Linux ARM,
Manivannan Sadhasivam, Marc Zyngier, Masahiro Yamada,
Miguel Ojeda, Mike Rapoport, Nathan Chancellor, Nick Desaulniers,
Nicolas Pitre, Rob Herring, Russell King, Thomas Gleixner,
Uwe Kleine-König, Valentin Schneider, Viresh Kumar,
Wolfram Sang (Renesas),
YiFei Zhu, Keith Packard
On Sat, 4 Sept 2021 at 08:09, Keith Packard <keithp@keithp.com> wrote:
>
> This avoids many stack overflow attacks which modified the thread_info
> structure by moving that into the task_struct as is done is almost all
> other architectures.
>
> The task_struct is now referenced by a per-cpu variable,
> 'current_task', allowing the current one on each cpu to be located
> from both C and assembly.
>
> This also involved removing the 'cpu' member from the thread_info
> struct and using the one added to the task_struct instead by the
> THREAD_INFO_IN_TASK code.
>
> This code is currently enabled only for v7 hardware as other ARM
> architectures do not make the c13 register in the p15 co-processor
> available for general OS use, leaving identifying the current cpu to
> the 'cpu' field in the thread_info located off the stack pointer.
>
c13 is not a register, it is a value in one of the dimensions of the
ARM sysreg space, and probably covers other system registers that
pre-v7 cores do implement.
Better to use its architectural name (TPIDRPRW) and clarify that
pre-v6k/v7 cores simply don't implement it.
> Signed-off-by: Keith Packard <keithpac@amazon.com>
> ---
> arch/arm/Kconfig | 1 +
> arch/arm/Makefile | 8 ++++
> arch/arm/include/asm/assembler.h | 66 ++++++++++++++++++++++++++----
> arch/arm/include/asm/current.h | 41 +++++++++++++++++++
> arch/arm/include/asm/smp.h | 18 ++++++++
> arch/arm/include/asm/thread_info.h | 17 ++++++++
> arch/arm/kernel/asm-offsets.c | 4 ++
> arch/arm/kernel/entry-armv.S | 17 ++++----
> arch/arm/kernel/entry-common.S | 6 +--
> arch/arm/kernel/entry-v7m.S | 7 +++-
> arch/arm/kernel/iwmmxt.S | 2 +-
> arch/arm/kernel/smp.c | 12 ++++++
> arch/arm/lib/copy_from_user.S | 2 +-
> arch/arm/lib/copy_to_user.S | 2 +-
> arch/arm/mach-ep93xx/crunch-bits.S | 2 +-
> arch/arm/mm/proc-macros.S | 2 +-
> arch/arm/vfp/entry.S | 4 ++
> arch/arm/vfp/vfpmodule.c | 25 +++++++----
> 18 files changed, 204 insertions(+), 32 deletions(-)
> create mode 100644 arch/arm/include/asm/current.h
>
Could we split this up?
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 24804f11302d..1c1ded500a2b 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -128,6 +128,7 @@ config ARM
> select RTC_LIB
> select SET_FS
> select SYS_SUPPORTS_APM_EMULATION
> + select THREAD_INFO_IN_TASK if CPU_V7
CPU_V6K also supports this
> # Above selects are sorted alphabetically; please add new ones
> # according to that. Thanks.
> help
> diff --git a/arch/arm/Makefile b/arch/arm/Makefile
> index 415c3514573a..71a2ba4549d3 100644
> --- a/arch/arm/Makefile
> +++ b/arch/arm/Makefile
> @@ -284,6 +284,14 @@ stack_protector_prepare: prepare0
> $(eval GCC_PLUGINS_CFLAGS += $(SSP_PLUGIN_CFLAGS))
> endif
>
> +ifdef CONFIG_SMP
> +prepare: task_cpu_prepare
> +
> +PHONY += task_cpu_prepare
> +task_cpu_prepare: prepare0
> + $(eval KBUILD_CFLAGS += -D_TSK_CPU=$(shell awk '{if ($$2 == "TSK_CPU") print $$3;}' include/generated/asm-offsets.h))
> +endif
> +
> all: $(notdir $(KBUILD_IMAGE))
>
This is rather horrid, and removed again in the next patch. Can we
omit it entirely?
>
> diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h
> index e2b1fd558bf3..2ce7403f9298 100644
> --- a/arch/arm/include/asm/assembler.h
> +++ b/arch/arm/include/asm/assembler.h
> @@ -199,16 +199,68 @@
> .endm
> .endr
>
> +#ifdef CONFIG_THREAD_INFO_IN_TASK
No need for this #ifdef - it only guards macros that will have no
effect if they are never instantiated (another case below)
> /*
> - * Get current thread_info.
> + * Get per-CPU offset
> + * rd: Destination register
> */
> - .macro get_thread_info, rd
> - ARM( mov \rd, sp, lsr #THREAD_SIZE_ORDER + PAGE_SHIFT )
> - THUMB( mov \rd, sp )
> - THUMB( lsr \rd, \rd, #THREAD_SIZE_ORDER + PAGE_SHIFT )
> - mov \rd, \rd, lsl #THREAD_SIZE_ORDER + PAGE_SHIFT
> + .macro this_cpu_offset rd:req
> + mrc p15, 0, \rd, c13, c0, 4
> .endm
>
> +/*
> + * Load a per-cpu variable
> + * @dst: Destination register to receive value
> + * @sym: The name of the per-cpu variable
> + * @tmp: scratch register
> + */
> + .macro ldr_this_cpu dst : req, sym : req, tmp : req
> + movw \dst, #:lower16:\sym
> + movt \dst, #:upper16:\sym
> + this_cpu_offset \tmp
> + ldr \dst, [\dst, \tmp]
> + .endm
> +
> +/*
> + * Store a value in a per-cpu variable
> + * @src: Source register with value
> + * @sym: The name of the per-cpu variable
> + * @t1: scratch register 1
> + * @t2: scratch register 2
> + */
> + .macro str_this_cpu src : req, sym : req, t1 : req, t2 : req
> + movw \t1, #:lower16:\sym
> + movt \t1, #:upper16:\sym
> + this_cpu_offset \t2
> + str \src, [\t1, \t2]
> + .endm
> +#endif
> +
> +/*
> + * Get current thread_info
> + * @dst: Destination register to receive current thread info
> + * @tmp: scratch register
> + */
> + .macro get_current, dst : req, tmp : req
> +#ifdef CONFIG_THREAD_INFO_IN_TASK
> + ldr_this_cpu \dst, current_task, \tmp
> +#else
> + ARM( mov \dst, sp, lsr #THREAD_SIZE_ORDER + PAGE_SHIFT )
> + THUMB( mov \dst, sp )
> + THUMB( lsr \dst, \dst, #THREAD_SIZE_ORDER + PAGE_SHIFT )
> + mov \dst, \dst, lsl #THREAD_SIZE_ORDER + PAGE_SHIFT
> +#endif
> + .endm
> +
> +#ifdef CONFIG_THREAD_INFO_IN_TASK
> +/*
> + * Set current task info
> + */
> + .macro set_current_task rs : req, t1 : req, t2 : req
> + str_this_cpu \rs, current_task, \t1, \t2
> + .endm
> +#endif
> +
> /*
> * Increment/decrement the preempt count.
> */
> @@ -226,7 +278,7 @@
> .endm
>
> .macro dec_preempt_count_ti, ti, tmp
> - get_thread_info \ti
> + get_current \ti, \tmp
> dec_preempt_count \ti, \tmp
> .endm
> #else
> diff --git a/arch/arm/include/asm/current.h b/arch/arm/include/asm/current.h
> new file mode 100644
> index 000000000000..7160315eb569
> --- /dev/null
> +++ b/arch/arm/include/asm/current.h
> @@ -0,0 +1,41 @@
> +/*
> + * Copyright © 2021 Keith Packard <keithp@keithp.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * General Public License for more details.
Please drop the boilerplate and use a SPDX header instead.
> + */
> +
> +#ifndef _ASM_ARM_CURRENT_H
> +#define _ASM_ARM_CURRENT_H
> +
> +#include <linux/compiler.h>
> +#include <linux/thread_info.h>
> +#include <asm/percpu.h>
> +
> +#ifndef __ASSEMBLY__
> +
> +#ifdef CONFIG_THREAD_INFO_IN_TASK
> +struct task_struct;
> +
> +DECLARE_PER_CPU(struct task_struct *, current_task);
> +
> +static __always_inline struct task_struct *get_current(void)
> +{
> + return raw_cpu_read(current_task);
This needs to run with preemption disabled, or we might get migrated
to another CPU halfway through, and produce the wrong result (i.e.,
the current task of the CPU we migrated from). However, it appears
that manipulating the preempt count will create a circular dependency
here.
Instead of using a per-CPU variable for current, I think it might be
better to borrow another system register (TPIDRURO or TPIDRURW) to
carry 'current' when THREAD_INFO_IN_TASK is in effect, similar to how
arm64 uses SP_EL0 - those registers could be preserved/restored in the
entry/exit from/to user space paths rather than in the context switch
path, and then be used any way we like while running in the kernel.
> +}
> +
> +#define current get_current()
> +#else
> +#include <asm-generic/current.h>
> +#endif
> +
> +#endif /* __ASSEMBLY__ */
> +
> +#endif /* _ASM_ARM_CURRENT_H */
> diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
> index 86a7fd721556..1c38d1fde641 100644
> --- a/arch/arm/include/asm/smp.h
> +++ b/arch/arm/include/asm/smp.h
> @@ -15,7 +15,25 @@
> # error "<asm/smp.h> included in non-SMP build"
> #endif
>
> +#ifdef CONFIG_THREAD_INFO_IN_TASK
> +/*
> + * This is particularly ugly: it appears we can't actually get the definition
> + * of task_struct here, but we need access to the CPU this task is running on.
> + * Instead of using task_struct we're using TSK_CPU which is extracted from
> + * asm-offsets.h by kbuild to get the current processor ID.
> + *
> + * This also needs to be safeguarded when building asm-offsets.s because at
> + * that time TSK_CPU is not defined yet.
> + */
> +#ifndef _TSK_CPU
> +#define raw_smp_processor_id() (0)
> +#else
> +#define raw_smp_processor_id() (*(unsigned int *)((void *)current + _TSK_CPU))
> +#endif
> +
> +#else
> #define raw_smp_processor_id() (current_thread_info()->cpu)
> +#endif
>
> struct seq_file;
>
> diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h
> index 70d4cbc49ae1..cbcd476a095b 100644
> --- a/arch/arm/include/asm/thread_info.h
> +++ b/arch/arm/include/asm/thread_info.h
> @@ -55,8 +55,10 @@ struct thread_info {
> unsigned long flags; /* low level flags */
> int preempt_count; /* 0 => preemptable, <0 => bug */
> mm_segment_t addr_limit; /* address limit */
> +#ifndef CONFIG_THREAD_INFO_IN_TASK
> struct task_struct *task; /* main task structure */
> __u32 cpu; /* cpu */
> +#endif
> __u32 cpu_domain; /* cpu domain */
> #ifdef CONFIG_STACKPROTECTOR_PER_TASK
> unsigned long stack_canary;
> @@ -75,6 +77,17 @@ struct thread_info {
> #endif
> };
>
> +#ifdef CONFIG_THREAD_INFO_IN_TASK
> +
> +#define INIT_THREAD_INFO(tsk) \
> +{ \
> + .flags = 0, \
> + .preempt_count = INIT_PREEMPT_COUNT, \
> + .addr_limit = KERNEL_DS, \
> +}
> +
> +#else
> +
> #define INIT_THREAD_INFO(tsk) \
> { \
> .task = &tsk, \
> @@ -83,6 +96,9 @@ struct thread_info {
> .addr_limit = KERNEL_DS, \
> }
>
> +#endif
> +
> +#ifndef CONFIG_THREAD_INFO_IN_TASK
> /*
> * how to get the thread information struct from C
> */
> @@ -93,6 +109,7 @@ static inline struct thread_info *current_thread_info(void)
> return (struct thread_info *)
> (current_stack_pointer & ~(THREAD_SIZE - 1));
> }
> +#endif
>
> #define thread_saved_pc(tsk) \
> ((unsigned long)(task_thread_info(tsk)->cpu_context.pc))
> diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c
> index 70993af22d80..c91dcfe34bdd 100644
> --- a/arch/arm/kernel/asm-offsets.c
> +++ b/arch/arm/kernel/asm-offsets.c
> @@ -44,8 +44,12 @@ int main(void)
> DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
> DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count));
> DEFINE(TI_ADDR_LIMIT, offsetof(struct thread_info, addr_limit));
> +#ifdef CONFIG_THREAD_INFO_IN_TASK
> + DEFINE(TSK_CPU, offsetof(struct task_struct, cpu));
> +#else
> DEFINE(TI_TASK, offsetof(struct thread_info, task));
> DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
> +#endif
> DEFINE(TI_CPU_DOMAIN, offsetof(struct thread_info, cpu_domain));
> DEFINE(TI_CPU_SAVE, offsetof(struct thread_info, cpu_context));
> DEFINE(TI_USED_CP, offsetof(struct thread_info, used_cp));
> diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
> index 0ea8529a4872..a5d71b0d8897 100644
> --- a/arch/arm/kernel/entry-armv.S
> +++ b/arch/arm/kernel/entry-armv.S
> @@ -179,7 +179,7 @@ ENDPROC(__und_invalid)
> @
> stmia r7, {r2 - r6}
>
> - get_thread_info tsk
> + get_current tsk, r0
> uaccess_entry tsk, r0, r1, r2, \uaccess
>
> .if \trace
> @@ -260,7 +260,7 @@ __und_svc:
> bl __und_fault
>
> __und_svc_finish:
> - get_thread_info tsk
> + get_current tsk, r5
> ldr r5, [sp, #S_PSR] @ Get SVC cpsr
> svc_exit r5 @ return from exception
> UNWIND(.fnend )
> @@ -428,7 +428,7 @@ __irq_usr:
> usr_entry
> kuser_cmpxchg_check
> irq_handler
> - get_thread_info tsk
> + get_current tsk, why
> mov why, #0
> b ret_to_user_from_irq
> UNWIND(.fnend )
> @@ -572,12 +572,12 @@ ENDPROC(__und_usr)
> @ Fall-through from Thumb-2 __und_usr
> @
> #ifdef CONFIG_NEON
> - get_thread_info r10 @ get current thread
> + get_current r10, r6 @ get current thread
> adr r6, .LCneon_thumb_opcodes
> b 2f
> #endif
> call_fpe:
> - get_thread_info r10 @ get current thread
> + get_current r10, r6 @ get current thread
> #ifdef CONFIG_NEON
> adr r6, .LCneon_arm_opcodes
> 2: ldr r5, [r6], #4 @ mask value
> @@ -722,7 +722,7 @@ __pabt_usr:
> ENTRY(ret_from_exception)
> UNWIND(.fnstart )
> UNWIND(.cantunwind )
> - get_thread_info tsk
> + get_current tsk, why
> mov why, #0
> b ret_to_user
> UNWIND(.fnend )
> @@ -735,7 +735,7 @@ __fiq_usr:
> kuser_cmpxchg_check
> mov r0, sp @ struct pt_regs *regs
> bl handle_fiq_as_nmi
> - get_thread_info tsk
> + get_current tsk, r0
> restore_user_regs fast = 0, offset = 0
> UNWIND(.fnend )
> ENDPROC(__fiq_usr)
> @@ -771,6 +771,9 @@ ENTRY(__switch_to)
> #endif
> #ifdef CONFIG_CPU_USE_DOMAINS
> mcr p15, 0, r6, c3, c0, 0 @ Set domain register
> +#endif
> +#ifdef CONFIG_THREAD_INFO_IN_TASK
> + set_current_task r2, r4, r5
> #endif
> mov r5, r0
> add r4, r2, #TI_CPU_SAVE
> diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
> index 7f0b7aba1498..52580ee463fe 100644
> --- a/arch/arm/kernel/entry-common.S
> +++ b/arch/arm/kernel/entry-common.S
> @@ -156,7 +156,7 @@ ENTRY(ret_from_fork)
> movne r0, r4
> badrne lr, 1f
> retne r5
> -1: get_thread_info tsk
> +1: get_current tsk, r1
> b ret_slow_syscall
> ENDPROC(ret_from_fork)
>
> @@ -243,7 +243,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
> + get_current tsk, r10
> /*
> * Reload the registers that may have been corrupted on entry to
> * the syscall assembly (by tracing or context tracking.)
> @@ -278,7 +278,7 @@ local_restart:
> 9001:
> sub lr, saved_pc, #4
> str lr, [sp, #S_PC]
> - get_thread_info tsk
> + get_current tsk, r1
> b ret_fast_syscall
> #endif
> ENDPROC(vector_swi)
> diff --git a/arch/arm/kernel/entry-v7m.S b/arch/arm/kernel/entry-v7m.S
> index d0e898608d30..f36a7a876085 100644
> --- a/arch/arm/kernel/entry-v7m.S
> +++ b/arch/arm/kernel/entry-v7m.S
> @@ -57,7 +57,7 @@ __irq_entry:
> tst r0, V7M_SCB_ICSR_RETTOBASE
> beq 2f
>
> - get_thread_info tsk
> + get_current tsk, r2
> ldr r2, [tsk, #TI_FLAGS]
> movs r2, r2, lsl #16
> beq 2f @ no work pending
> @@ -83,7 +83,7 @@ __pendsv_entry:
> str r0, [r1, V7M_SCB_ICSR] @ clear PendSV
>
> @ execute the pending work, including reschedule
> - get_thread_info tsk
> + get_current tsk, why
> mov why, #0
> b ret_to_user_from_irq
> ENDPROC(__pendsv_entry)
> @@ -107,6 +107,9 @@ ENTRY(__switch_to)
> bl atomic_notifier_call_chain
> mov ip, r4
> mov r0, r5
> +#ifdef CONFIG_THREAD_INFO_IN_TASK
> + set_current_task r2, r4, r5
> +#endif
> ldmia ip!, {r4 - r11} @ Load all regs saved previously
> ldr sp, [ip]
> ldr pc, [ip, #4]!
> diff --git a/arch/arm/kernel/iwmmxt.S b/arch/arm/kernel/iwmmxt.S
> index d2b4ac06e4ed..781f7c7fca90 100644
> --- a/arch/arm/kernel/iwmmxt.S
> +++ b/arch/arm/kernel/iwmmxt.S
> @@ -96,7 +96,7 @@ ENTRY(iwmmxt_task_enable)
> bl concan_save
>
> #ifdef CONFIG_PREEMPT_COUNT
> - get_thread_info r10
> + get_current r10, r3
> #endif
> 4: dec_preempt_count r10, r3
> ret r9 @ normal exit from exception
> diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
> index 55cb1689a4b3..be0ede16dbb1 100644
> --- a/arch/arm/kernel/smp.c
> +++ b/arch/arm/kernel/smp.c
> @@ -51,6 +51,13 @@
> #define CREATE_TRACE_POINTS
> #include <trace/events/ipi.h>
>
> +#ifdef CONFIG_THREAD_INFO_IN_TASK
> +DEFINE_PER_CPU(struct task_struct *, current_task) ____cacheline_aligned =
> + &init_task;
> +EXPORT_PER_CPU_SYMBOL(current_task);
> +
> +#endif
> +
> /*
> * as from 2.5, kernels no longer have an init_tasks structure
> * so we need some other way of telling a new secondary core
> @@ -156,6 +163,10 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
> secondary_data.cpu = cpu;
> sync_cache_w(&secondary_data);
>
> +#ifdef CONFIG_THREAD_INFO_IN_TASK
> + per_cpu(current_task, cpu) = idle;
> +#endif
> +
> /*
> * Now bring the CPU into our world.
> */
> @@ -509,6 +520,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
> */
> if (max_cpus > ncores)
> max_cpus = ncores;
> +
> if (ncores > 1 && max_cpus) {
> /*
> * Initialise the present map, which describes the set of CPUs
> diff --git a/arch/arm/lib/copy_from_user.S b/arch/arm/lib/copy_from_user.S
> index f8016e3db65d..5320950100a2 100644
> --- a/arch/arm/lib/copy_from_user.S
> +++ b/arch/arm/lib/copy_from_user.S
> @@ -109,7 +109,7 @@
>
> ENTRY(arm_copy_from_user)
> #ifdef CONFIG_CPU_SPECTRE
> - get_thread_info r3
> + get_current r3, ip
> ldr r3, [r3, #TI_ADDR_LIMIT]
> uaccess_mask_range_ptr r1, r2, r3, ip
> #endif
> diff --git a/arch/arm/lib/copy_to_user.S b/arch/arm/lib/copy_to_user.S
> index ebfe4cb3d912..e7e61c87893a 100644
> --- a/arch/arm/lib/copy_to_user.S
> +++ b/arch/arm/lib/copy_to_user.S
> @@ -109,7 +109,7 @@
> ENTRY(__copy_to_user_std)
> WEAK(arm_copy_to_user)
> #ifdef CONFIG_CPU_SPECTRE
> - get_thread_info r3
> + get_current r3, ip
> ldr r3, [r3, #TI_ADDR_LIMIT]
> uaccess_mask_range_ptr r0, r2, r3, ip
> #endif
> diff --git a/arch/arm/mach-ep93xx/crunch-bits.S b/arch/arm/mach-ep93xx/crunch-bits.S
> index fb2dbf76f09e..d0bb34b3d973 100644
> --- a/arch/arm/mach-ep93xx/crunch-bits.S
> +++ b/arch/arm/mach-ep93xx/crunch-bits.S
> @@ -192,7 +192,7 @@ crunch_load:
>
> 1:
> #ifdef CONFIG_PREEMPT_COUNT
> - get_thread_info r10
> + get_current r10, r3
> #endif
> 2: dec_preempt_count r10, r3
> ret lr
> diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S
> index e2c743aa2eb2..a782c025fdf3 100644
> --- a/arch/arm/mm/proc-macros.S
> +++ b/arch/arm/mm/proc-macros.S
> @@ -30,7 +30,7 @@
> * act_mm - get current->active_mm
> */
> .macro act_mm, rd
> - get_thread_info \rd
> + get_current \rd, unused @ won't build if THREAD_INFO_IN_TASK
> ldr \rd, [\rd, #TI_TASK]
> .if (TSK_ACTIVE_MM > IMM12_MASK)
> add \rd, \rd, #TSK_ACTIVE_MM & ~IMM12_MASK
> diff --git a/arch/arm/vfp/entry.S b/arch/arm/vfp/entry.S
> index 27b0a1f27fbd..48cb40a3b72d 100644
> --- a/arch/arm/vfp/entry.S
> +++ b/arch/arm/vfp/entry.S
> @@ -24,7 +24,11 @@
> ENTRY(do_vfp)
> inc_preempt_count r10, r4
> ldr r4, .LCvfp
> +#ifdef CONFIG_THREAD_INFO_IN_TASK
> + ldr r11, [r10, #TSK_CPU] @ CPU number
> +#else
> ldr r11, [r10, #TI_CPU] @ CPU number
> +#endif
> add r10, r10, #TI_VFPSTATE @ r10 = workspace
> ldr pc, [r4] @ call VFP entry point
> ENDPROC(do_vfp)
> diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
> index 2cb355c1b5b7..f929a26a05a5 100644
> --- a/arch/arm/vfp/vfpmodule.c
> +++ b/arch/arm/vfp/vfpmodule.c
> @@ -143,22 +143,27 @@ static void vfp_thread_copy(struct thread_info *thread)
> * THREAD_NOFTIFY_SWTICH:
> * - the previously running thread will not be scheduled onto another CPU.
> * - the next thread to be run (v) will not be running on another CPU.
> - * - thread->cpu is the local CPU number
> + * - tsk->cpu is the local CPU number
> * - not preemptible as we're called in the middle of a thread switch
> * THREAD_NOTIFY_FLUSH:
> * - the thread (v) will be running on the local CPU, so
> - * v === current_thread_info()
> - * - thread->cpu is the local CPU number at the time it is accessed,
> + * v === current
> + * - tsk->cpu is the local CPU number at the time it is accessed,
> * but may change at any time.
> * - we could be preempted if tree preempt rcu is enabled, so
> - * it is unsafe to use thread->cpu.
> + * it is unsafe to use tsk->cpu.
> * THREAD_NOTIFY_EXIT
> * - we could be preempted if tree preempt rcu is enabled, so
> - * it is unsafe to use thread->cpu.
> + * it is unsafe to use tsk->cpu.
> */
> static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
> {
> +#ifdef CONFIG_THREAD_INFO_IN_TASK
> + struct task_struct *tsk = v;
> + struct thread_info *thread = &tsk->thread_info;
> +#else
> struct thread_info *thread = v;
> +#endif
> u32 fpexc;
> #ifdef CONFIG_SMP
> unsigned int cpu;
> @@ -169,7 +174,11 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
> fpexc = fmrx(FPEXC);
>
> #ifdef CONFIG_SMP
> +#ifdef CONFIG_THREAD_INFO_IN_TASK
> + cpu = tsk->cpu;
> +#else
> cpu = thread->cpu;
> +#endif
>
> /*
> * On SMP, if VFP is enabled, save the old state in
> @@ -458,16 +467,16 @@ static int vfp_pm_suspend(void)
>
> /* disable, just in case */
> fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
> - } else if (vfp_current_hw_state[ti->cpu]) {
> + } else if (vfp_current_hw_state[smp_processor_id()]) {
> #ifndef CONFIG_SMP
> fmxr(FPEXC, fpexc | FPEXC_EN);
> - vfp_save_state(vfp_current_hw_state[ti->cpu], fpexc);
> + vfp_save_state(vfp_current_hw_state[smp_processor_id()], fpexc);
> fmxr(FPEXC, fpexc);
> #endif
> }
>
> /* clear any information we had about last context state */
> - vfp_current_hw_state[ti->cpu] = NULL;
> + vfp_current_hw_state[smp_processor_id()] = NULL;
>
> return 0;
> }
> --
> 2.33.0
>
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH 2/3] ARM: Move thread_info into task_struct (v7 only)
2021-09-05 20:56 ` Ard Biesheuvel
@ 2021-09-06 6:14 ` Keith Packard
2021-09-06 7:49 ` Ard Biesheuvel
2021-09-06 6:20 ` Keith Packard
1 sibling, 1 reply; 36+ messages in thread
From: Keith Packard @ 2021-09-06 6:14 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: Linux Kernel Mailing List, Abbott Liu, Alexander Sverdlin,
Andrew Morton, Anshuman Khandual, Arnd Bergmann, Bjorn Andersson,
Florian Fainelli, Geert Uytterhoeven, Hartley Sweeten,
Jens Axboe, Jian Cai, Joe Perches, Kees Cook,
Krzysztof Kozlowski, Linus Walleij, Linux ARM,
Manivannan Sadhasivam, Marc Zyngier, Masahiro Yamada,
Miguel Ojeda, Mike Rapoport, Nathan Chancellor, Nick Desaulniers,
Nicolas Pitre, Rob Herring, Russell King, Thomas Gleixner,
Uwe Kleine-König, Valentin Schneider, Viresh Kumar,
Wolfram Sang (Renesas),
YiFei Zhu
[-- Attachment #1: Type: text/plain, Size: 2504 bytes --]
Ard Biesheuvel <ardb@kernel.org> writes:
> c13 is not a register, it is a value in one of the dimensions of the
> ARM sysreg space, and probably covers other system registers that
> pre-v7 cores do implement.
> Better to use its architectural name (TPIDRPRW) and clarify that
> pre-v6k/v7 cores simply don't implement it.
Thanks, I'll reword the commit message
> Could we split this up?
I could split up the assembler macro changes which add a temporary
register to the calls getting the current thread_info/task_struct value?
If that would help get this reviewed, I'd be happy to do
that. Otherwise, it's pretty much all-or-nothing as enabling
THREAD_INFO_IN_TASK requires a bunch of synchronized changes.
>> +#ifdef CONFIG_THREAD_INFO_IN_TASK
>
> No need for this #ifdef - it only guards macros that will have no
> effect if they are never instantiated (another case below)
Sure, the resulting code is a bit less noisy, which seems good.
>> +DECLARE_PER_CPU(struct task_struct *, current_task);
>> +
>> +static __always_inline struct task_struct *get_current(void)
>> +{
>> + return raw_cpu_read(current_task);
>
> This needs to run with preemption disabled, or we might get migrated
> to another CPU halfway through, and produce the wrong result (i.e.,
> the current task of the CPU we migrated from). However, it appears
> that manipulating the preempt count will create a circular dependency
> here.
Yeah, I really don't understand the restrictions of this API well. Any
code fetching the current task pointer better not be subject to
preemption or that value will be stale at some point after it was
computed. Do you know if it could ever be run in a context allowing
preemption?
>
> Instead of using a per-CPU variable for current, I think it might be
> better to borrow another system register (TPIDRURO or TPIDRURW) to
> carry 'current' when THREAD_INFO_IN_TASK is in effect, similar to how
> arm64 uses SP_EL0 - those registers could be preserved/restored in the
> entry/exit from/to user space paths rather than in the context switch
> path, and then be used any way we like while running in the kernel.
Making sure these values don't leak through to user space somehow? I'm
not excited by that prospect at all. But, perhaps someone can help me
understand the conditions under which the current task value can be
computed where preemption was enabled and have that not be a problem for
the enclosing code?
--
-keith
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH 2/3] ARM: Move thread_info into task_struct (v7 only)
2021-09-05 20:56 ` Ard Biesheuvel
2021-09-06 6:14 ` Keith Packard
@ 2021-09-06 6:20 ` Keith Packard
1 sibling, 0 replies; 36+ messages in thread
From: Keith Packard @ 2021-09-06 6:20 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: Linux Kernel Mailing List, Abbott Liu, Alexander Sverdlin,
Andrew Morton, Anshuman Khandual, Arnd Bergmann, Bjorn Andersson,
Florian Fainelli, Geert Uytterhoeven, Hartley Sweeten,
Jens Axboe, Jian Cai, Joe Perches, Kees Cook,
Krzysztof Kozlowski, Linus Walleij, Linux ARM,
Manivannan Sadhasivam, Marc Zyngier, Masahiro Yamada,
Miguel Ojeda, Mike Rapoport, Nathan Chancellor, Nick Desaulniers,
Nicolas Pitre, Rob Herring, Russell King, Thomas Gleixner,
Uwe Kleine-König, Valentin Schneider, Viresh Kumar,
Wolfram Sang (Renesas),
YiFei Zhu
[-- Attachment #1: Type: text/plain, Size: 2119 bytes --]
Ard Biesheuvel <ardb@kernel.org> writes:
(sorry, missed a couple of comments, and also neglected to thank you for
your review!)
>> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
>> index 24804f11302d..1c1ded500a2b 100644
>> --- a/arch/arm/Kconfig
>> +++ b/arch/arm/Kconfig
>> @@ -128,6 +128,7 @@ config ARM
>> select RTC_LIB
>> select SET_FS
>> select SYS_SUPPORTS_APM_EMULATION
>> + select THREAD_INFO_IN_TASK if CPU_V7
>
> CPU_V6K also supports this
I've only tested on V7; help getting testing for V6K so we could enable
that as well would be greatly appreciated.
>> diff --git a/arch/arm/Makefile b/arch/arm/Makefile
>> index 415c3514573a..71a2ba4549d3 100644
>> --- a/arch/arm/Makefile
>> +++ b/arch/arm/Makefile
>> @@ -284,6 +284,14 @@ stack_protector_prepare: prepare0
>> $(eval GCC_PLUGINS_CFLAGS += $(SSP_PLUGIN_CFLAGS))
>> endif
>>
>> +ifdef CONFIG_SMP
>> +prepare: task_cpu_prepare
>> +
>> +PHONY += task_cpu_prepare
>> +task_cpu_prepare: prepare0
>> + $(eval KBUILD_CFLAGS += -D_TSK_CPU=$(shell awk '{if ($$2 == "TSK_CPU") print $$3;}' include/generated/asm-offsets.h))
>> +endif
>> +
>> all: $(notdir $(KBUILD_IMAGE))
>>
>
> This is rather horrid, and removed again in the next patch. Can we
> omit it entirely?
Yeah, this did get rather ugly -- I wanted to use the task_struct in the
raw_smp_processor_id() macro, but discovered that I couldn't include
linux/sched.h in that file.
I found this lovely hack in the powerpc kernel code and just lifted it
from there. In terms of code changes, this one is "smaller" than
including the new per-cpu variable, "cpu_number", but in terms of
ugliness, it's hard to argue which is cleaner.
I was going for fewest logical changes in structure with this patch
instead of cleanest result to try and make it slightly easier to review.
Happy to squash these two patches together if you'd prefer; I initially
wrote the code with the cpu_number variable but then discovered that I
didn't need it if I used the cpu value in the task_struct...
--
-keith
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH 2/3] ARM: Move thread_info into task_struct (v7 only)
2021-09-06 6:14 ` Keith Packard
@ 2021-09-06 7:49 ` Ard Biesheuvel
2021-09-07 15:24 ` Keith Packard
0 siblings, 1 reply; 36+ messages in thread
From: Ard Biesheuvel @ 2021-09-06 7:49 UTC (permalink / raw)
To: Keith Packard
Cc: Linux Kernel Mailing List, Abbott Liu, Alexander Sverdlin,
Andrew Morton, Anshuman Khandual, Arnd Bergmann, Bjorn Andersson,
Florian Fainelli, Geert Uytterhoeven, Hartley Sweeten,
Jens Axboe, Jian Cai, Joe Perches, Kees Cook,
Krzysztof Kozlowski, Linus Walleij, Linux ARM,
Manivannan Sadhasivam, Marc Zyngier, Masahiro Yamada,
Miguel Ojeda, Mike Rapoport, Nathan Chancellor, Nick Desaulniers,
Nicolas Pitre, Rob Herring, Russell King, Thomas Gleixner,
Uwe Kleine-König, Valentin Schneider, Viresh Kumar,
Wolfram Sang (Renesas),
YiFei Zhu
On Mon, 6 Sept 2021 at 08:14, Keith Packard <keithp@keithp.com> wrote:
>
> Ard Biesheuvel <ardb@kernel.org> writes:
>
> > c13 is not a register, it is a value in one of the dimensions of the
> > ARM sysreg space, and probably covers other system registers that
> > pre-v7 cores do implement.
>
> > Better to use its architectural name (TPIDRPRW) and clarify that
> > pre-v6k/v7 cores simply don't implement it.
>
> Thanks, I'll reword the commit message
>
> > Could we split this up?
>
> I could split up the assembler macro changes which add a temporary
> register to the calls getting the current thread_info/task_struct value?
> If that would help get this reviewed, I'd be happy to do
> that. Otherwise, it's pretty much all-or-nothing as enabling
> THREAD_INFO_IN_TASK requires a bunch of synchronized changes.
>
Sure, so it is precisely for that reason that it is better to isolate
changes that can be isolated.
...
> >> +DECLARE_PER_CPU(struct task_struct *, current_task);
> >> +
> >> +static __always_inline struct task_struct *get_current(void)
> >> +{
> >> + return raw_cpu_read(current_task);
> >
> > This needs to run with preemption disabled, or we might get migrated
> > to another CPU halfway through, and produce the wrong result (i.e.,
> > the current task of the CPU we migrated from). However, it appears
> > that manipulating the preempt count will create a circular dependency
> > here.
>
> Yeah, I really don't understand the restrictions of this API well. Any
> code fetching the current task pointer better not be subject to
> preemption or that value will be stale at some point after it was
> computed. Do you know if it could ever be run in a context allowing
> preemption?
All the time. 'current' essentially never changes value from the POV
of code running in task context, so there is usually no reason to care
about preemption/migration when referring to it. Using per-CPU
variables is what creates the problem here.
> >
> > Instead of using a per-CPU variable for current, I think it might be
> > better to borrow another system register (TPIDRURO or TPIDRURW) to
> > carry 'current' when THREAD_INFO_IN_TASK is in effect, similar to how
> > arm64 uses SP_EL0 - those registers could be preserved/restored in the
> > entry/exit from/to user space paths rather than in the context switch
> > path, and then be used any way we like while running in the kernel.
>
> Making sure these values don't leak through to user space somehow? I'm
> not excited by that prospect at all.
Moving the code that pokes the right user space value into these
registers from the context switch patch to the user space exit path
should be rather straight-forward, so I am not too concerned about
security issues here (famous last words)
> But, perhaps someone can help me
> understand the conditions under which the current task value can be
> computed where preemption was enabled and have that not be a problem for
> the enclosing code?
>
In principle, it should be sufficient to run the per-CPU variable load
sequence with preemption disabled. For instance, your asm version
movw \dst, #:lower16:\sym
movt \dst, #:upper16:\sym
this_cpu_offset \tmp
ldr \dst, [\dst, \tmp]
must not be preempted and migrated right before the ldr instruction,
because that would end up accessing another CPU's value for 'current'.
However, the preempt_count itself is stored in thread_info as well, so
I'm not sure there is a way we can safely disable preemption for this
sequence to begin with, unless we run the above with interrupts
disabled.
Given that we are already relying on the MP extensions for this
anyway, I personally think that using another thread ID register to
carry 'current' is a reasonable approach as well, since it would also
allow us to get per-task stack protector support into the compiler.
But I would like to hear from some other folks on cc as well.
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH 2/3] ARM: Move thread_info into task_struct (v7 only)
2021-09-06 7:49 ` Ard Biesheuvel
@ 2021-09-07 15:24 ` Keith Packard
2021-09-07 16:05 ` Ard Biesheuvel
0 siblings, 1 reply; 36+ messages in thread
From: Keith Packard @ 2021-09-07 15:24 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: Linux Kernel Mailing List, Abbott Liu, Alexander Sverdlin,
Andrew Morton, Anshuman Khandual, Arnd Bergmann, Bjorn Andersson,
Florian Fainelli, Geert Uytterhoeven, Hartley Sweeten,
Jens Axboe, Jian Cai, Joe Perches, Kees Cook,
Krzysztof Kozlowski, Linus Walleij, Linux ARM,
Manivannan Sadhasivam, Marc Zyngier, Masahiro Yamada,
Miguel Ojeda, Mike Rapoport, Nathan Chancellor, Nick Desaulniers,
Nicolas Pitre, Rob Herring, Russell King, Thomas Gleixner,
Uwe Kleine-König, Valentin Schneider, Viresh Kumar,
Wolfram Sang (Renesas),
YiFei Zhu
[-- Attachment #1: Type: text/plain, Size: 1505 bytes --]
Ard Biesheuvel <ardb@kernel.org> writes:
> Sure, so it is precisely for that reason that it is better to isolate
> changes that can be isolated.
I'll go ahead and split this apart then; that is how I did development,
after all.
> All the time. 'current' essentially never changes value from the POV
> of code running in task context, so there is usually no reason to care
> about preemption/migration when referring to it. Using per-CPU
> variables is what creates the problem here.
Thanks for helping me -- I just got the wrong model stuck in my head
over the weekend somehow.
If I do have this figured out, we should be able to stick the
per_cpu_offset value in thread_info and use TPIDRPRW to hold 'current'
as code using per_cpu_offset should already be disabling
preemption. That should be an easier change than putting a kernel
pointer in a user-visible register.
> Given that we are already relying on the MP extensions for this
> anyway, I personally think that using another thread ID register to
> carry 'current' is a reasonable approach as well, since it would also
> allow us to get per-task stack protector support into the compiler.
> But I would like to hear from some other folks on cc as well.
That would be awesome; I assume that doesn't require leaving
per_cpu_offset in a thread ID register?
In any case, I'll give my plan a try, and then see about trying your
plan as well so I can compare the complexity of the two solutions.
--
-keith
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH 2/3] ARM: Move thread_info into task_struct (v7 only)
2021-09-07 15:24 ` Keith Packard
@ 2021-09-07 16:05 ` Ard Biesheuvel
2021-09-07 22:17 ` Keith Packard
0 siblings, 1 reply; 36+ messages in thread
From: Ard Biesheuvel @ 2021-09-07 16:05 UTC (permalink / raw)
To: Keith Packard
Cc: Linux Kernel Mailing List, Abbott Liu, Alexander Sverdlin,
Andrew Morton, Anshuman Khandual, Arnd Bergmann, Bjorn Andersson,
Florian Fainelli, Geert Uytterhoeven, Hartley Sweeten,
Jens Axboe, Jian Cai, Joe Perches, Kees Cook,
Krzysztof Kozlowski, Linus Walleij, Linux ARM,
Manivannan Sadhasivam, Marc Zyngier, Masahiro Yamada,
Miguel Ojeda, Mike Rapoport, Nathan Chancellor, Nick Desaulniers,
Nicolas Pitre, Rob Herring, Russell King, Thomas Gleixner,
Uwe Kleine-König, Valentin Schneider, Viresh Kumar,
Wolfram Sang (Renesas),
YiFei Zhu
On Tue, 7 Sept 2021 at 17:24, Keith Packard <keithp@keithp.com> wrote:
>
> Ard Biesheuvel <ardb@kernel.org> writes:
>
> > Sure, so it is precisely for that reason that it is better to isolate
> > changes that can be isolated.
>
> I'll go ahead and split this apart then; that is how I did development,
> after all.
>
> > All the time. 'current' essentially never changes value from the POV
> > of code running in task context, so there is usually no reason to care
> > about preemption/migration when referring to it. Using per-CPU
> > variables is what creates the problem here.
>
> Thanks for helping me -- I just got the wrong model stuck in my head
> over the weekend somehow.
>
> If I do have this figured out, we should be able to stick the
> per_cpu_offset value in thread_info and use TPIDRPRW to hold 'current'
> as code using per_cpu_offset should already be disabling
> preemption. That should be an easier change than putting a kernel
> pointer in a user-visible register.
>
That is still a bit tricky, given that you now have to swap out the
per-CPU offset when you migrate a task, and the generic code is not
really set up for that.
> > Given that we are already relying on the MP extensions for this
> > anyway, I personally think that using another thread ID register to
> > carry 'current' is a reasonable approach as well, since it would also
> > allow us to get per-task stack protector support into the compiler.
> > But I would like to hear from some other folks on cc as well.
>
> That would be awesome; I assume that doesn't require leaving
> per_cpu_offset in a thread ID register?
>
> In any case, I'll give my plan a try, and then see about trying your
> plan as well so I can compare the complexity of the two solutions.
>
I had a stab at this myself today (long boring day with no Internet connection).
https://android-kvm.googlesource.com/linux/+log/refs/heads/ardb/arm32-ti-in-task
It resembles your code in some places - I suppose we went on the same
journey in a sense :-) We'll fix up the credits before this gets
resubmitted.
Fixing the per-task stack protector plugin on top of these changes
should be trivial but I need a coffee first.
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH 0/7] ARM: support THREAD_INFO_IN_TASK (v3)
2021-09-04 6:09 ` [PATCH 0/2] ARM: support THREAD_INFO_IN_TASK (v7 only) (v2) Keith Packard
` (2 preceding siblings ...)
2021-09-04 6:09 ` [PATCH 3/3] ARM: Add per-cpu variable cpu_number " Keith Packard
@ 2021-09-07 22:00 ` Keith Packard
2021-09-07 22:00 ` [PATCH 1/7] ARM: Pass cpu number to secondary_start_kernel Keith Packard
` (7 more replies)
3 siblings, 8 replies; 36+ messages in thread
From: Keith Packard @ 2021-09-07 22:00 UTC (permalink / raw)
To: linux-kernel
Cc: Abbott Liu, Andrew Morton, Andrey Ryabinin, Anshuman Khandual,
Ard Biesheuvel, Arnd Bergmann, Bjorn Andersson,
Christoph Lameter, Dennis Zhou, Geert Uytterhoeven, Jens Axboe,
Joe Perches, Kees Cook, Keith Packard, Krzysztof Kozlowski,
Linus Walleij, linux-arm-kernel, linux-mm, Manivannan Sadhasivam,
Marc Zyngier, Masahiro Yamada, Mike Rapoport, Nathan Chancellor,
Nick Desaulniers, Nick Desaulniers, Nicolas Pitre, Russell King,
Tejun Heo, Thomas Gleixner, Uwe Kleine-König,
Valentin Schneider, Viresh Kumar, Wolfram Sang (Renesas),
YiFei Zhu
Placing thread_info in the kernel stack leaves it vulnerable to stack
overflow attacks. This short series addresses that by using the
existing THREAD_INFO_IN_TASK infrastructure.
This is the third version of this series, in this version the changes
are restricted to hardware which provides the TPIDRPRW register. This
register is repurposed from holding the per_cpu_offset value to
holding the 'current' value as that allows fetching this value
atomically so that it can be used in a preemptable context.
The series is broken into seven pieces:
1) Change the secondary_start_kernel API to receive the cpu
number. This avoids needing to be able to find this value independently in
future patches.
2) Change the secondary_start_kernel API to also receive the 'task'
value. Passing the value to this function also avoids needing to
be able to discover it independently.
3) A cleanup which avoids assuming that THREAD_INFO_IN_TASK is not set.
4) A hack, borrowed from the powerpc arch, which allows locating the 'cpu'
field in either thread_info or task_struct, without requiring linux/sched.h
to be included in asm/smp.h
5) Disable the optimization storing per_cpu_offset in TPIDRPRW. This leaves
the register free to hold 'current' instead.
6) Use TPIDRPRW for 'current'. This is enabled for either CPU_V6K or CPU_V7,
but not if CPU_V6 is also enabled.
7) Enable THREAD_INFO_IN_TASK whenever TPIDRPRW is used to hold 'current'.
Signed-off-by: Keith Packard <keithpac@amazon.com>
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH 1/7] ARM: Pass cpu number to secondary_start_kernel
2021-09-07 22:00 ` [PATCH 0/7] ARM: support THREAD_INFO_IN_TASK (v3) Keith Packard
@ 2021-09-07 22:00 ` Keith Packard
2021-09-07 22:00 ` [PATCH 2/7] ARM: Pass task " Keith Packard
` (6 subsequent siblings)
7 siblings, 0 replies; 36+ messages in thread
From: Keith Packard @ 2021-09-07 22:00 UTC (permalink / raw)
To: linux-kernel
Cc: Abbott Liu, Andrew Morton, Andrey Ryabinin, Anshuman Khandual,
Ard Biesheuvel, Arnd Bergmann, Bjorn Andersson,
Christoph Lameter, Dennis Zhou, Geert Uytterhoeven, Jens Axboe,
Joe Perches, Kees Cook, Keith Packard, Krzysztof Kozlowski,
Linus Walleij, linux-arm-kernel, linux-mm, Manivannan Sadhasivam,
Marc Zyngier, Masahiro Yamada, Mike Rapoport, Nathan Chancellor,
Nick Desaulniers, Nick Desaulniers, Nicolas Pitre, Russell King,
Tejun Heo, Thomas Gleixner, Uwe Kleine-König,
Valentin Schneider, Viresh Kumar, Wolfram Sang (Renesas),
YiFei Zhu
Instead of pulling the CPU value out of the thread_info struct, pass
it as an argument. When first initializing secondary processors, this
is done by stashing the value in the secondary_data struct. When
restarting idle processors, the previous CPU value is passed.
Because the cpu is now known at the top of secondary_start_kernel, the
per_cpu_offset value can now be set at this point, instead of in
cpu_init where it was also incorrectly setting the per_cpu_offset for
the boot processor before that value had been computed.
Signed-off-by: Keith Packard <keithpac@amazon.com>
Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/arm/include/asm/smp.h | 3 ++-
arch/arm/kernel/head-nommu.S | 1 +
arch/arm/kernel/head.S | 1 +
arch/arm/kernel/setup.c | 6 ------
arch/arm/kernel/smp.c | 14 +++++++++-----
5 files changed, 13 insertions(+), 12 deletions(-)
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 5d508f5d56c4..86a7fd721556 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -48,7 +48,7 @@ extern void set_smp_ipi_range(int ipi_base, int nr_ipi);
* Called from platform specific assembly code, this is the
* secondary CPU entry point.
*/
-asmlinkage void secondary_start_kernel(void);
+asmlinkage void secondary_start_kernel(unsigned int cpu);
/*
@@ -61,6 +61,7 @@ struct secondary_data {
};
unsigned long swapper_pg_dir;
void *stack;
+ unsigned int cpu;
};
extern struct secondary_data secondary_data;
extern void secondary_startup(void);
diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S
index 0fc814bbc34b..5aa8ef42717f 100644
--- a/arch/arm/kernel/head-nommu.S
+++ b/arch/arm/kernel/head-nommu.S
@@ -114,6 +114,7 @@ ENTRY(secondary_startup)
add r12, r12, r10
ret r12
1: bl __after_proc_init
+ ldr r0, [r7, #16] @ set up cpu number
ldr sp, [r7, #12] @ set up the stack pointer
mov fp, #0
b secondary_start_kernel
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index 7f62c5eccdf3..0e541af738e2 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -394,6 +394,7 @@ ENDPROC(secondary_startup_arm)
ENTRY(__secondary_switched)
ldr_l r7, secondary_data + 12 @ get secondary_data.stack
+ ldr_l r0, secondary_data + 16 @ get secondary_data.cpu
mov sp, r7
mov fp, #0
b secondary_start_kernel
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 73ca7797b92f..ca0201635fac 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -532,12 +532,6 @@ void notrace cpu_init(void)
BUG();
}
- /*
- * This only works on resume and secondary cores. For booting on the
- * boot cpu, smp_prepare_boot_cpu is called after percpu area setup.
- */
- set_my_cpu_offset(per_cpu_offset(cpu));
-
cpu_proc_init();
/*
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 74679240a9d8..55cb1689a4b3 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -153,6 +153,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
secondary_data.pgdir = virt_to_phys(idmap_pgd);
secondary_data.swapper_pg_dir = get_arch_pgd(swapper_pg_dir);
#endif
+ secondary_data.cpu = cpu;
sync_cache_w(&secondary_data);
/*
@@ -373,11 +374,14 @@ void arch_cpu_idle_dead(void)
* cpu initialisation. There's some initialisation which needs
* to be repeated to undo the effects of taking the CPU offline.
*/
- __asm__("mov sp, %0\n"
+ __asm__("mov r0, %1\n"
+ " mov sp, %0\n"
" mov fp, #0\n"
" b secondary_start_kernel"
:
- : "r" (task_stack_page(current) + THREAD_SIZE - 8));
+ : "r" (task_stack_page(current) + THREAD_SIZE - 8),
+ "r" (cpu)
+ : "r0");
}
#endif /* CONFIG_HOTPLUG_CPU */
@@ -400,10 +404,11 @@ static void smp_store_cpu_info(unsigned int cpuid)
* This is the secondary CPU boot entry. We're using this CPUs
* idle thread stack, but a set of temporary page tables.
*/
-asmlinkage void secondary_start_kernel(void)
+asmlinkage void secondary_start_kernel(unsigned int cpu)
{
struct mm_struct *mm = &init_mm;
- unsigned int cpu;
+
+ set_my_cpu_offset(per_cpu_offset(cpu));
secondary_biglittle_init();
@@ -420,7 +425,6 @@ asmlinkage void secondary_start_kernel(void)
* All kernel threads share the same mm context; grab a
* reference and switch to it.
*/
- cpu = smp_processor_id();
mmgrab(mm);
current->active_mm = mm;
cpumask_set_cpu(cpu, mm_cpumask(mm));
--
2.33.0
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH 2/7] ARM: Pass task to secondary_start_kernel
2021-09-07 22:00 ` [PATCH 0/7] ARM: support THREAD_INFO_IN_TASK (v3) Keith Packard
2021-09-07 22:00 ` [PATCH 1/7] ARM: Pass cpu number to secondary_start_kernel Keith Packard
@ 2021-09-07 22:00 ` Keith Packard
2021-09-07 22:00 ` [PATCH 3/7] ARM: Use smp_processor_id() in vfp_pm_suspend instead of ti->cpu Keith Packard
` (5 subsequent siblings)
7 siblings, 0 replies; 36+ messages in thread
From: Keith Packard @ 2021-09-07 22:00 UTC (permalink / raw)
To: linux-kernel
Cc: Abbott Liu, Andrew Morton, Andrey Ryabinin, Anshuman Khandual,
Ard Biesheuvel, Arnd Bergmann, Bjorn Andersson,
Christoph Lameter, Dennis Zhou, Geert Uytterhoeven, Jens Axboe,
Joe Perches, Kees Cook, Keith Packard, Krzysztof Kozlowski,
Linus Walleij, linux-arm-kernel, linux-mm, Manivannan Sadhasivam,
Marc Zyngier, Masahiro Yamada, Mike Rapoport, Nathan Chancellor,
Nick Desaulniers, Nick Desaulniers, Nicolas Pitre, Russell King,
Tejun Heo, Thomas Gleixner, Uwe Kleine-König,
Valentin Schneider, Viresh Kumar, Wolfram Sang (Renesas),
YiFei Zhu
This avoids needing to compute the task pointer in this function,
allowing it to be used as the source of identification in the future.
Signed-off-by: Keith Packard <keithpac@amazon.com>
---
arch/arm/include/asm/smp.h | 3 ++-
arch/arm/kernel/head-nommu.S | 1 +
arch/arm/kernel/head.S | 1 +
arch/arm/kernel/smp.c | 8 +++++---
4 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 86a7fd721556..d43b64635d77 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -48,7 +48,7 @@ extern void set_smp_ipi_range(int ipi_base, int nr_ipi);
* Called from platform specific assembly code, this is the
* secondary CPU entry point.
*/
-asmlinkage void secondary_start_kernel(unsigned int cpu);
+asmlinkage void secondary_start_kernel(unsigned int cpu, struct task_struct *task);
/*
@@ -62,6 +62,7 @@ struct secondary_data {
unsigned long swapper_pg_dir;
void *stack;
unsigned int cpu;
+ struct task_struct *task;
};
extern struct secondary_data secondary_data;
extern void secondary_startup(void);
diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S
index 5aa8ef42717f..218715c135ed 100644
--- a/arch/arm/kernel/head-nommu.S
+++ b/arch/arm/kernel/head-nommu.S
@@ -115,6 +115,7 @@ ENTRY(secondary_startup)
ret r12
1: bl __after_proc_init
ldr r0, [r7, #16] @ set up cpu number
+ ldr r1, [r7, #20] @ set up task pointer
ldr sp, [r7, #12] @ set up the stack pointer
mov fp, #0
b secondary_start_kernel
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index 0e541af738e2..4a6cb0b0808b 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -395,6 +395,7 @@ ENDPROC(secondary_startup_arm)
ENTRY(__secondary_switched)
ldr_l r7, secondary_data + 12 @ get secondary_data.stack
ldr_l r0, secondary_data + 16 @ get secondary_data.cpu
+ ldr_l r1, secondary_data + 20 @ get secondary_data.task
mov sp, r7
mov fp, #0
b secondary_start_kernel
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 55cb1689a4b3..5e999f1f1aea 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -154,6 +154,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
secondary_data.swapper_pg_dir = get_arch_pgd(swapper_pg_dir);
#endif
secondary_data.cpu = cpu;
+ secondary_data.task = idle;
sync_cache_w(&secondary_data);
/*
@@ -375,13 +376,14 @@ void arch_cpu_idle_dead(void)
* to be repeated to undo the effects of taking the CPU offline.
*/
__asm__("mov r0, %1\n"
+ " mov r1, %2\n"
" mov sp, %0\n"
" mov fp, #0\n"
" b secondary_start_kernel"
:
: "r" (task_stack_page(current) + THREAD_SIZE - 8),
- "r" (cpu)
- : "r0");
+ "r" (cpu), "r" (current)
+ : "r0", "r1");
}
#endif /* CONFIG_HOTPLUG_CPU */
@@ -404,7 +406,7 @@ static void smp_store_cpu_info(unsigned int cpuid)
* This is the secondary CPU boot entry. We're using this CPUs
* idle thread stack, but a set of temporary page tables.
*/
-asmlinkage void secondary_start_kernel(unsigned int cpu)
+asmlinkage void secondary_start_kernel(unsigned int cpu, struct task_struct *task)
{
struct mm_struct *mm = &init_mm;
--
2.33.0
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH 3/7] ARM: Use smp_processor_id() in vfp_pm_suspend instead of ti->cpu
2021-09-07 22:00 ` [PATCH 0/7] ARM: support THREAD_INFO_IN_TASK (v3) Keith Packard
2021-09-07 22:00 ` [PATCH 1/7] ARM: Pass cpu number to secondary_start_kernel Keith Packard
2021-09-07 22:00 ` [PATCH 2/7] ARM: Pass task " Keith Packard
@ 2021-09-07 22:00 ` Keith Packard
2021-09-07 22:00 ` [PATCH 4/7] ARM: Use hack from powerpc to get current cpu number Keith Packard
` (4 subsequent siblings)
7 siblings, 0 replies; 36+ messages in thread
From: Keith Packard @ 2021-09-07 22:00 UTC (permalink / raw)
To: linux-kernel
Cc: Abbott Liu, Andrew Morton, Andrey Ryabinin, Anshuman Khandual,
Ard Biesheuvel, Arnd Bergmann, Bjorn Andersson,
Christoph Lameter, Dennis Zhou, Geert Uytterhoeven, Jens Axboe,
Joe Perches, Kees Cook, Keith Packard, Krzysztof Kozlowski,
Linus Walleij, linux-arm-kernel, linux-mm, Manivannan Sadhasivam,
Marc Zyngier, Masahiro Yamada, Mike Rapoport, Nathan Chancellor,
Nick Desaulniers, Nick Desaulniers, Nicolas Pitre, Russell King,
Tejun Heo, Thomas Gleixner, Uwe Kleine-König,
Valentin Schneider, Viresh Kumar, Wolfram Sang (Renesas),
YiFei Zhu
These are equivalent when thread_info contains the CPU value, but when
THREAD_INFO_IN_TASK is enabled, cpu moves to task_struct. Using the macro
allows either.
Signed-off-by: Keith Packard <keithpac@amazon.com>
---
arch/arm/vfp/vfpmodule.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 2cb355c1b5b7..d7a3818da671 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -458,16 +458,16 @@ static int vfp_pm_suspend(void)
/* disable, just in case */
fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
- } else if (vfp_current_hw_state[ti->cpu]) {
+ } else if (vfp_current_hw_state[smp_processor_id()]) {
#ifndef CONFIG_SMP
fmxr(FPEXC, fpexc | FPEXC_EN);
- vfp_save_state(vfp_current_hw_state[ti->cpu], fpexc);
+ vfp_save_state(vfp_current_hw_state[smp_processor_id()], fpexc);
fmxr(FPEXC, fpexc);
#endif
}
/* clear any information we had about last context state */
- vfp_current_hw_state[ti->cpu] = NULL;
+ vfp_current_hw_state[smp_processor_id()] = NULL;
return 0;
}
--
2.33.0
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH 4/7] ARM: Use hack from powerpc to get current cpu number
2021-09-07 22:00 ` [PATCH 0/7] ARM: support THREAD_INFO_IN_TASK (v3) Keith Packard
` (2 preceding siblings ...)
2021-09-07 22:00 ` [PATCH 3/7] ARM: Use smp_processor_id() in vfp_pm_suspend instead of ti->cpu Keith Packard
@ 2021-09-07 22:00 ` Keith Packard
2021-09-08 7:45 ` Ard Biesheuvel
2021-09-07 22:00 ` [PATCH 5/7] ARM: Stop using TPIDRPRW to hold per_cpu_offset Keith Packard
` (3 subsequent siblings)
7 siblings, 1 reply; 36+ messages in thread
From: Keith Packard @ 2021-09-07 22:00 UTC (permalink / raw)
To: linux-kernel
Cc: Abbott Liu, Andrew Morton, Andrey Ryabinin, Anshuman Khandual,
Ard Biesheuvel, Arnd Bergmann, Bjorn Andersson,
Christoph Lameter, Dennis Zhou, Geert Uytterhoeven, Jens Axboe,
Joe Perches, Kees Cook, Keith Packard, Krzysztof Kozlowski,
Linus Walleij, linux-arm-kernel, linux-mm, Manivannan Sadhasivam,
Marc Zyngier, Masahiro Yamada, Mike Rapoport, Nathan Chancellor,
Nick Desaulniers, Nick Desaulniers, Nicolas Pitre, Russell King,
Tejun Heo, Thomas Gleixner, Uwe Kleine-König,
Valentin Schneider, Viresh Kumar, Wolfram Sang (Renesas),
YiFei Zhu
When we enable THREAD_INFO_IN_TASK, the cpu number will disappear from
thread_info and reappear in task_struct. As we cannot include
linux/sched.h in asm/smp.h, there's no way to use that struct type in
the raw_smp_processor_id macro. Instead, a hack from the powerpc code
is used. This pulls the TI_CPU offset out of asm-offsets.h and uses
that to find the cpu value.
Signed-off-by: Keith Packard <keithpac@amazon.com>
---
arch/arm/Makefile | 8 ++++++++
arch/arm/include/asm/smp.h | 18 +++++++++++++++++-
2 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 415c3514573a..6752995d2914 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -284,6 +284,14 @@ stack_protector_prepare: prepare0
$(eval GCC_PLUGINS_CFLAGS += $(SSP_PLUGIN_CFLAGS))
endif
+ifdef CONFIG_SMP
+prepare: task_cpu_prepare
+
+PHONY += task_cpu_prepare
+task_cpu_prepare: prepare0
+ $(eval KBUILD_CFLAGS += -D_TI_CPU=$(shell awk '{if ($$2 == "TI_CPU") print $$3;}' include/generated/asm-offsets.h))
+endif
+
all: $(notdir $(KBUILD_IMAGE))
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index d43b64635d77..f77ba3753bc4 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -15,7 +15,23 @@
# error "<asm/smp.h> included in non-SMP build"
#endif
-#define raw_smp_processor_id() (current_thread_info()->cpu)
+/*
+ * This is particularly ugly: it appears we can't actually get the
+ * definition of task_struct here, but we need access to the CPU this
+ * task is running on, which is stored in task_struct when
+ * THREAD_INFO_IN_TASK is set. Instead of using task_struct we're
+ * using TI_CPU which is extracted from asm-offsets.h by kbuild to get
+ * the current processor ID.
+ *
+ * This also needs to be safeguarded when building asm-offsets.s
+ * because at that time TI_CPU is not defined yet.
+ */
+#ifndef _TI_CPU
+#define raw_smp_processor_id() (0)
+#else
+#define raw_smp_processor_id() \
+ (*(unsigned int *)((void *)current_thread_info() + _TI_CPU))
+#endif
struct seq_file;
--
2.33.0
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH 5/7] ARM: Stop using TPIDRPRW to hold per_cpu_offset
2021-09-07 22:00 ` [PATCH 0/7] ARM: support THREAD_INFO_IN_TASK (v3) Keith Packard
` (3 preceding siblings ...)
2021-09-07 22:00 ` [PATCH 4/7] ARM: Use hack from powerpc to get current cpu number Keith Packard
@ 2021-09-07 22:00 ` Keith Packard
2021-09-09 13:54 ` Ard Biesheuvel
2021-09-07 22:00 ` [PATCH 6/7] ARM: Use TPIDRPRW for current Keith Packard
` (2 subsequent siblings)
7 siblings, 1 reply; 36+ messages in thread
From: Keith Packard @ 2021-09-07 22:00 UTC (permalink / raw)
To: linux-kernel
Cc: Abbott Liu, Andrew Morton, Andrey Ryabinin, Anshuman Khandual,
Ard Biesheuvel, Arnd Bergmann, Bjorn Andersson,
Christoph Lameter, Dennis Zhou, Geert Uytterhoeven, Jens Axboe,
Joe Perches, Kees Cook, Keith Packard, Krzysztof Kozlowski,
Linus Walleij, linux-arm-kernel, linux-mm, Manivannan Sadhasivam,
Marc Zyngier, Masahiro Yamada, Mike Rapoport, Nathan Chancellor,
Nick Desaulniers, Nick Desaulniers, Nicolas Pitre, Russell King,
Tejun Heo, Thomas Gleixner, Uwe Kleine-König,
Valentin Schneider, Viresh Kumar, Wolfram Sang (Renesas),
YiFei Zhu
We're going to store TPIDRPRW here instead
Signed-off-by: Keith Packard <keithpac@amazon.com>
---
arch/arm/include/asm/percpu.h | 31 -------------------------------
arch/arm/kernel/setup.c | 7 -------
arch/arm/kernel/smp.c | 3 ---
3 files changed, 41 deletions(-)
diff --git a/arch/arm/include/asm/percpu.h b/arch/arm/include/asm/percpu.h
index e2fcb3cfd3de..eeafcd6a3e01 100644
--- a/arch/arm/include/asm/percpu.h
+++ b/arch/arm/include/asm/percpu.h
@@ -7,37 +7,6 @@
register unsigned long current_stack_pointer asm ("sp");
-/*
- * Same as asm-generic/percpu.h, except that we store the per cpu offset
- * in the TPIDRPRW. TPIDRPRW only exists on V6K and V7
- */
-#if defined(CONFIG_SMP) && !defined(CONFIG_CPU_V6)
-static inline void set_my_cpu_offset(unsigned long off)
-{
- /* Set TPIDRPRW */
- asm volatile("mcr p15, 0, %0, c13, c0, 4" : : "r" (off) : "memory");
-}
-
-static inline unsigned long __my_cpu_offset(void)
-{
- unsigned long off;
-
- /*
- * Read TPIDRPRW.
- * We want to allow caching the value, so avoid using volatile and
- * instead use a fake stack read to hazard against barrier().
- */
- asm("mrc p15, 0, %0, c13, c0, 4" : "=r" (off)
- : "Q" (*(const unsigned long *)current_stack_pointer));
-
- return off;
-}
-#define __my_cpu_offset __my_cpu_offset()
-#else
-#define set_my_cpu_offset(x) do {} while(0)
-
-#endif /* CONFIG_SMP */
-
#include <asm-generic/percpu.h>
#endif /* _ASM_ARM_PERCPU_H_ */
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index ca0201635fac..d0dc60afe54f 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -590,13 +590,6 @@ void __init smp_setup_processor_id(void)
for (i = 1; i < nr_cpu_ids; ++i)
cpu_logical_map(i) = i == cpu ? 0 : i;
- /*
- * clear __my_cpu_offset on boot CPU to avoid hang caused by
- * using percpu variable early, for example, lockdep will
- * access percpu variable inside lock_release
- */
- set_my_cpu_offset(0);
-
pr_info("Booting Linux on physical CPU 0x%x\n", mpidr);
}
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 5e999f1f1aea..8ccf10b34f08 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -410,8 +410,6 @@ asmlinkage void secondary_start_kernel(unsigned int cpu, struct task_struct *tas
{
struct mm_struct *mm = &init_mm;
- set_my_cpu_offset(per_cpu_offset(cpu));
-
secondary_biglittle_init();
/*
@@ -495,7 +493,6 @@ void __init smp_cpus_done(unsigned int max_cpus)
void __init smp_prepare_boot_cpu(void)
{
- set_my_cpu_offset(per_cpu_offset(smp_processor_id()));
}
void __init smp_prepare_cpus(unsigned int max_cpus)
--
2.33.0
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH 6/7] ARM: Use TPIDRPRW for current
2021-09-07 22:00 ` [PATCH 0/7] ARM: support THREAD_INFO_IN_TASK (v3) Keith Packard
` (4 preceding siblings ...)
2021-09-07 22:00 ` [PATCH 5/7] ARM: Stop using TPIDRPRW to hold per_cpu_offset Keith Packard
@ 2021-09-07 22:00 ` Keith Packard
2021-09-09 13:56 ` Ard Biesheuvel
2021-09-07 22:00 ` [PATCH 7/7] ARM: Move thread_info into task_struct (v7 only) Keith Packard
2021-09-08 7:01 ` [PATCH 0/7] ARM: support THREAD_INFO_IN_TASK (v3) Krzysztof Kozlowski
7 siblings, 1 reply; 36+ messages in thread
From: Keith Packard @ 2021-09-07 22:00 UTC (permalink / raw)
To: linux-kernel
Cc: Abbott Liu, Andrew Morton, Andrey Ryabinin, Anshuman Khandual,
Ard Biesheuvel, Arnd Bergmann, Bjorn Andersson,
Christoph Lameter, Dennis Zhou, Geert Uytterhoeven, Jens Axboe,
Joe Perches, Kees Cook, Keith Packard, Krzysztof Kozlowski,
Linus Walleij, linux-arm-kernel, linux-mm, Manivannan Sadhasivam,
Marc Zyngier, Masahiro Yamada, Mike Rapoport, Nathan Chancellor,
Nick Desaulniers, Nick Desaulniers, Nicolas Pitre, Russell King,
Tejun Heo, Thomas Gleixner, Uwe Kleine-König,
Valentin Schneider, Viresh Kumar, Wolfram Sang (Renesas),
YiFei Zhu
Store current task pointer in CPU thread ID register TPIDRPRW so that
accessing it doesn't depend on being able to locate thread_info off of
the kernel stack pointer.
Signed-off-by: Keith Packard <keithpac@amazon.com>
---
arch/arm/Kconfig | 4 +++
arch/arm/include/asm/assembler.h | 8 +++++
arch/arm/include/asm/current.h | 52 ++++++++++++++++++++++++++++++++
arch/arm/kernel/entry-armv.S | 4 +++
arch/arm/kernel/setup.c | 1 +
arch/arm/kernel/smp.c | 1 +
6 files changed, 70 insertions(+)
create mode 100644 arch/arm/include/asm/current.h
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 24804f11302d..414fe23fd5ac 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1172,6 +1172,10 @@ config SMP_ON_UP
If you don't know what to do here, say Y.
+config CURRENT_POINTER_IN_TPIDRPRW
+ def_bool y
+ depends on (CPU_V6K || CPU_V7) && !CPU_V6
+
config ARM_CPU_TOPOLOGY
bool "Support cpu topology definition"
depends on SMP && CPU_V7
diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h
index e2b1fd558bf3..ea12fe3bb589 100644
--- a/arch/arm/include/asm/assembler.h
+++ b/arch/arm/include/asm/assembler.h
@@ -209,6 +209,14 @@
mov \rd, \rd, lsl #THREAD_SIZE_ORDER + PAGE_SHIFT
.endm
+/*
+ * Set current task_info
+ * @src: Source register containing task_struct pointer
+ */
+ .macro set_current src : req
+ mcr p15, 0, \src, c13, c0, 4
+ .endm
+
/*
* Increment/decrement the preempt count.
*/
diff --git a/arch/arm/include/asm/current.h b/arch/arm/include/asm/current.h
new file mode 100644
index 000000000000..153a2ea18747
--- /dev/null
+++ b/arch/arm/include/asm/current.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright © 2021 Keith Packard <keithp@keithp.com>
+ */
+
+#ifndef _ASM_ARM_CURRENT_H_
+#define _ASM_ARM_CURRENT_H_
+
+#ifndef __ASSEMBLY__
+
+register unsigned long current_stack_pointer asm ("sp");
+
+/*
+ * Same as asm-generic/current.h, except that we store current
+ * in TPIDRPRW. TPIDRPRW only exists on V6K and V7
+ */
+#ifdef CONFIG_CURRENT_POINTER_IN_TPIDRPRW
+
+struct task_struct;
+
+static inline void set_current(struct task_struct *tsk)
+{
+ /* Set TPIDRPRW */
+ asm volatile("mcr p15, 0, %0, c13, c0, 4" : : "r" (tsk) : "memory");
+}
+
+static __always_inline struct task_struct *get_current(void)
+{
+ struct task_struct *tsk;
+
+ /*
+ * Read TPIDRPRW.
+ * We want to allow caching the value, so avoid using volatile and
+ * instead use a fake stack read to hazard against barrier().
+ */
+ asm("mrc p15, 0, %0, c13, c0, 4" : "=r" (tsk)
+ : "Q" (*(const unsigned long *)current_stack_pointer));
+
+ return tsk;
+}
+#define current get_current()
+#else
+
+#define set_current(tsk) do {} while (0)
+
+#include <asm-generic/current.h>
+
+#endif /* CONFIG_SMP */
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_ARM_CURRENT_H_ */
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 0ea8529a4872..db3947ee9c3e 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -761,6 +761,10 @@ ENTRY(__switch_to)
ldr r6, [r2, #TI_CPU_DOMAIN]
#endif
switch_tls r1, r4, r5, r3, r7
+#ifdef CONFIG_CURRENT_POINTER_IN_TPIDRPRW
+ ldr r7, [r2, #TI_TASK]
+ set_current r7
+#endif
#if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_SMP)
ldr r7, [r2, #TI_TASK]
ldr r8, =__stack_chk_guard
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index d0dc60afe54f..2fdf8c31d6c9 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -586,6 +586,7 @@ void __init smp_setup_processor_id(void)
u32 mpidr = is_smp() ? read_cpuid_mpidr() & MPIDR_HWID_BITMASK : 0;
u32 cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+ set_current(&init_task);
cpu_logical_map(0) = cpu;
for (i = 1; i < nr_cpu_ids; ++i)
cpu_logical_map(i) = i == cpu ? 0 : i;
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 8ccf10b34f08..09771916442a 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -410,6 +410,7 @@ asmlinkage void secondary_start_kernel(unsigned int cpu, struct task_struct *tas
{
struct mm_struct *mm = &init_mm;
+ set_current(task);
secondary_biglittle_init();
/*
--
2.33.0
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH 7/7] ARM: Move thread_info into task_struct (v7 only)
2021-09-07 22:00 ` [PATCH 0/7] ARM: support THREAD_INFO_IN_TASK (v3) Keith Packard
` (5 preceding siblings ...)
2021-09-07 22:00 ` [PATCH 6/7] ARM: Use TPIDRPRW for current Keith Packard
@ 2021-09-07 22:00 ` Keith Packard
2021-09-08 7:01 ` [PATCH 0/7] ARM: support THREAD_INFO_IN_TASK (v3) Krzysztof Kozlowski
7 siblings, 0 replies; 36+ messages in thread
From: Keith Packard @ 2021-09-07 22:00 UTC (permalink / raw)
To: linux-kernel
Cc: Abbott Liu, Andrew Morton, Andrey Ryabinin, Anshuman Khandual,
Ard Biesheuvel, Arnd Bergmann, Bjorn Andersson,
Christoph Lameter, Dennis Zhou, Geert Uytterhoeven, Jens Axboe,
Joe Perches, Kees Cook, Keith Packard, Krzysztof Kozlowski,
Linus Walleij, linux-arm-kernel, linux-mm, Manivannan Sadhasivam,
Marc Zyngier, Masahiro Yamada, Mike Rapoport, Nathan Chancellor,
Nick Desaulniers, Nick Desaulniers, Nicolas Pitre, Russell King,
Tejun Heo, Thomas Gleixner, Uwe Kleine-König,
Valentin Schneider, Viresh Kumar, Wolfram Sang (Renesas),
YiFei Zhu
This avoids many stack overflow attacks which modified the thread_info
structure by moving that into the task_struct as is done is almost all
other architectures.
This depends on having 'current' stored in the TPIDRPRW register as
that allows us to find thread_info and task_struct once the
thread_info cannot be located using the kernel stack pointer.
Signed-off-by: Keith Packard <keithpac@amazon.com>
---
arch/arm/Kconfig | 1 +
arch/arm/include/asm/assembler.h | 4 ++++
arch/arm/include/asm/thread_info.h | 12 +++++++++++-
arch/arm/kernel/asm-offsets.c | 4 ++++
arch/arm/kernel/entry-armv.S | 4 ++++
arch/arm/vfp/vfpmodule.c | 9 +++++++++
6 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 414fe23fd5ac..5846b4f5444b 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -128,6 +128,7 @@ config ARM
select RTC_LIB
select SET_FS
select SYS_SUPPORTS_APM_EMULATION
+ select THREAD_INFO_IN_TASK if CURRENT_POINTER_IN_TPIDRPRW
# Above selects are sorted alphabetically; please add new ones
# according to that. Thanks.
help
diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h
index ea12fe3bb589..b23d2b87184a 100644
--- a/arch/arm/include/asm/assembler.h
+++ b/arch/arm/include/asm/assembler.h
@@ -203,10 +203,14 @@
* Get current thread_info.
*/
.macro get_thread_info, rd
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+ mrc p15, 0, \rd, c13, c0, 4
+#else
ARM( mov \rd, sp, lsr #THREAD_SIZE_ORDER + PAGE_SHIFT )
THUMB( mov \rd, sp )
THUMB( lsr \rd, \rd, #THREAD_SIZE_ORDER + PAGE_SHIFT )
mov \rd, \rd, lsl #THREAD_SIZE_ORDER + PAGE_SHIFT
+#endif
.endm
/*
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h
index 70d4cbc49ae1..6b67703ca16a 100644
--- a/arch/arm/include/asm/thread_info.h
+++ b/arch/arm/include/asm/thread_info.h
@@ -55,8 +55,10 @@ struct thread_info {
unsigned long flags; /* low level flags */
int preempt_count; /* 0 => preemptable, <0 => bug */
mm_segment_t addr_limit; /* address limit */
+#ifndef CONFIG_THREAD_INFO_IN_TASK
struct task_struct *task; /* main task structure */
__u32 cpu; /* cpu */
+#endif
__u32 cpu_domain; /* cpu domain */
#ifdef CONFIG_STACKPROTECTOR_PER_TASK
unsigned long stack_canary;
@@ -75,14 +77,21 @@ struct thread_info {
#endif
};
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+#define INIT_THREAD_INFO_TASK(tsk)
+#else
+#define INIT_THREAD_INFO_TASK(tsk) .task = &tsk,
+#endif
+
#define INIT_THREAD_INFO(tsk) \
{ \
- .task = &tsk, \
+ INIT_THREAD_INFO_TASK(tsk) \
.flags = 0, \
.preempt_count = INIT_PREEMPT_COUNT, \
.addr_limit = KERNEL_DS, \
}
+#ifndef CONFIG_THREAD_INFO_IN_TASK
/*
* how to get the thread information struct from C
*/
@@ -93,6 +102,7 @@ static inline struct thread_info *current_thread_info(void)
return (struct thread_info *)
(current_stack_pointer & ~(THREAD_SIZE - 1));
}
+#endif
#define thread_saved_pc(tsk) \
((unsigned long)(task_thread_info(tsk)->cpu_context.pc))
diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c
index 70993af22d80..2a6745f7423e 100644
--- a/arch/arm/kernel/asm-offsets.c
+++ b/arch/arm/kernel/asm-offsets.c
@@ -44,8 +44,12 @@ int main(void)
DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count));
DEFINE(TI_ADDR_LIMIT, offsetof(struct thread_info, addr_limit));
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+ DEFINE(TI_CPU, offsetof(struct task_struct, cpu));
+#else
DEFINE(TI_TASK, offsetof(struct thread_info, task));
DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
+#endif
DEFINE(TI_CPU_DOMAIN, offsetof(struct thread_info, cpu_domain));
DEFINE(TI_CPU_SAVE, offsetof(struct thread_info, cpu_context));
DEFINE(TI_USED_CP, offsetof(struct thread_info, used_cp));
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index db3947ee9c3e..5ae687c8c7b8 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -762,9 +762,13 @@ ENTRY(__switch_to)
#endif
switch_tls r1, r4, r5, r3, r7
#ifdef CONFIG_CURRENT_POINTER_IN_TPIDRPRW
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+ set_current r2
+#else
ldr r7, [r2, #TI_TASK]
set_current r7
#endif
+#endif
#if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_SMP)
ldr r7, [r2, #TI_TASK]
ldr r8, =__stack_chk_guard
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index d7a3818da671..84a691da59fa 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -158,7 +158,12 @@ static void vfp_thread_copy(struct thread_info *thread)
*/
static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
{
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+ struct task_struct *tsk = v;
+ struct thread_info *thread = &tsk->thread_info;
+#else
struct thread_info *thread = v;
+#endif
u32 fpexc;
#ifdef CONFIG_SMP
unsigned int cpu;
@@ -169,7 +174,11 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
fpexc = fmrx(FPEXC);
#ifdef CONFIG_SMP
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+ cpu = tsk->cpu;
+#else
cpu = thread->cpu;
+#endif
/*
* On SMP, if VFP is enabled, save the old state in
--
2.33.0
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH 2/3] ARM: Move thread_info into task_struct (v7 only)
2021-09-07 16:05 ` Ard Biesheuvel
@ 2021-09-07 22:17 ` Keith Packard
0 siblings, 0 replies; 36+ messages in thread
From: Keith Packard @ 2021-09-07 22:17 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: Linux Kernel Mailing List, Abbott Liu, Alexander Sverdlin,
Andrew Morton, Anshuman Khandual, Arnd Bergmann, Bjorn Andersson,
Florian Fainelli, Geert Uytterhoeven, Hartley Sweeten,
Jens Axboe, Jian Cai, Joe Perches, Kees Cook,
Krzysztof Kozlowski, Linus Walleij, Linux ARM,
Manivannan Sadhasivam, Marc Zyngier, Masahiro Yamada,
Miguel Ojeda, Mike Rapoport, Nathan Chancellor, Nick Desaulniers,
Nicolas Pitre, Rob Herring, Russell King, Thomas Gleixner,
Uwe Kleine-König, Valentin Schneider, Viresh Kumar,
Wolfram Sang (Renesas),
YiFei Zhu
[-- Attachment #1: Type: text/plain, Size: 1446 bytes --]
Ard Biesheuvel <ardb@kernel.org> writes:
> That is still a bit tricky, given that you now have to swap out the
> per-CPU offset when you migrate a task, and the generic code is not
> really set up for that.
Yeah, I decided to just leverage as much generic code as possible and
re-purposed the TPIDRPRW register for 'current', leaving the
per_cpu_offset data in memory. That makes the patch series pretty
compact, with a bunch of restructuring changes followed by fairly short
functional changes.
> I had a stab at this myself today (long boring day with no Internet connection).
>
> https://android-kvm.googlesource.com/linux/+log/refs/heads/ardb/arm32-ti-in-task
>
> It resembles your code in some places - I suppose we went on the same
> journey in a sense :-) We'll fix up the credits before this gets
> resubmitted.
This does look great, and preserves the optimization of keeping the
per_cpu_offset value in a register.
With the series I posted, getting the per_cpu_offset value requires
fetching the cpu value from task_struct and then using that to index the
per_cpu_offset arrray. I don't have a good feeling of how important this
optimization is? We could stick the per_cpu_offset value into
thread_info to avoid one fetch?
> Fixing the per-task stack protector plugin on top of these changes
> should be trivial but I need a coffee first.
I haven't even looked at that step yet :-)
--
-keith
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH 0/7] ARM: support THREAD_INFO_IN_TASK (v3)
2021-09-07 22:00 ` [PATCH 0/7] ARM: support THREAD_INFO_IN_TASK (v3) Keith Packard
` (6 preceding siblings ...)
2021-09-07 22:00 ` [PATCH 7/7] ARM: Move thread_info into task_struct (v7 only) Keith Packard
@ 2021-09-08 7:01 ` Krzysztof Kozlowski
2021-09-08 7:47 ` Ard Biesheuvel
7 siblings, 1 reply; 36+ messages in thread
From: Krzysztof Kozlowski @ 2021-09-08 7:01 UTC (permalink / raw)
To: Keith Packard, linux-kernel
Cc: Abbott Liu, Andrew Morton, Andrey Ryabinin, Anshuman Khandual,
Ard Biesheuvel, Arnd Bergmann, Bjorn Andersson,
Christoph Lameter, Dennis Zhou, Geert Uytterhoeven, Jens Axboe,
Joe Perches, Kees Cook, Linus Walleij, linux-arm-kernel,
linux-mm, Manivannan Sadhasivam, Marc Zyngier, Masahiro Yamada,
Mike Rapoport, Nathan Chancellor, Nick Desaulniers,
Nick Desaulniers, Nicolas Pitre, Russell King, Tejun Heo,
Thomas Gleixner, Uwe Kleine-König, Valentin Schneider,
Viresh Kumar, Wolfram Sang (Renesas),
YiFei Zhu
On 08/09/2021 00:00, Keith Packard wrote:
> Placing thread_info in the kernel stack leaves it vulnerable to stack
> overflow attacks. This short series addresses that by using the
> existing THREAD_INFO_IN_TASK infrastructure.
>
> This is the third version of this series, in this version the changes
> are restricted to hardware which provides the TPIDRPRW register. This
> register is repurposed from holding the per_cpu_offset value to
> holding the 'current' value as that allows fetching this value
> atomically so that it can be used in a preemptable context.
>
> The series is broken into seven pieces:
>
> 1) Change the secondary_start_kernel API to receive the cpu
> number. This avoids needing to be able to find this value independently in
> future patches.
>
> 2) Change the secondary_start_kernel API to also receive the 'task'
> value. Passing the value to this function also avoids needing to
> be able to discover it independently.
>
> 3) A cleanup which avoids assuming that THREAD_INFO_IN_TASK is not set.
>
> 4) A hack, borrowed from the powerpc arch, which allows locating the 'cpu'
> field in either thread_info or task_struct, without requiring linux/sched.h
> to be included in asm/smp.h
>
> 5) Disable the optimization storing per_cpu_offset in TPIDRPRW. This leaves
> the register free to hold 'current' instead.
>
> 6) Use TPIDRPRW for 'current'. This is enabled for either CPU_V6K or CPU_V7,
> but not if CPU_V6 is also enabled.
>
> 7) Enable THREAD_INFO_IN_TASK whenever TPIDRPRW is used to hold 'current'.
Hi,
Thanks for your patches. This seems to be a v3 but the patches are not
marked with it. Use "-v3" in format-patch to get it right.
The email here also lacks diffstat which is useful, for example to check
whether any maintainer's relevant files are touched here. You can get it
with "--cover-letter".
In total the command should look like:
git format-patch --cover-letter -v3 -7 HEAD
Of course you can use any other tools to achieve the same result but as
of now - result is not the same.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH 4/7] ARM: Use hack from powerpc to get current cpu number
2021-09-07 22:00 ` [PATCH 4/7] ARM: Use hack from powerpc to get current cpu number Keith Packard
@ 2021-09-08 7:45 ` Ard Biesheuvel
0 siblings, 0 replies; 36+ messages in thread
From: Ard Biesheuvel @ 2021-09-08 7:45 UTC (permalink / raw)
To: Keith Packard
Cc: Linux Kernel Mailing List, Abbott Liu, Andrew Morton,
Andrey Ryabinin, Anshuman Khandual, Arnd Bergmann,
Bjorn Andersson, Christoph Lameter, Dennis Zhou,
Geert Uytterhoeven, Jens Axboe, Joe Perches, Kees Cook,
Krzysztof Kozlowski, Linus Walleij, Linux ARM,
Linux Memory Management List, Manivannan Sadhasivam,
Marc Zyngier, Masahiro Yamada, Mike Rapoport, Nathan Chancellor,
Nick Desaulniers, Nick Desaulniers, Nicolas Pitre, Russell King,
Tejun Heo, Thomas Gleixner, Uwe Kleine-König,
Valentin Schneider, Viresh Kumar, Wolfram Sang (Renesas),
YiFei Zhu
On Wed, 8 Sept 2021 at 00:00, Keith Packard <keithpac@amazon.com> wrote:
>
> When we enable THREAD_INFO_IN_TASK, the cpu number will disappear from
> thread_info and reappear in task_struct. As we cannot include
> linux/sched.h in asm/smp.h, there's no way to use that struct type in
> the raw_smp_processor_id macro. Instead, a hack from the powerpc code
> is used. This pulls the TI_CPU offset out of asm-offsets.h and uses
> that to find the cpu value.
>
> Signed-off-by: Keith Packard <keithpac@amazon.com>
> ---
> arch/arm/Makefile | 8 ++++++++
> arch/arm/include/asm/smp.h | 18 +++++++++++++++++-
> 2 files changed, 25 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm/Makefile b/arch/arm/Makefile
> index 415c3514573a..6752995d2914 100644
> --- a/arch/arm/Makefile
> +++ b/arch/arm/Makefile
> @@ -284,6 +284,14 @@ stack_protector_prepare: prepare0
> $(eval GCC_PLUGINS_CFLAGS += $(SSP_PLUGIN_CFLAGS))
> endif
>
> +ifdef CONFIG_SMP
> +prepare: task_cpu_prepare
> +
> +PHONY += task_cpu_prepare
> +task_cpu_prepare: prepare0
> + $(eval KBUILD_CFLAGS += -D_TI_CPU=$(shell awk '{if ($$2 == "TI_CPU") print $$3;}' include/generated/asm-offsets.h))
> +endif
> +
> all: $(notdir $(KBUILD_IMAGE))
>
>
> diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
> index d43b64635d77..f77ba3753bc4 100644
> --- a/arch/arm/include/asm/smp.h
> +++ b/arch/arm/include/asm/smp.h
> @@ -15,7 +15,23 @@
> # error "<asm/smp.h> included in non-SMP build"
> #endif
>
> -#define raw_smp_processor_id() (current_thread_info()->cpu)
> +/*
> + * This is particularly ugly: it appears we can't actually get the
> + * definition of task_struct here, but we need access to the CPU this
> + * task is running on, which is stored in task_struct when
> + * THREAD_INFO_IN_TASK is set. Instead of using task_struct we're
> + * using TI_CPU which is extracted from asm-offsets.h by kbuild to get
> + * the current processor ID.
> + *
> + * This also needs to be safeguarded when building asm-offsets.s
> + * because at that time TI_CPU is not defined yet.
> + */
> +#ifndef _TI_CPU
> +#define raw_smp_processor_id() (0)
> +#else
> +#define raw_smp_processor_id() \
> + (*(unsigned int *)((void *)current_thread_info() + _TI_CPU))
> +#endif
>
> struct seq_file;
>
As I stated before, I would really like to avoid using this hack - I
don't think we need to.
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH 0/7] ARM: support THREAD_INFO_IN_TASK (v3)
2021-09-08 7:01 ` [PATCH 0/7] ARM: support THREAD_INFO_IN_TASK (v3) Krzysztof Kozlowski
@ 2021-09-08 7:47 ` Ard Biesheuvel
2021-09-08 7:50 ` Geert Uytterhoeven
0 siblings, 1 reply; 36+ messages in thread
From: Ard Biesheuvel @ 2021-09-08 7:47 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Keith Packard, Linux Kernel Mailing List, Abbott Liu,
Andrew Morton, Andrey Ryabinin, Anshuman Khandual, Arnd Bergmann,
Bjorn Andersson, Christoph Lameter, Dennis Zhou,
Geert Uytterhoeven, Jens Axboe, Joe Perches, Kees Cook,
Linus Walleij, Linux ARM, Linux Memory Management List,
Manivannan Sadhasivam, Marc Zyngier, Masahiro Yamada,
Mike Rapoport, Nathan Chancellor, Nick Desaulniers,
Nick Desaulniers, Nicolas Pitre, Russell King, Tejun Heo,
Thomas Gleixner, Uwe Kleine-König, Valentin Schneider,
Viresh Kumar, Wolfram Sang (Renesas),
YiFei Zhu
On Wed, 8 Sept 2021 at 09:01, Krzysztof Kozlowski
<krzysztof.kozlowski@canonical.com> wrote:
>
> On 08/09/2021 00:00, Keith Packard wrote:
> > Placing thread_info in the kernel stack leaves it vulnerable to stack
> > overflow attacks. This short series addresses that by using the
> > existing THREAD_INFO_IN_TASK infrastructure.
> >
> > This is the third version of this series, in this version the changes
> > are restricted to hardware which provides the TPIDRPRW register. This
> > register is repurposed from holding the per_cpu_offset value to
> > holding the 'current' value as that allows fetching this value
> > atomically so that it can be used in a preemptable context.
> >
> > The series is broken into seven pieces:
> >
> > 1) Change the secondary_start_kernel API to receive the cpu
> > number. This avoids needing to be able to find this value independently in
> > future patches.
> >
> > 2) Change the secondary_start_kernel API to also receive the 'task'
> > value. Passing the value to this function also avoids needing to
> > be able to discover it independently.
> >
> > 3) A cleanup which avoids assuming that THREAD_INFO_IN_TASK is not set.
> >
> > 4) A hack, borrowed from the powerpc arch, which allows locating the 'cpu'
> > field in either thread_info or task_struct, without requiring linux/sched.h
> > to be included in asm/smp.h
> >
> > 5) Disable the optimization storing per_cpu_offset in TPIDRPRW. This leaves
> > the register free to hold 'current' instead.
> >
> > 6) Use TPIDRPRW for 'current'. This is enabled for either CPU_V6K or CPU_V7,
> > but not if CPU_V6 is also enabled.
> >
> > 7) Enable THREAD_INFO_IN_TASK whenever TPIDRPRW is used to hold 'current'.
>
> Hi,
>
> Thanks for your patches. This seems to be a v3 but the patches are not
> marked with it. Use "-v3" in format-patch to get it right.
>
> The email here also lacks diffstat which is useful, for example to check
> whether any maintainer's relevant files are touched here. You can get it
> with "--cover-letter".
>
> In total the command should look like:
> git format-patch --cover-letter -v3 -7 HEAD
>
> Of course you can use any other tools to achieve the same result but as
> of now - result is not the same.
>
Also, this ended up in my GMail spam folder, likely due to some
antispam ID header being set incorrectly?
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH 0/7] ARM: support THREAD_INFO_IN_TASK (v3)
2021-09-08 7:47 ` Ard Biesheuvel
@ 2021-09-08 7:50 ` Geert Uytterhoeven
0 siblings, 0 replies; 36+ messages in thread
From: Geert Uytterhoeven @ 2021-09-08 7:50 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: Krzysztof Kozlowski, Keith Packard, Linux Kernel Mailing List,
Abbott Liu, Andrew Morton, Andrey Ryabinin, Anshuman Khandual,
Arnd Bergmann, Bjorn Andersson, Christoph Lameter, Dennis Zhou,
Geert Uytterhoeven, Jens Axboe, Joe Perches, Kees Cook,
Linus Walleij, Linux ARM, Linux Memory Management List,
Manivannan Sadhasivam, Marc Zyngier, Masahiro Yamada,
Mike Rapoport, Nathan Chancellor, Nick Desaulniers,
Nick Desaulniers, Nicolas Pitre, Russell King, Tejun Heo,
Thomas Gleixner, Uwe Kleine-König, Valentin Schneider,
Viresh Kumar, Wolfram Sang (Renesas),
YiFei Zhu
Hi Ard,
On Wed, Sep 8, 2021 at 9:47 AM Ard Biesheuvel <ardb@kernel.org> wrote:
> Also, this ended up in my GMail spam folder, likely due to some
> antispam ID header being set incorrectly?
I have a rule to never mark as spam email with "patch" in the subject.
So far only one false positive in all these years ;-)
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH 5/7] ARM: Stop using TPIDRPRW to hold per_cpu_offset
2021-09-07 22:00 ` [PATCH 5/7] ARM: Stop using TPIDRPRW to hold per_cpu_offset Keith Packard
@ 2021-09-09 13:54 ` Ard Biesheuvel
0 siblings, 0 replies; 36+ messages in thread
From: Ard Biesheuvel @ 2021-09-09 13:54 UTC (permalink / raw)
To: Keith Packard
Cc: Linux Kernel Mailing List, Abbott Liu, Andrew Morton,
Andrey Ryabinin, Anshuman Khandual, Arnd Bergmann,
Bjorn Andersson, Christoph Lameter, Dennis Zhou,
Geert Uytterhoeven, Jens Axboe, Joe Perches, Kees Cook,
Krzysztof Kozlowski, Linus Walleij, Linux ARM,
Linux Memory Management List, Manivannan Sadhasivam,
Marc Zyngier, Masahiro Yamada, Mike Rapoport, Nathan Chancellor,
Nick Desaulniers, Nick Desaulniers, Nicolas Pitre, Russell King,
Tejun Heo, Thomas Gleixner, Uwe Kleine-König,
Valentin Schneider, Viresh Kumar, Wolfram Sang (Renesas),
YiFei Zhu
On Wed, 8 Sept 2021 at 00:00, Keith Packard <keithpac@amazon.com> wrote:
>
> We're going to store TPIDRPRW here instead
>
?
> Signed-off-by: Keith Packard <keithpac@amazon.com>
I'd much prefer to keep using TPIDIRPRW for the per-CPU offsets, and
use the user space TLS register for current.
There are several reasons for this:
- arm64 does the same - as someone who still cares about ARM while
many have moved on to arm64 or RISC-V, I am still trying to maintain
parity between ARM and arm64 where possible.
- efficiency: loading the per-CPU offset using a CPU id stored in
memory, which is then used to index the per-CPU offsets array in
memory adds two additional loads to every load/store of a per-CPU
variable
- 'current' usually does not change value under the code's feet,
whereas per-CPU offsets might change at any time. Given the fact that
the CPU offset load is visible to the compiler as a memory access, I
suppose this should be safe, but I would still prefer per-CPU access
to avoid going via current if possible.
> ---
> arch/arm/include/asm/percpu.h | 31 -------------------------------
> arch/arm/kernel/setup.c | 7 -------
> arch/arm/kernel/smp.c | 3 ---
> 3 files changed, 41 deletions(-)
>
> diff --git a/arch/arm/include/asm/percpu.h b/arch/arm/include/asm/percpu.h
> index e2fcb3cfd3de..eeafcd6a3e01 100644
> --- a/arch/arm/include/asm/percpu.h
> +++ b/arch/arm/include/asm/percpu.h
> @@ -7,37 +7,6 @@
>
> register unsigned long current_stack_pointer asm ("sp");
>
> -/*
> - * Same as asm-generic/percpu.h, except that we store the per cpu offset
> - * in the TPIDRPRW. TPIDRPRW only exists on V6K and V7
> - */
> -#if defined(CONFIG_SMP) && !defined(CONFIG_CPU_V6)
> -static inline void set_my_cpu_offset(unsigned long off)
> -{
> - /* Set TPIDRPRW */
> - asm volatile("mcr p15, 0, %0, c13, c0, 4" : : "r" (off) : "memory");
> -}
> -
> -static inline unsigned long __my_cpu_offset(void)
> -{
> - unsigned long off;
> -
> - /*
> - * Read TPIDRPRW.
> - * We want to allow caching the value, so avoid using volatile and
> - * instead use a fake stack read to hazard against barrier().
> - */
> - asm("mrc p15, 0, %0, c13, c0, 4" : "=r" (off)
> - : "Q" (*(const unsigned long *)current_stack_pointer));
> -
> - return off;
> -}
> -#define __my_cpu_offset __my_cpu_offset()
> -#else
> -#define set_my_cpu_offset(x) do {} while(0)
> -
> -#endif /* CONFIG_SMP */
> -
> #include <asm-generic/percpu.h>
>
> #endif /* _ASM_ARM_PERCPU_H_ */
> diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
> index ca0201635fac..d0dc60afe54f 100644
> --- a/arch/arm/kernel/setup.c
> +++ b/arch/arm/kernel/setup.c
> @@ -590,13 +590,6 @@ void __init smp_setup_processor_id(void)
> for (i = 1; i < nr_cpu_ids; ++i)
> cpu_logical_map(i) = i == cpu ? 0 : i;
>
> - /*
> - * clear __my_cpu_offset on boot CPU to avoid hang caused by
> - * using percpu variable early, for example, lockdep will
> - * access percpu variable inside lock_release
> - */
> - set_my_cpu_offset(0);
> -
> pr_info("Booting Linux on physical CPU 0x%x\n", mpidr);
> }
>
> diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
> index 5e999f1f1aea..8ccf10b34f08 100644
> --- a/arch/arm/kernel/smp.c
> +++ b/arch/arm/kernel/smp.c
> @@ -410,8 +410,6 @@ asmlinkage void secondary_start_kernel(unsigned int cpu, struct task_struct *tas
> {
> struct mm_struct *mm = &init_mm;
>
> - set_my_cpu_offset(per_cpu_offset(cpu));
> -
> secondary_biglittle_init();
>
> /*
> @@ -495,7 +493,6 @@ void __init smp_cpus_done(unsigned int max_cpus)
>
> void __init smp_prepare_boot_cpu(void)
> {
> - set_my_cpu_offset(per_cpu_offset(smp_processor_id()));
> }
>
> void __init smp_prepare_cpus(unsigned int max_cpus)
> --
> 2.33.0
>
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH 6/7] ARM: Use TPIDRPRW for current
2021-09-07 22:00 ` [PATCH 6/7] ARM: Use TPIDRPRW for current Keith Packard
@ 2021-09-09 13:56 ` Ard Biesheuvel
0 siblings, 0 replies; 36+ messages in thread
From: Ard Biesheuvel @ 2021-09-09 13:56 UTC (permalink / raw)
To: Keith Packard
Cc: Linux Kernel Mailing List, Abbott Liu, Andrew Morton,
Andrey Ryabinin, Anshuman Khandual, Arnd Bergmann,
Bjorn Andersson, Christoph Lameter, Dennis Zhou,
Geert Uytterhoeven, Jens Axboe, Joe Perches, Kees Cook,
Krzysztof Kozlowski, Linus Walleij, Linux ARM,
Linux Memory Management List, Manivannan Sadhasivam,
Marc Zyngier, Masahiro Yamada, Mike Rapoport, Nathan Chancellor,
Nick Desaulniers, Nick Desaulniers, Nicolas Pitre, Russell King,
Tejun Heo, Thomas Gleixner, Uwe Kleine-König,
Valentin Schneider, Viresh Kumar, Wolfram Sang (Renesas),
YiFei Zhu
On Wed, 8 Sept 2021 at 00:00, Keith Packard <keithpac@amazon.com> wrote:
>
> Store current task pointer in CPU thread ID register TPIDRPRW so that
> accessing it doesn't depend on being able to locate thread_info off of
> the kernel stack pointer.
>
> Signed-off-by: Keith Packard <keithpac@amazon.com>
> ---
> arch/arm/Kconfig | 4 +++
> arch/arm/include/asm/assembler.h | 8 +++++
> arch/arm/include/asm/current.h | 52 ++++++++++++++++++++++++++++++++
> arch/arm/kernel/entry-armv.S | 4 +++
> arch/arm/kernel/setup.c | 1 +
> arch/arm/kernel/smp.c | 1 +
> 6 files changed, 70 insertions(+)
> create mode 100644 arch/arm/include/asm/current.h
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 24804f11302d..414fe23fd5ac 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -1172,6 +1172,10 @@ config SMP_ON_UP
>
> If you don't know what to do here, say Y.
>
> +config CURRENT_POINTER_IN_TPIDRPRW
> + def_bool y
> + depends on (CPU_V6K || CPU_V7) && !CPU_V6
> +
> config ARM_CPU_TOPOLOGY
> bool "Support cpu topology definition"
> depends on SMP && CPU_V7
> diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h
> index e2b1fd558bf3..ea12fe3bb589 100644
> --- a/arch/arm/include/asm/assembler.h
> +++ b/arch/arm/include/asm/assembler.h
> @@ -209,6 +209,14 @@
> mov \rd, \rd, lsl #THREAD_SIZE_ORDER + PAGE_SHIFT
> .endm
>
> +/*
> + * Set current task_info
> + * @src: Source register containing task_struct pointer
> + */
> + .macro set_current src : req
> + mcr p15, 0, \src, c13, c0, 4
> + .endm
> +
> /*
> * Increment/decrement the preempt count.
> */
> diff --git a/arch/arm/include/asm/current.h b/arch/arm/include/asm/current.h
> new file mode 100644
> index 000000000000..153a2ea18747
> --- /dev/null
> +++ b/arch/arm/include/asm/current.h
> @@ -0,0 +1,52 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright © 2021 Keith Packard <keithp@keithp.com>
> + */
> +
> +#ifndef _ASM_ARM_CURRENT_H_
> +#define _ASM_ARM_CURRENT_H_
> +
> +#ifndef __ASSEMBLY__
> +
> +register unsigned long current_stack_pointer asm ("sp");
> +
> +/*
> + * Same as asm-generic/current.h, except that we store current
> + * in TPIDRPRW. TPIDRPRW only exists on V6K and V7
> + */
> +#ifdef CONFIG_CURRENT_POINTER_IN_TPIDRPRW
> +
> +struct task_struct;
> +
> +static inline void set_current(struct task_struct *tsk)
> +{
> + /* Set TPIDRPRW */
> + asm volatile("mcr p15, 0, %0, c13, c0, 4" : : "r" (tsk) : "memory");
> +}
> +
> +static __always_inline struct task_struct *get_current(void)
> +{
> + struct task_struct *tsk;
> +
> + /*
> + * Read TPIDRPRW.
> + * We want to allow caching the value, so avoid using volatile and
> + * instead use a fake stack read to hazard against barrier().
> + */
> + asm("mrc p15, 0, %0, c13, c0, 4" : "=r" (tsk)
> + : "Q" (*(const unsigned long *)current_stack_pointer));
> +
> + return tsk;
> +}
> +#define current get_current()
> +#else
> +
> +#define set_current(tsk) do {} while (0)
> +
> +#include <asm-generic/current.h>
> +
> +#endif /* CONFIG_SMP */
> +
> +#endif /* __ASSEMBLY__ */
> +
> +#endif /* _ASM_ARM_CURRENT_H_ */
> diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
> index 0ea8529a4872..db3947ee9c3e 100644
> --- a/arch/arm/kernel/entry-armv.S
> +++ b/arch/arm/kernel/entry-armv.S
> @@ -761,6 +761,10 @@ ENTRY(__switch_to)
> ldr r6, [r2, #TI_CPU_DOMAIN]
> #endif
> switch_tls r1, r4, r5, r3, r7
> +#ifdef CONFIG_CURRENT_POINTER_IN_TPIDRPRW
> + ldr r7, [r2, #TI_TASK]
> + set_current r7
> +#endif
This is too early: this will cause the thread notification hooks to be
called with current pointing to the new task instead of the old one.
> #if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_SMP)
> ldr r7, [r2, #TI_TASK]
> ldr r8, =__stack_chk_guard
> diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
> index d0dc60afe54f..2fdf8c31d6c9 100644
> --- a/arch/arm/kernel/setup.c
> +++ b/arch/arm/kernel/setup.c
> @@ -586,6 +586,7 @@ void __init smp_setup_processor_id(void)
> u32 mpidr = is_smp() ? read_cpuid_mpidr() & MPIDR_HWID_BITMASK : 0;
> u32 cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
>
> + set_current(&init_task);
> cpu_logical_map(0) = cpu;
> for (i = 1; i < nr_cpu_ids; ++i)
> cpu_logical_map(i) = i == cpu ? 0 : i;
> diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
> index 8ccf10b34f08..09771916442a 100644
> --- a/arch/arm/kernel/smp.c
> +++ b/arch/arm/kernel/smp.c
> @@ -410,6 +410,7 @@ asmlinkage void secondary_start_kernel(unsigned int cpu, struct task_struct *tas
> {
> struct mm_struct *mm = &init_mm;
>
> + set_current(task);
> secondary_biglittle_init();
>
> /*
> --
> 2.33.0
>
^ permalink raw reply [flat|nested] 36+ messages in thread
end of thread, other threads:[~2021-09-09 13:58 UTC | newest]
Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-02 15:54 [PATCH 0/2]: ARM: Enable THREAD_INFO_IN_TASK Keith Packard
2021-09-02 15:54 ` [PATCH 1/2] ARM: Add per-cpu variable holding cpu number Keith Packard
2021-09-02 15:54 ` [PATCH 2/2] ARM: Move thread_info into task_struct Keith Packard
2021-09-02 16:07 ` [PATCH 0/2]: ARM: Enable THREAD_INFO_IN_TASK Kees Cook
2021-09-02 16:18 ` Ard Biesheuvel
2021-09-02 17:37 ` Kees Cook
2021-09-02 16:54 ` Russell King (Oracle)
2021-09-02 16:53 ` Russell King (Oracle)
2021-09-02 17:35 ` Kees Cook
2021-09-02 17:58 ` Keith Packard
2021-09-04 6:09 ` [PATCH 0/2] ARM: support THREAD_INFO_IN_TASK (v7 only) (v2) Keith Packard
2021-09-04 6:09 ` [PATCH 1/3] ARM: Pass cpu number to secondary_start_kernel Keith Packard
2021-09-05 20:25 ` Ard Biesheuvel
2021-09-04 6:09 ` [PATCH 2/3] ARM: Move thread_info into task_struct (v7 only) Keith Packard
2021-09-05 20:56 ` Ard Biesheuvel
2021-09-06 6:14 ` Keith Packard
2021-09-06 7:49 ` Ard Biesheuvel
2021-09-07 15:24 ` Keith Packard
2021-09-07 16:05 ` Ard Biesheuvel
2021-09-07 22:17 ` Keith Packard
2021-09-06 6:20 ` Keith Packard
2021-09-04 6:09 ` [PATCH 3/3] ARM: Add per-cpu variable cpu_number " Keith Packard
2021-09-07 22:00 ` [PATCH 0/7] ARM: support THREAD_INFO_IN_TASK (v3) Keith Packard
2021-09-07 22:00 ` [PATCH 1/7] ARM: Pass cpu number to secondary_start_kernel Keith Packard
2021-09-07 22:00 ` [PATCH 2/7] ARM: Pass task " Keith Packard
2021-09-07 22:00 ` [PATCH 3/7] ARM: Use smp_processor_id() in vfp_pm_suspend instead of ti->cpu Keith Packard
2021-09-07 22:00 ` [PATCH 4/7] ARM: Use hack from powerpc to get current cpu number Keith Packard
2021-09-08 7:45 ` Ard Biesheuvel
2021-09-07 22:00 ` [PATCH 5/7] ARM: Stop using TPIDRPRW to hold per_cpu_offset Keith Packard
2021-09-09 13:54 ` Ard Biesheuvel
2021-09-07 22:00 ` [PATCH 6/7] ARM: Use TPIDRPRW for current Keith Packard
2021-09-09 13:56 ` Ard Biesheuvel
2021-09-07 22:00 ` [PATCH 7/7] ARM: Move thread_info into task_struct (v7 only) Keith Packard
2021-09-08 7:01 ` [PATCH 0/7] ARM: support THREAD_INFO_IN_TASK (v3) Krzysztof Kozlowski
2021-09-08 7:47 ` Ard Biesheuvel
2021-09-08 7:50 ` Geert Uytterhoeven
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).