BPF List
 help / color / mirror / Atom feed
* [RFC PATCH 0/3] Move thread_info into task_struct for LoongArch
@ 2026-04-28  7:20 Tiezhu Yang
  2026-04-28  7:20 ` [RFC PATCH 1/3] LoongArch: Implement CONFIG_THREAD_INFO_IN_TASK Tiezhu Yang
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Tiezhu Yang @ 2026-04-28  7:20 UTC (permalink / raw)
  To: loongarch, bpf, linux-arch, linux-kernel

This is still an RFC, based on 7.1-rc1. I will perform more tests locally.
Looking forward to more review comments and test results.

Tiezhu Yang (3):
  LoongArch: Implement CONFIG_THREAD_INFO_IN_TASK
  LoongArch: BPF: Inline bpf_get_current_task{_btf}() helpers
  LoongArch: BPF: Inline bpf_get_smp_processor_id() helper

 arch/loongarch/Kconfig                   |  1 +
 arch/loongarch/include/asm/current.h     | 22 ++++++++++++
 arch/loongarch/include/asm/processor.h   | 44 +++---------------------
 arch/loongarch/include/asm/ptrace.h      |  6 ----
 arch/loongarch/include/asm/smp.h         |  3 +-
 arch/loongarch/include/asm/stackframe.h  |  9 +++--
 arch/loongarch/include/asm/switch_to.h   | 15 ++++++--
 arch/loongarch/include/asm/thread_info.h | 13 +------
 arch/loongarch/kernel/asm-offsets.c      |  7 ++--
 arch/loongarch/kernel/entry.S            |  7 ++--
 arch/loongarch/kernel/head.S             | 18 ++++++----
 arch/loongarch/kernel/process.c          |  6 ++++
 arch/loongarch/kernel/relocate.c         |  2 +-
 arch/loongarch/kernel/setup.c            |  3 ++
 arch/loongarch/kernel/smp.c              |  8 +++--
 arch/loongarch/kernel/switch.S           |  9 ++---
 arch/loongarch/net/bpf_jit.c             | 26 ++++++++++++++
 17 files changed, 115 insertions(+), 84 deletions(-)
 create mode 100644 arch/loongarch/include/asm/current.h

-- 
2.42.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [RFC PATCH 1/3] LoongArch: Implement CONFIG_THREAD_INFO_IN_TASK
  2026-04-28  7:20 [RFC PATCH 0/3] Move thread_info into task_struct for LoongArch Tiezhu Yang
@ 2026-04-28  7:20 ` Tiezhu Yang
  2026-04-28 20:38   ` sashiko-bot
  2026-04-28  7:20 ` [RFC PATCH 2/3] LoongArch: BPF: Inline bpf_get_current_task{_btf}() helpers Tiezhu Yang
  2026-04-28  7:20 ` [RFC PATCH 3/3] LoongArch: BPF: Inline bpf_get_smp_processor_id() helper Tiezhu Yang
  2 siblings, 1 reply; 6+ messages in thread
From: Tiezhu Yang @ 2026-04-28  7:20 UTC (permalink / raw)
  To: loongarch, bpf, linux-arch, linux-kernel

Like other architectures such as x86, arm64, riscv, powerpc and s390,
select THREAD_INFO_IN_TASK for LoongArch to move thread_info off the
stack into task_struct. This follows modern kernel standards and also
makes the system more secure.

With this patch, thread_info is included in task_struct at an offset
of 0 instead of being placed at the bottom of the kernel stack. Thus,
the $tp register points to both thread_info and task_struct.

To support this, introduce a per-CPU variable __entry_task to store
the pointer to the current task_struct. This decouples the recovery
of the $tp register from the stack pointer during exception entry.
Relying on SP for task identification is insecure since the SP can be
controlled or corrupted by userspace.

Then initialize __entry_task for both the primary and secondary CPUs
during arch-specific setup and SMP boot paths, modify SAVE_SOME and
handle_syscall to restore the $tp register from __entry_task, and use
la_abs absolute addressing for __entry_task access in assembly to
bypass relocation limits within exception handling sections. Also,
add entry_task_switch() to update __entry_task during switch_to().

Additionally, add reg02 ($tp) to thread_struct and initialize it in
both INIT_THREAD and copy_thread() to ensure that the "current" task
pointer is correctly set up for the initial idle task and all future
child processes. While __switch_to() directly updates $tp from a1 for
efficiency, storing it in thread_struct ensures correct restoration
for new processes and in non-standard switch paths.

Furthermore, initialize reg03 ($sp) in INIT_THREAD to set the initial
kernel stack pointer for the idle task. This ensures the idle task has
a valid stack to use when the system first starts or whenever it is
switched back to.

Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
---
 arch/loongarch/Kconfig                   |  1 +
 arch/loongarch/include/asm/current.h     | 22 ++++++++++++
 arch/loongarch/include/asm/processor.h   | 44 +++---------------------
 arch/loongarch/include/asm/ptrace.h      |  6 ----
 arch/loongarch/include/asm/smp.h         |  3 +-
 arch/loongarch/include/asm/stackframe.h  |  9 +++--
 arch/loongarch/include/asm/switch_to.h   | 15 ++++++--
 arch/loongarch/include/asm/thread_info.h | 13 +------
 arch/loongarch/kernel/asm-offsets.c      |  7 ++--
 arch/loongarch/kernel/entry.S            |  7 ++--
 arch/loongarch/kernel/head.S             | 18 ++++++----
 arch/loongarch/kernel/process.c          |  6 ++++
 arch/loongarch/kernel/relocate.c         |  2 +-
 arch/loongarch/kernel/setup.c            |  3 ++
 arch/loongarch/kernel/smp.c              |  8 +++--
 arch/loongarch/kernel/switch.S           |  9 ++---
 16 files changed, 89 insertions(+), 84 deletions(-)
 create mode 100644 arch/loongarch/include/asm/current.h

diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
index 3b042dbb2c41..ea29d5d17588 100644
--- a/arch/loongarch/Kconfig
+++ b/arch/loongarch/Kconfig
@@ -210,6 +210,7 @@ config LOONGARCH
 	select SYSCTL_ARCH_UNALIGN_NO_WARN
 	select SYSCTL_EXCEPTION_TRACE
 	select SWIOTLB if 64BIT
+	select THREAD_INFO_IN_TASK
 	select TRACE_IRQFLAGS_SUPPORT
 	select USE_PERCPU_NUMA_NODE_ID
 	select USER_STACKTRACE_SUPPORT
diff --git a/arch/loongarch/include/asm/current.h b/arch/loongarch/include/asm/current.h
new file mode 100644
index 000000000000..c03cf0abb863
--- /dev/null
+++ b/arch/loongarch/include/asm/current.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_LOONGARCH_CURRENT_H
+#define __ASM_LOONGARCH_CURRENT_H
+
+#include <linux/compiler.h>
+
+#ifndef __ASSEMBLER__
+
+struct task_struct;
+
+register struct task_struct *current_thread_pointer __asm__("$tp");
+
+static __always_inline struct task_struct *get_current(void)
+{
+	return current_thread_pointer;
+}
+
+#define current get_current()
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* __ASM_LOONGARCH_CURRENT_H */
diff --git a/arch/loongarch/include/asm/processor.h b/arch/loongarch/include/asm/processor.h
index ce8b953f8c79..df927a4318cc 100644
--- a/arch/loongarch/include/asm/processor.h
+++ b/arch/loongarch/include/asm/processor.h
@@ -109,7 +109,7 @@ struct loongarch_vdso_info;
  */
 struct thread_struct {
 	/* Main processor registers. */
-	unsigned long reg01, reg03, reg22; /* ra sp fp */
+	unsigned long reg01, reg02, reg03, reg22; /* ra tp sp fp */
 	unsigned long reg23, reg24, reg25, reg26; /* s0-s3 */
 	unsigned long reg27, reg28, reg29, reg30, reg31; /* s4-s8 */
 
@@ -145,45 +145,9 @@ struct thread_struct {
 #define thread_saved_ra(tsk)	(tsk->thread.sched_ra)
 #define thread_saved_fp(tsk)	(tsk->thread.sched_cfa)
 
-#define INIT_THREAD  {						\
-	/*							\
-	 * Main processor registers				\
-	 */							\
-	.reg01			= 0,				\
-	.reg03			= 0,				\
-	.reg22			= 0,				\
-	.reg23			= 0,				\
-	.reg24			= 0,				\
-	.reg25			= 0,				\
-	.reg26			= 0,				\
-	.reg27			= 0,				\
-	.reg28			= 0,				\
-	.reg29			= 0,				\
-	.reg30			= 0,				\
-	.reg31			= 0,				\
-	.sched_ra		= 0,				\
-	.sched_cfa		= 0,				\
-	.csr_crmd		= 0,				\
-	.csr_prmd		= 0,				\
-	.csr_euen		= 0,				\
-	.csr_ecfg		= 0,				\
-	.csr_badvaddr		= 0,				\
-	/*							\
-	 * Other stuff associated with the process		\
-	 */							\
-	.trap_nr		= 0,				\
-	.error_code		= 0,				\
-	/*							\
-	 * FPU & vector registers				\
-	 */							\
-	.fpu			= {				\
-		.fcc		= 0,				\
-		.fcsr		= 0,				\
-		.ftop		= 0,				\
-		.fpr		= {{{0,},},},			\
-	},							\
-	.hbp_break		= {0},				\
-	.hbp_watch		= {0},				\
+#define INIT_THREAD  {							\
+	.reg02 = (unsigned long)&init_task,				\
+	.reg03 = (unsigned long)&init_stack + sizeof(init_stack),	\
 }
 
 struct task_struct;
diff --git a/arch/loongarch/include/asm/ptrace.h b/arch/loongarch/include/asm/ptrace.h
index e5d21e836d99..37f53629d3c7 100644
--- a/arch/loongarch/include/asm/ptrace.h
+++ b/arch/loongarch/include/asm/ptrace.h
@@ -170,12 +170,6 @@ static inline void die_if_kernel(const char *str, struct pt_regs *regs)
 		die(str, regs);
 }
 
-#define current_pt_regs()						\
-({									\
-	unsigned long sp = (unsigned long)__builtin_frame_address(0);	\
-	(struct pt_regs *)((sp | (THREAD_SIZE - 1)) + 1) - 1;		\
-})
-
 /* Helpers for working with the user stack pointer */
 
 static inline unsigned long user_stack_pointer(struct pt_regs *regs)
diff --git a/arch/loongarch/include/asm/smp.h b/arch/loongarch/include/asm/smp.h
index 3a47f52959a8..761cc0016df8 100644
--- a/arch/loongarch/include/asm/smp.h
+++ b/arch/loongarch/include/asm/smp.h
@@ -82,7 +82,8 @@ struct seq_file;
 
 struct secondary_data {
 	unsigned long stack;
-	unsigned long thread_info;
+	unsigned long task;
+	unsigned long offset;
 };
 extern struct secondary_data cpuboot_data;
 
diff --git a/arch/loongarch/include/asm/stackframe.h b/arch/loongarch/include/asm/stackframe.h
index ecc8e50fffa8..eeda5dcc982e 100644
--- a/arch/loongarch/include/asm/stackframe.h
+++ b/arch/loongarch/include/asm/stackframe.h
@@ -191,8 +191,13 @@
 	andi	t0, t0, 0x3	/* extract pplv bit */
 	beqz	t0, 9f
 
-	LONG_LI	tp, ~_THREAD_MASK
-	and	tp, tp, sp
+	la_abs      t1, __entry_task
+#ifdef CONFIG_SMP
+	csrrd       t0, PERCPU_BASE_KS
+	LONG_ADD    t1, t1, t0
+#endif
+	LONG_L      tp, t1, 0
+
 	cfi_st  u0, PT_R21, \docfi
 	csrrd	u0, PERCPU_BASE_KS
 9:
diff --git a/arch/loongarch/include/asm/switch_to.h b/arch/loongarch/include/asm/switch_to.h
index 5b225aff3ba2..9932429cfe17 100644
--- a/arch/loongarch/include/asm/switch_to.h
+++ b/arch/loongarch/include/asm/switch_to.h
@@ -5,17 +5,25 @@
 #ifndef _ASM_SWITCH_TO_H
 #define _ASM_SWITCH_TO_H
 
+#include <linux/percpu.h>
+
 #include <asm/cpu-features.h>
 #include <asm/fpu.h>
 #include <asm/lbt.h>
 
 struct task_struct;
 
+DECLARE_PER_CPU(struct task_struct *, __entry_task);
+
+static inline void entry_task_switch(struct task_struct *next)
+{
+	__this_cpu_write(__entry_task, next);
+}
+
 /**
  * __switch_to - switch execution of a task
  * @prev:	The task previously executed.
  * @next:	The task to begin executing.
- * @next_ti:	task_thread_info(next).
  * @sched_ra:	__schedule return address.
  * @sched_cfa:	__schedule call frame address.
  *
@@ -23,7 +31,7 @@ struct task_struct;
  * the context of next. Returns prev.
  */
 extern asmlinkage struct task_struct *__switch_to(struct task_struct *prev,
-			struct task_struct *next, struct thread_info *next_ti,
+			struct task_struct *next,
 			void *sched_ra, void *sched_cfa);
 
 /*
@@ -37,7 +45,8 @@ do {										\
 	lose_fpu_inatomic(1, prev);						\
 	lose_lbt_inatomic(1, prev);						\
 	hw_breakpoint_thread_switch(next);					\
-	(last) = __switch_to(prev, next, task_thread_info(next),		\
+	entry_task_switch(next);						\
+	(last) = __switch_to(prev, next,					\
 		 __builtin_return_address(0), __builtin_frame_address(0));	\
 } while (0)
 
diff --git a/arch/loongarch/include/asm/thread_info.h b/arch/loongarch/include/asm/thread_info.h
index 4d7117fcdc78..2c95a5134976 100644
--- a/arch/loongarch/include/asm/thread_info.h
+++ b/arch/loongarch/include/asm/thread_info.h
@@ -22,9 +22,7 @@
  *   must also be changed
  */
 struct thread_info {
-	struct task_struct	*task;		/* main task structure */
 	unsigned long		flags;		/* low level flags */
-	unsigned long		tp_value;	/* thread pointer */
 	__u32			cpu;		/* current CPU */
 	int			preempt_count;	/* 0 => preemptible, <0 => BUG */
 	struct pt_regs		*regs;
@@ -37,20 +35,11 @@ struct thread_info {
  */
 #define INIT_THREAD_INFO(tsk)			\
 {						\
-	.task		= &tsk,			\
-	.flags		= _TIF_FIXADE,		\
+	.flags		= 0,			\
 	.cpu		= 0,			\
 	.preempt_count	= INIT_PREEMPT_COUNT,	\
 }
 
-/* How to get the thread information struct from C. */
-register struct thread_info *__current_thread_info __asm__("$tp");
-
-static inline struct thread_info *current_thread_info(void)
-{
-	return __current_thread_info;
-}
-
 register unsigned long current_stack_pointer __asm__("$sp");
 
 #endif /* !__ASSEMBLER__ */
diff --git a/arch/loongarch/kernel/asm-offsets.c b/arch/loongarch/kernel/asm-offsets.c
index 2cc953f113ac..55f4ffc1aca5 100644
--- a/arch/loongarch/kernel/asm-offsets.c
+++ b/arch/loongarch/kernel/asm-offsets.c
@@ -70,7 +70,7 @@ static void __used output_task_defines(void)
 {
 	COMMENT("LoongArch task_struct offsets.");
 	OFFSET(TASK_STATE, task_struct, __state);
-	OFFSET(TASK_THREAD_INFO, task_struct, stack);
+	OFFSET(TASK_STACK, task_struct, stack);
 	OFFSET(TASK_FLAGS, task_struct, flags);
 	OFFSET(TASK_MM, task_struct, mm);
 	OFFSET(TASK_PID, task_struct, pid);
@@ -84,9 +84,7 @@ static void __used output_task_defines(void)
 static void __used output_thread_info_defines(void)
 {
 	COMMENT("LoongArch thread_info offsets.");
-	OFFSET(TI_TASK, thread_info, task);
 	OFFSET(TI_FLAGS, thread_info, flags);
-	OFFSET(TI_TP_VALUE, thread_info, tp_value);
 	OFFSET(TI_CPU, thread_info, cpu);
 	OFFSET(TI_PRE_COUNT, thread_info, preempt_count);
 	OFFSET(TI_REGS, thread_info, regs);
@@ -267,7 +265,8 @@ static void __used output_smpboot_defines(void)
 {
 	COMMENT("Linux smp cpu boot offsets.");
 	OFFSET(CPU_BOOT_STACK, secondary_data, stack);
-	OFFSET(CPU_BOOT_TINFO, secondary_data, thread_info);
+	OFFSET(CPU_BOOT_TASK, secondary_data, task);
+	OFFSET(CPU_BOOT_OFFSET, secondary_data, offset);
 	BLANK();
 }
 #endif
diff --git a/arch/loongarch/kernel/entry.S b/arch/loongarch/kernel/entry.S
index b53d333a7c42..b099672eab60 100644
--- a/arch/loongarch/kernel/entry.S
+++ b/arch/loongarch/kernel/entry.S
@@ -67,8 +67,11 @@ SYM_CODE_START(handle_syscall)
 #endif
 
 	move		u0, t0
-	LONG_LI		tp, ~_THREAD_MASK
-	and		tp, tp, sp
+	la_abs		t1, __entry_task
+#ifdef CONFIG_SMP
+	LONG_ADD	t1, t1, u0
+#endif
+	LONG_L		tp, t1, 0
 
 	move		a0, sp
 	bl		do_syscall
diff --git a/arch/loongarch/kernel/head.S b/arch/loongarch/kernel/head.S
index 4eed7bc312a8..ec67faab907b 100644
--- a/arch/loongarch/kernel/head.S
+++ b/arch/loongarch/kernel/head.S
@@ -74,10 +74,11 @@ SYM_CODE_START(kernel_entry)			# kernel entry point
 	/* GPR21 used for percpu base (runtime), initialized as 0 */
 	move		u0, zero
 
-	la.pcrel	tp, init_thread_union
-	/* Set the SP after an empty pt_regs.  */
-	PTR_LI		sp, (_THREAD_SIZE - PT_SIZE)
-	PTR_ADD		sp, sp, tp
+	la.pcrel	tp, init_task
+	la.pcrel	t0, init_stack
+	PTR_LI		t1, _THREAD_SIZE
+	PTR_ADD		t0, t0, t1
+	PTR_ADDI	sp, t0, -PT_SIZE
 	set_saved_sp	sp, t0, t1
 
 #ifdef CONFIG_RELOCATABLE
@@ -86,8 +87,10 @@ SYM_CODE_START(kernel_entry)			# kernel entry point
 
 #ifdef CONFIG_RANDOMIZE_BASE
 	/* Repoint the sp into the new kernel */
-	PTR_LI		sp, (_THREAD_SIZE - PT_SIZE)
-	PTR_ADD		sp, sp, tp
+	LONG_LPTR	t0, tp, TASK_STACK
+	PTR_LI		t1, _THREAD_SIZE
+	PTR_ADD		t0, t0, t1
+	PTR_ADDI	sp, t0, -PT_SIZE
 	set_saved_sp	sp, t0, t1
 
 	/* Jump to the new kernel: new_pc = current_pc + random_offset */
@@ -128,7 +131,8 @@ SYM_CODE_START(smpboot_entry)
 #endif
 	la.pcrel	t0, cpuboot_data
 	ld.d		sp, t0, CPU_BOOT_STACK
-	ld.d		tp, t0, CPU_BOOT_TINFO
+	ld.d		tp, t0, CPU_BOOT_TASK
+	ld.d		u0, t0, CPU_BOOT_OFFSET
 
 	bl		start_secondary
 	ASM_BUG()
diff --git a/arch/loongarch/kernel/process.c b/arch/loongarch/kernel/process.c
index 5505fc355e1b..71c9c6468e60 100644
--- a/arch/loongarch/kernel/process.c
+++ b/arch/loongarch/kernel/process.c
@@ -54,6 +54,9 @@
 #include <asm/vdso.h>
 #include <asm/vdso/vdso.h>
 
+DEFINE_PER_CPU(struct task_struct *, __entry_task);
+EXPORT_PER_CPU_SYMBOL_GPL(__entry_task);
+
 #ifdef CONFIG_STACKPROTECTOR
 #include <linux/stackprotector.h>
 unsigned long __stack_chk_guard __read_mostly;
@@ -223,6 +226,9 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
 	if (clone_flags & CLONE_SETTLS)
 		childregs->regs[2] = tls;
 
+	/* Set tp to the new task structure for context switching */
+	p->thread.reg02 = (unsigned long)p;
+
 out:
 	ptrace_hw_copy_thread(p);
 	clear_tsk_thread_flag(p, TIF_USEDFPU);
diff --git a/arch/loongarch/kernel/relocate.c b/arch/loongarch/kernel/relocate.c
index 16f6a9b39659..a9ef38459629 100644
--- a/arch/loongarch/kernel/relocate.c
+++ b/arch/loongarch/kernel/relocate.c
@@ -263,7 +263,7 @@ unsigned long __init relocate_kernel(void)
 		reloc_offset += random_offset;
 
 		/* The current thread is now within the relocated kernel */
-		__current_thread_info = RELOCATED_KASLR(__current_thread_info);
+		current_thread_pointer = RELOCATED_KASLR(current_thread_pointer);
 
 		update_reloc_offset(&reloc_offset, random_offset);
 	}
diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c
index 839b23edee87..5d434c5612ab 100644
--- a/arch/loongarch/kernel/setup.c
+++ b/arch/loongarch/kernel/setup.c
@@ -46,6 +46,7 @@
 #include <asm/pgalloc.h>
 #include <asm/sections.h>
 #include <asm/setup.h>
+#include <asm/switch_to.h>
 #include <asm/time.h>
 #include <asm/unwind.h>
 
@@ -617,4 +618,6 @@ void __init setup_arch(char **cmdline_p)
 #ifdef CONFIG_KASAN
 	kasan_init();
 #endif
+
+	entry_task_switch(&init_task);
 }
diff --git a/arch/loongarch/kernel/smp.c b/arch/loongarch/kernel/smp.c
index 64a048f1b880..e8b0d2fc2a9a 100644
--- a/arch/loongarch/kernel/smp.c
+++ b/arch/loongarch/kernel/smp.c
@@ -34,6 +34,7 @@
 #include <asm/paravirt.h>
 #include <asm/processor.h>
 #include <asm/setup.h>
+#include <asm/switch_to.h>
 #include <asm/time.h>
 
 int __cpu_number_map[NR_CPUS];   /* Map physical to logical */
@@ -400,8 +401,9 @@ void loongson_boot_secondary(int cpu, struct task_struct *idle)
 	pr_info("Booting CPU#%d...\n", cpu);
 
 	entry = __pa_symbol((unsigned long)&smpboot_entry);
-	cpuboot_data.stack = (unsigned long)__KSTK_TOS(idle);
-	cpuboot_data.thread_info = (unsigned long)task_thread_info(idle);
+	cpuboot_data.stack = (unsigned long)task_pt_regs(idle);
+	cpuboot_data.task = (unsigned long)idle;
+	cpuboot_data.offset = per_cpu_offset(cpu);
 
 	csr_mail_send(entry, cpu_logical_map(cpu), 0);
 
@@ -686,6 +688,8 @@ asmlinkage void start_secondary(void)
 	 */
 	complete(&cpu_running);
 
+	entry_task_switch(current);
+
 	/*
 	 * irq will be enabled in loongson_smp_finish(), enabling it too
 	 * early is dangerous.
diff --git a/arch/loongarch/kernel/switch.S b/arch/loongarch/kernel/switch.S
index f377d8f5c51a..644348e05f6a 100644
--- a/arch/loongarch/kernel/switch.S
+++ b/arch/loongarch/kernel/switch.S
@@ -12,7 +12,7 @@
 
 /*
  * task_struct *__switch_to(task_struct *prev, task_struct *next,
- *			    struct thread_info *next_ti, void *sched_ra, void *sched_cfa)
+ *			    void *sched_ra, void *sched_cfa)
  */
 	.align	5
 SYM_FUNC_START(__switch_to)
@@ -33,11 +33,12 @@ SYM_FUNC_START(__switch_to)
 	LONG_SPTR	t8, t7, 0
 #endif
 
-	move	tp, a2
+	move	tp, a1
 	cpu_restore_nonscratch a1
 
-	li.w		t0, _THREAD_SIZE
-	PTR_ADD		t0, t0, tp
+	LONG_LPTR	t0, tp, TASK_STACK
+	PTR_LI		t1, _THREAD_SIZE
+	PTR_ADD		t0, t0, t1
 	set_saved_sp	t0, t1, t2
 
 	LONG_LPTR	t1, a1, (THREAD_CSRPRMD - TASK_STRUCT_OFFSET)
-- 
2.42.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [RFC PATCH 2/3] LoongArch: BPF: Inline bpf_get_current_task{_btf}() helpers
  2026-04-28  7:20 [RFC PATCH 0/3] Move thread_info into task_struct for LoongArch Tiezhu Yang
  2026-04-28  7:20 ` [RFC PATCH 1/3] LoongArch: Implement CONFIG_THREAD_INFO_IN_TASK Tiezhu Yang
