]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
LoongArch: Handle percpu handler address for ORC unwinder
authorTiezhu Yang <yangtiezhu@loongson.cn>
Tue, 10 Feb 2026 11:31:13 +0000 (19:31 +0800)
committerHuacai Chen <chenhuacai@loongson.cn>
Tue, 10 Feb 2026 11:31:13 +0000 (19:31 +0800)
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>
arch/loongarch/include/asm/setup.h
arch/loongarch/kernel/unwind_orc.c

index 3c2fb16b11b649cdfc895c9051d471307c9ca0ce..f81375e5e89c0d14d97dd5344fa8aebbf2483d11 100644 (file)
@@ -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);
index d6b3688a1ce9702e01d44cef4109d9cb9fb27d38..11ba3e4ac9eee94f4830ec472dd00d7aa639fe40 100644 (file)
@@ -352,6 +352,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;