| From f13a8eb8db2241b98ee01abc55635345669e079f Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Tue, 10 Feb 2026 19:31:13 +0800 |
| Subject: LoongArch: Handle percpu handler address for ORC unwinder |
| |
| From: Tiezhu Yang <yangtiezhu@loongson.cn> |
| |
| [ Upstream commit 055c7e75190e0be43037bd663a3f6aced194416e ] |
| |
| After commit 4cd641a79e69 ("LoongArch: Remove unnecessary checks for ORC |
| unwinder"), the system can not boot normally under some configs (such as |
| enable KASAN), there are many error messages "cannot find unwind pc". |
| |
| The kernel boots normally with the defconfig, so no problem found out at |
| the first time. Here is one way to reproduce: |
| |
| cd linux |
| make mrproper defconfig -j"$(nproc)" |
| scripts/config -e KASAN |
| make olddefconfig all -j"$(nproc)" |
| sudo make modules_install |
| sudo make install |
| sudo reboot |
| |
| The address that can not unwind is not a valid kernel address which is |
| between "pcpu_handlers[cpu]" and "pcpu_handlers[cpu] + vec_sz" due to |
| the code of eentry was copied to the new area of pcpu_handlers[cpu] in |
| setup_tlb_handler(), handle this special case to get the valid address |
| to unwind normally. |
| |
| Cc: stable@vger.kernel.org |
| Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn> |
| Signed-off-by: Huacai Chen <chenhuacai@loongson.cn> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| arch/loongarch/include/asm/setup.h | 3 +++ |
| arch/loongarch/kernel/unwind_orc.c | 16 ++++++++++++++++ |
| 2 files changed, 19 insertions(+) |
| |
| diff --git a/arch/loongarch/include/asm/setup.h b/arch/loongarch/include/asm/setup.h |
| index 3c2fb16b11b64..f81375e5e89c0 100644 |
| --- a/arch/loongarch/include/asm/setup.h |
| +++ b/arch/loongarch/include/asm/setup.h |
| @@ -7,6 +7,7 @@ |
| #define _LOONGARCH_SETUP_H |
| |
| #include <linux/types.h> |
| +#include <linux/threads.h> |
| #include <asm/sections.h> |
| #include <uapi/asm/setup.h> |
| |
| @@ -14,6 +15,8 @@ |
| |
| extern unsigned long eentry; |
| extern unsigned long tlbrentry; |
| +extern unsigned long pcpu_handlers[NR_CPUS]; |
| +extern long exception_handlers[VECSIZE * 128 / sizeof(long)]; |
| extern char init_command_line[COMMAND_LINE_SIZE]; |
| extern void tlb_init(int cpu); |
| extern void cpu_cache_init(void); |
| diff --git a/arch/loongarch/kernel/unwind_orc.c b/arch/loongarch/kernel/unwind_orc.c |
| index b67f065905256..ad7e63f495045 100644 |
| --- a/arch/loongarch/kernel/unwind_orc.c |
| +++ b/arch/loongarch/kernel/unwind_orc.c |
| @@ -360,6 +360,22 @@ static inline unsigned long bt_address(unsigned long ra) |
| { |
| extern unsigned long eentry; |
| |
| +#if defined(CONFIG_NUMA) && !defined(CONFIG_PREEMPT_RT) |
| + int cpu; |
| + int vec_sz = sizeof(exception_handlers); |
| + |
| + for_each_possible_cpu(cpu) { |
| + if (!pcpu_handlers[cpu]) |
| + continue; |
| + |
| + if (ra >= pcpu_handlers[cpu] && |
| + ra < pcpu_handlers[cpu] + vec_sz) { |
| + ra = ra + eentry - pcpu_handlers[cpu]; |
| + break; |
| + } |
| + } |
| +#endif |
| + |
| if (ra >= eentry && ra < eentry + EXCCODE_INT_END * VECSIZE) { |
| unsigned long func; |
| unsigned long type = (ra - eentry) / VECSIZE; |
| -- |
| 2.51.0 |
| |