@ 2026-04-28  7:20 ` Tiezhu Yang
  2026-04-28  7:20 ` [RFC PATCH 3/3] LoongArch: BPF: Inline bpf_get_smp_processor_id() helper Tiezhu Yang
  2 siblings, 0 replies; 6+ messages in thread
From: Tiezhu Yang @ 2026-04-28  7:20 UTC (permalink / raw)
  To: loongarch, bpf, linux-arch, linux-kernel

The pointer to task_struct is always available in the $tp register,
the calls to bpf_get_current_task() and bpf_get_current_task_btf()
can be inlined into a single move instruction.

(1) Here is the sample test.c:

  #include <linux/bpf.h>
  #include <bpf/bpf_helpers.h>

  SEC("raw_tp/sys_enter")
  long test_task(void *ctx)
  {
	  return (long)bpf_get_current_task();
  }
  char _license[] SEC("license") = "GPL";

(2) Here are the test steps:

  sudo yum install libbpf-devel kernel-devel bpftool
  clang -target bpf -O2 -c test.c -o test.o
  sudo sysctl -w net.core.bpf_jit_enable=1
  sudo bpftool prog show name test_task
  sudo rm -f /sys/fs/bpf/test_task
  sudo bpftool prog load test.o /sys/fs/bpf/test_task
  ID=$(sudo bpftool prog show pinned /sys/fs/bpf/test_task | grep -oE '^[0-9]+')
  sudo bpftool prog dump jited id $ID

(3) Here are the test results:

Before: 6 instructions

  ...
  64:	lu12i.w	$t1, 1093
  68:	ori	$t1, $t1, 3320
  6c:	lu32i.d	$t1, 0
  70:	lu52i.d	$t1, $t1, -1792
  74:	jirl	$ra, $t1, 0
  78:	move	$a5, $a0
  ...

After: 1 instruction

  ...
  64:	move	$a5, $tp
  ...

This is similar with commit 2bb138cb20a6 ("bpf, arm64: Inline
bpf_get_current_task/_btf() helpers").

Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
---
 arch/loongarch/net/bpf_jit.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c
index 24913dc7f4e8..b93b67d22c26 100644
--- a/arch/loongarch/net/bpf_jit.c
+++ b/arch/loongarch/net/bpf_jit.c
@@ -1147,6 +1147,13 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
 
 	/* function call */
 	case BPF_JMP | BPF_CALL:
+		/* Implement helper call to bpf_get_current_task/_btf() inline */
+		if (insn->src_reg == 0 && (insn->imm == BPF_FUNC_get_current_task ||
+					   insn->imm == BPF_FUNC_get_current_task_btf)) {
+			move_reg(ctx, regmap[BPF_REG_0], LOONGARCH_GPR_TP);
+			break;
+		}
+
 		ret = bpf_jit_get_func_addr(ctx->prog, insn, extra_pass,
 					    &func_addr, &func_addr_fixed);
 		if (ret < 0)
@@ -2367,3 +2374,14 @@ bool bpf_jit_supports_subprog_tailcalls(void)
 {
 	return true;
 }
+
+bool bpf_jit_inlines_helper_call(s32 imm)
+{
+	switch (imm) {
+	case BPF_FUNC_get_current_task:
+	case BPF_FUNC_get_current_task_btf:
+		return true;
+	default:
+		return false;
+	}
+}
-- 
2.42.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [RFC PATCH 3/3] LoongArch: BPF: Inline bpf_get_smp_processor_id() helper
  2026-04-28  7:20 [RFC PATCH 0/3] Move thread_info into task_struct for LoongArch Tiezhu Yang
  2026-04-28  7:20 ` [RFC PATCH 1/3] LoongArch: Implement CONFIG_THREAD_INFO_IN_TASK Tiezhu Yang
  2026-04-28  7:20 ` [RFC PATCH 2/3] LoongArch: BPF: Inline bpf_get_current_task{_btf}() helpers Tiezhu Yang
@ 2026-04-28  7:20 ` Tiezhu Yang
  2026-04-28 21:25   ` sashiko-bot
  2 siblings, 1 reply; 6+ messages in thread
From: Tiezhu Yang @ 2026-04-28  7:20 UTC (permalink / raw)
  To: loongarch, bpf, linux-arch, linux-kernel

The pointer to thread_info is always available in the $tp register,
the call to bpf_get_smp_processor_id() can be inlined into a single
load instruction.

(1) Here is the sample test.c:

  #include <linux/bpf.h>
  #include <bpf/bpf_helpers.h>

  SEC("raw_tp/sys_enter")
  int test_cpuid(void *ctx)
  {
	  return bpf_get_smp_processor_id();
  }
  char _license[] SEC("license") = "GPL";

(2) Here are the test steps:

  sudo yum install libbpf-devel kernel-devel bpftool
  clang -target bpf -O2 -c test.c -o test.o
  sudo sysctl -w net.core.bpf_jit_enable=1
  sudo bpftool prog show name test_cpuid
  sudo rm -f /sys/fs/bpf/test_cpuid
  sudo bpftool prog load test.o /sys/fs/bpf/test_cpuid
  ID=$(sudo bpftool prog show pinned /sys/fs/bpf/test_cpuid | grep -oE '^[0-9]+')
  sudo bpftool prog dump jited id $ID

(3) Here are the test results:

Before: 6 instructions

  ...
  64:	lu12i.w	$t1, 1213
  68:	ori	$t1, $t1, 1680
  6c:	lu32i.d	$t1, 0
  70:	lu52i.d	$t1, $t1, -1792
  74:	jirl	$ra, $t1, 0
  78:	move	$a5, $a0
  ...

After: 1 instruction

  ...
  64:	ld.w	$a5, $tp, 8
  ...

This is similar with commit 2ddec2c80b44 ("riscv, bpf: inline
bpf_get_smp_processor_id()").

Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
---
 arch/loongarch/net/bpf_jit.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c
index b93b67d22c26..b1c6194c4099 100644
--- a/arch/loongarch/net/bpf_jit.c
+++ b/arch/loongarch/net/bpf_jit.c
@@ -5,6 +5,7 @@
  * Copyright (C) 2022 Loongson Technology Corporation Limited
  */
 #include <linux/memory.h>
+#include <asm/asm-offsets.h>
 #include "bpf_jit.h"
 
 #define LOONGARCH_MAX_REG_ARGS 8
@@ -1154,6 +1155,12 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
 			break;
 		}
 
+		/* Implement helper call to bpf_get_smp_processor_id() inline */
+		if (insn->src_reg == 0 && insn->imm == BPF_FUNC_get_smp_processor_id) {
+			emit_insn(ctx, ldw, regmap[BPF_REG_0], LOONGARCH_GPR_TP, TI_CPU);
+			break;
+		}
+
 		ret = bpf_jit_get_func_addr(ctx->prog, insn, extra_pass,
 					    &func_addr, &func_addr_fixed);
 		if (ret < 0)
@@ -2380,6 +2387,7 @@ bool bpf_jit_inlines_helper_call(s32 imm)
 	switch (imm) {
 	case BPF_FUNC_get_current_task:
 	case BPF_FUNC_get_current_task_btf:
+	case BPF_FUNC_get_smp_processor_id:
 		return true;
 	default:
 		return false;
-- 
2.42.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [RFC PATCH 1/3] LoongArch: Implement CONFIG_THREAD_INFO_IN_TASK
  2026-04-28  7:20 ` [RFC PATCH 1/3] LoongArch: Implement CONFIG_THREAD_INFO_IN_TASK Tiezhu Yang
@ 2026-04-28 20:38   ` sashiko-bot
  0 siblings, 0 replies; 6+ messages in thread
From: sashiko-bot @ 2026-04-28 20:38 UTC (permalink / raw)
  To: Tiezhu Yang; +Cc: bpf

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Critical] The default thread flags initialization drops `_TIF_FIXADE`, silently disabling unaligned memory access software fixups by default.
- [High] The `__switch_to` assembly function incorrectly saves the `sched_ra` and `sched_cfa` arguments due to a shifted parameter list, corrupting the saved stack unwinding information.
- [Low] The `reg02` field added to `thread_struct` is dead code, never read or restored, and left uninitialized for kernel threads.
--

commit 40aa85795dd4ee444da3115a1909cec1be7bed8d
Author: Tiezhu Yang <yangtiezhu@loongson.cn>

LoongArch: Implement CONFIG_THREAD_INFO_IN_TASK

This commit selects THREAD_INFO_IN_TASK for LoongArch to move thread_info
off the stack into task_struct. It introduces a per-CPU variable __entry_task
to store the current task_struct pointer and updates the context switch path
and exception entry to use it.

>     Additionally, add reg02 ($tp) to thread_struct and initialize it in
>     both INIT_THREAD and copy_thread() to ensure that the "current" task
>     pointer is correctly set up for the initial idle task and all future
>     child processes. While __switch_to() directly updates $tp from a1 for
>     efficiency, storing it in thread_struct ensures correct restoration
>     for new processes and in non-standard switch paths.

Is this description accurate? Looking at the code, the reg02 field does not
appear to be read during restoration. New threads restore their user tp from
pt_regs, and cpu_restore_nonscratch does not seem to restore it. 

> diff --git a/arch/loongarch/include/asm/processor.h b/arch/loongarch/include/asm/processor.h
> index ce8b953f8c79..df927a4318cc 100644
> --- a/arch/loongarch/include/asm/processor.h
> +++ b/arch/loongarch/include/asm/processor.h
[ ... ]
> @@ -109,7 +109,7 @@ struct loongarch_vdso_info;
>   */
>  struct thread_struct {
>  	/* Main processor registers. */
> -	unsigned long reg01, reg03, reg22; /* ra sp fp */
> +	unsigned long reg01, reg02, reg03, reg22; /* ra tp sp fp */
>  	unsigned long reg23, reg24, reg25, reg26; /* s0-s3 */
>  	unsigned long reg27, reg28, reg29, reg30, reg31; /* s4-s8 */

Could this reg02 field be dead code? If it is never read back out of the
thread_struct, is it needed here?

> diff --git a/arch/loongarch/include/asm/switch_to.h b/arch/loongarch/include/asm/switch_to.h
> index 5b225aff3ba2..9932429cfe17 100644
> --- a/arch/loongarch/include/asm/switch_to.h
> +++ b/arch/loongarch/include/asm/switch_to.h
[ ... ]
> @@ -23,7 +31,7 @@ struct task_struct;
>   * the context of next. Returns prev.
>   */
>  extern asmlinkage struct task_struct *__switch_to(struct task_struct *prev,
> -			struct task_struct *next, struct thread_info *next_ti,
> +			struct task_struct *next,
>  			void *sched_ra, void *sched_cfa);

When the next_ti argument is removed here, sched_ra and sched_cfa shift to 
registers a2 and a3 under the LoongArch C calling convention.

Does the assembly implementation of __switch_to() in switch.S also need to be 
updated? If it still reads from a3 and a4, could this corrupt the saved stack 
unwinding information by storing the stack pointer into THREAD_SCHED_RA
instead? This might break stack unwinding for parked tasks.

> diff --git a/arch/loongarch/include/asm/thread_info.h b/arch/loongarch/include/asm/thread_info.h
> index 4d7117fcdc78..2c95a5134976 100644
> --- a/arch/loongarch/include/asm/thread_info.h
> +++ b/arch/loongarch/include/asm/thread_info.h
[ ... ]
> @@ -37,20 +35,11 @@ struct thread_info {
>   */
>  #define INIT_THREAD_INFO(tsk)			\
>  {						\
> -	.task		= &tsk,			\
> -	.flags		= _TIF_FIXADE,		\
> +	.flags		= 0,			\
>  	.cpu		= 0,			\
>  	.preempt_count	= INIT_PREEMPT_COUNT,	\
>  }

Does removing _TIF_FIXADE here globally disable the unaligned memory access 
software fixups? 

Since all newly created tasks inherit their initial thread info flags from 
init_task, could this cause user-space applications performing unaligned 
accesses to crash with a bus error?

> diff --git a/arch/loongarch/kernel/process.c b/arch/loongarch/kernel/process.c
> index 5505fc355e1b..71c9c6468e60 100644
> --- a/arch/loongarch/kernel/process.c
> +++ b/arch/loongarch/kernel/process.c
[ ... ]
> @@ -223,6 +226,9 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
>  	if (clone_flags & CLONE_SETTLS)
>  		childregs->regs[2] = tls;
>  
> +	/* Set tp to the new task structure for context switching */
> +	p->thread.reg02 = (unsigned long)p;
> +
>  out:
>  	ptrace_hw_copy_thread(p);

For kernel threads, copy_thread() jumps to the out label before reaching this 
initialization. Does this leave p->thread.reg02 uninitialized for kernel
threads, potentially retaining a stale task pointer from the parent process?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260428072021.7289-1-yangtiezhu@loongson.cn?part=1

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [RFC PATCH 3/3] LoongArch: BPF: Inline bpf_get_smp_processor_id() helper
  2026-04-28  7:20 ` [RFC PATCH 3/3] LoongArch: BPF: Inline bpf_get_smp_processor_id() helper Tiezhu Yang
@ 2026-04-28 21:25   ` sashiko-bot
  0 siblings, 0 replies; 6+ messages in thread
From: sashiko-bot @ 2026-04-28 21:25 UTC (permalink / raw)
  To: Tiezhu Yang; +Cc: bpf

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] The inlined `bpf_get_smp_processor_id` helper uses a sign-extending load (`ldw`) instead of a zero-extending load (`ldwu`).
--

commit 537ce2d4859db91089b968d6b560566858b53b6f
Author: Tiezhu Yang <yangtiezhu@loongson.cn>

LoongArch: BPF: Inline bpf_get_smp_processor_id() helper

This commit inlines the bpf_get_smp_processor_id() helper into a single
load instruction on LoongArch. It accesses the thread_info which is always
available in the thread pointer register.

> diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c
> index b93b67d22c26..b1c6194c4099 100644
> --- a/arch/loongarch/net/bpf_jit.c
> +++ b/arch/loongarch/net/bpf_jit.c

[ ... ]

> @@ -1154,6 +1155,12 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
>  			break;
>  		}
>  
> +		/* Implement helper call to bpf_get_smp_processor_id() inline */
> +		if (insn->src_reg == 0 && insn->imm == BPF_FUNC_get_smp_processor_id) {
> +			emit_insn(ctx, ldw, regmap[BPF_REG_0], LOONGARCH_GPR_TP, TI_CPU);

Does this code need to use a zero-extending load (ldwu) instead of a
sign-extending load (ldw)?

The C implementation of bpf_get_smp_processor_id() returns a u64, meaning
the 32-bit smp_processor_id() result is zero-extended to 64 bits.

While CPU IDs are small positive integers so sign-extending and
zero-extending produce the same result in practice, using the
zero-extending ldwu would strictly match the BPF calling convention and
original C helper semantics.

> +			break;
> +		}
> +
>  		ret = bpf_jit_get_func_addr(ctx->prog, insn, extra_pass,
>  					    &func_addr, &func_addr_fixed);
>  		if (ret < 0)

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260428072021.7289-1-yangtiezhu@loongson.cn?part=3

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-04-28 21:25 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-28  7:20 [RFC PATCH 0/3] Move thread_info into task_struct for LoongArch Tiezhu Yang
2026-04-28  7:20 ` [RFC PATCH 1/3] LoongArch: Implement CONFIG_THREAD_INFO_IN_TASK Tiezhu Yang
2026-04-28 20:38   ` sashiko-bot
2026-04-28  7:20 ` [RFC PATCH 2/3] LoongArch: BPF: Inline bpf_get_current_task{_btf}() helpers Tiezhu Yang
2026-04-28  7:20 ` [RFC PATCH 3/3] LoongArch: BPF: Inline bpf_get_smp_processor_id() helper Tiezhu Yang
2026-04-28 21:25   ` sashiko-bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox