[PATCH v1] LoongArch: Handle special PC in unwind_next_frame()

Tiezhu Yang posted 1 patch 6 days, 17 hours ago
arch/loongarch/kernel/unwind_orc.c | 3 +++
1 file changed, 3 insertions(+)
[PATCH v1] LoongArch: Handle special PC in unwind_next_frame()
Posted by Tiezhu Yang 6 days, 17 hours ago
When running virtual machine before testing the kernel live patching with
"modprobe livepatch-sample", there is a timeout over 15 seconds, the dmesg
command shows "unreliable stack" for user tasks in debug mode.

The "unreliable stack" is because it can not unwind from kvm_handle_exit()
to its previous frame kvm_exc_entry() due to the PC is not a valid kernel
address, the root cause is that the code of kvm_exc_entry() was copied to
the DMW area in kvm_loongarch_env_init(), so it should check the PC range
and then finish unwinding for this special case.

How to test:

(1) Update kernel with LIVEPATCH

  git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
  cd linux && make mrproper defconfig
  scripts/config -e FTRACE -e FUNCTION_TRACER \
  -e LIVEPATCH -e SAMPLES -m SAMPLE_LIVEPATCH
  make olddefconfig all -j"$(nproc)"
  sudo make modules_install
  sudo make install
  sudo reboot

(2) Set up a VM with "-accel kvm", no need to specify kernel and initrd

  sudo yum -y install edk2-loongarch64 qemu
  qemu-system-loongarch64 -serial stdio \
  -machine virt -cpu la464 -smp 8 -m 4G \
  -bios /usr/share/edk2/loongarch64/QEMU_EFI.fd \
  -nodefaults -no-reboot -nographic -accel kvm

(3) Test the kernel live patching

  cat /proc/cmdline
  sudo modprobe livepatch-sample
  cat /proc/cmdline
  sudo sh -c "echo 0 > /sys/kernel/livepatch/livepatch_sample/enabled"
  sudo rmmod livepatch_sample
  cat /proc/cmdline
  dmesg -T

Cc: stable@vger.kernel.org # v6.9+
Fixes: cb8a2ef0848c ("LoongArch: Add ORC stack unwinder support")
Reported-by: Xi Zhang <zhangxi@kylinos.cn>
Reported-by: Xianglai Li <lixianglai@loongson.cn>
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
---
 arch/loongarch/kernel/unwind_orc.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/loongarch/kernel/unwind_orc.c b/arch/loongarch/kernel/unwind_orc.c
index 0d5fa64a2225..1d60a593479a 100644
--- a/arch/loongarch/kernel/unwind_orc.c
+++ b/arch/loongarch/kernel/unwind_orc.c
@@ -506,6 +506,9 @@ bool unwind_next_frame(struct unwind_state *state)
 		goto err;
 	}
 
+	if (pc >= (unsigned long)_end && pc < (unsigned long)XKVRANGE)
+		goto end;
+
 	state->pc = bt_address(pc);
 	if (!state->pc) {
 		pr_err("cannot find unwind pc at %p\n", (void *)pc);
-- 
2.42.0
Re: [PATCH v1] LoongArch: Handle special PC in unwind_next_frame()
Posted by Jinyang He 6 days, 13 hours ago
On 2025-11-25 14:33, Tiezhu Yang wrote:

> When running virtual machine before testing the kernel live patching with
> "modprobe livepatch-sample", there is a timeout over 15 seconds, the dmesg
> command shows "unreliable stack" for user tasks in debug mode.
>
> The "unreliable stack" is because it can not unwind from kvm_handle_exit()
> to its previous frame kvm_exc_entry() due to the PC is not a valid kernel
> address, the root cause is that the code of kvm_exc_entry() was copied to
> the DMW area in kvm_loongarch_env_init(), so it should check the PC range
> and then finish unwinding for this special case.

Hi, Tiezhu,

Since kvm_loongarch_env_init copies kvm_exc_entry which similar to how
trap_init copies the exception handler. We should apply the same
offset-based adjustment to compute the shadow PC address:
  shadow_pc = kvm_exc_entry + (cur_pc − copied_base_address)
This allows the ORC unwinder to correctly locate the corresponding 
unwind info.

On the other hand, the address range [_end, XKVRANGE) is unreliable.
If an immediate value is in this range and pushed into the stack,
unwinder might mistakenly interpret once it get this value as pc.

Jinyang


>
> How to test:
>
> (1) Update kernel with LIVEPATCH
>
>    git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
>    cd linux && make mrproper defconfig
>    scripts/config -e FTRACE -e FUNCTION_TRACER \
>    -e LIVEPATCH -e SAMPLES -m SAMPLE_LIVEPATCH
>    make olddefconfig all -j"$(nproc)"
>    sudo make modules_install
>    sudo make install
>    sudo reboot
>
> (2) Set up a VM with "-accel kvm", no need to specify kernel and initrd
>
>    sudo yum -y install edk2-loongarch64 qemu
>    qemu-system-loongarch64 -serial stdio \
>    -machine virt -cpu la464 -smp 8 -m 4G \
>    -bios /usr/share/edk2/loongarch64/QEMU_EFI.fd \
>    -nodefaults -no-reboot -nographic -accel kvm
>
> (3) Test the kernel live patching
>
>    cat /proc/cmdline
>    sudo modprobe livepatch-sample
>    cat /proc/cmdline
>    sudo sh -c "echo 0 > /sys/kernel/livepatch/livepatch_sample/enabled"
>    sudo rmmod livepatch_sample
>    cat /proc/cmdline
>    dmesg -T
>
> Cc: stable@vger.kernel.org # v6.9+
> Fixes: cb8a2ef0848c ("LoongArch: Add ORC stack unwinder support")
> Reported-by: Xi Zhang <zhangxi@kylinos.cn>
> Reported-by: Xianglai Li <lixianglai@loongson.cn>
> Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
> ---
>   arch/loongarch/kernel/unwind_orc.c | 3 +++
>   1 file changed, 3 insertions(+)
>
> diff --git a/arch/loongarch/kernel/unwind_orc.c b/arch/loongarch/kernel/unwind_orc.c
> index 0d5fa64a2225..1d60a593479a 100644
> --- a/arch/loongarch/kernel/unwind_orc.c
> +++ b/arch/loongarch/kernel/unwind_orc.c
> @@ -506,6 +506,9 @@ bool unwind_next_frame(struct unwind_state *state)
>   		goto err;
>   	}
>   
> +	if (pc >= (unsigned long)_end && pc < (unsigned long)XKVRANGE)
> +		goto end;
> +
>   	state->pc = bt_address(pc);
>   	if (!state->pc) {
>   		pr_err("cannot find unwind pc at %p\n", (void *)pc);

Re: [PATCH v1] LoongArch: Handle special PC in unwind_next_frame()
Posted by Tiezhu Yang 5 days, 17 hours ago
On 2025/11/25 下午6:52, Jinyang He wrote:
> On 2025-11-25 14:33, Tiezhu Yang wrote:
> 
>> When running virtual machine before testing the kernel live patching with
>> "modprobe livepatch-sample", there is a timeout over 15 seconds, the 
>> dmesg
>> command shows "unreliable stack" for user tasks in debug mode.
>>
>> The "unreliable stack" is because it can not unwind from 
>> kvm_handle_exit()
>> to its previous frame kvm_exc_entry() due to the PC is not a valid kernel
>> address, the root cause is that the code of kvm_exc_entry() was copied to
>> the DMW area in kvm_loongarch_env_init(), so it should check the PC range
>> and then finish unwinding for this special case.
> 
> Hi, Tiezhu,
> 
> Since kvm_loongarch_env_init copies kvm_exc_entry which similar to how
> trap_init copies the exception handler. We should apply the same
> offset-based adjustment to compute the shadow PC address:
>   shadow_pc = kvm_exc_entry + (cur_pc − copied_base_address)
> This allows the ORC unwinder to correctly locate the corresponding 
> unwind info.

Thank you. I did some tests, it can unwind from kvm_handle_exit()
to its previous frame kvm_exc_entry() only when CONFIG_KVM=y,
but it can not unwind from kvm_handle_exit() to its previous frame 
kvm_exc_entry() when CONFIG_KVM=m because we can not get the two
kvm address (unsigned long)kvm_exc_entry and
(unsigned long)kvm_loongarch_ops->exc_entry
in arch/loongarch/kernel/unwind_orc.c.

The KVM team will provide a patch to do something, then I will
test it again.

Thanks,
Tiezhu

Re: [PATCH v1] LoongArch: Handle special PC in unwind_next_frame()
Posted by Tiezhu Yang 5 days, 17 hours ago
On 2025/11/26 下午2:08, Tiezhu Yang wrote:
> On 2025/11/25 下午6:52, Jinyang He wrote:
>> On 2025-11-25 14:33, Tiezhu Yang wrote:
>>
>>> When running virtual machine before testing the kernel live patching 
>>> with
>>> "modprobe livepatch-sample", there is a timeout over 15 seconds, the 
>>> dmesg
>>> command shows "unreliable stack" for user tasks in debug mode.
>>>
>>> The "unreliable stack" is because it can not unwind from 
>>> kvm_handle_exit()
>>> to its previous frame kvm_exc_entry() due to the PC is not a valid 
>>> kernel
>>> address, the root cause is that the code of kvm_exc_entry() was 
>>> copied to
>>> the DMW area in kvm_loongarch_env_init(), so it should check the PC 
>>> range
>>> and then finish unwinding for this special case.
>>
>> Hi, Tiezhu,
>>
>> Since kvm_loongarch_env_init copies kvm_exc_entry which similar to how
>> trap_init copies the exception handler. We should apply the same
>> offset-based adjustment to compute the shadow PC address:
>>   shadow_pc = kvm_exc_entry + (cur_pc − copied_base_address)
>> This allows the ORC unwinder to correctly locate the corresponding 
>> unwind info.
> 
> Thank you. I did some tests, it can unwind from kvm_handle_exit()
> to its previous frame kvm_exc_entry() only when CONFIG_KVM=y,
> but it can not unwind from kvm_handle_exit() to its previous frame 
> kvm_exc_entry() when CONFIG_KVM=m because we can not get the two
> kvm address (unsigned long)kvm_exc_entry and
> (unsigned long)kvm_loongarch_ops->exc_entry
> in arch/loongarch/kernel/unwind_orc.c.

Use function pointer can get get the two kvm address
(unsigned long)kvm_exc_entry and
(unsigned long)kvm_loongarch_ops->exc_entry
in arch/loongarch/kernel/unwind_orc.c.

I will do more test and send v2 later.

Thanks,
Tiezhu

Re: [PATCH v1] LoongArch: Handle special PC in unwind_next_frame()
Posted by Tiezhu Yang 5 days, 14 hours ago
Cc: Bibo Mao <maobibo@loongson.cn>

On 2025/11/26 下午2:28, Tiezhu Yang wrote:
> On 2025/11/26 下午2:08, Tiezhu Yang wrote:
>> On 2025/11/25 下午6:52, Jinyang He wrote:
>>> On 2025-11-25 14:33, Tiezhu Yang wrote:
>>>
>>>> When running virtual machine before testing the kernel live patching 
>>>> with
>>>> "modprobe livepatch-sample", there is a timeout over 15 seconds, the 
>>>> dmesg
>>>> command shows "unreliable stack" for user tasks in debug mode.
>>>>
>>>> The "unreliable stack" is because it can not unwind from 
>>>> kvm_handle_exit()
>>>> to its previous frame kvm_exc_entry() due to the PC is not a valid 
>>>> kernel
>>>> address, the root cause is that the code of kvm_exc_entry() was 
>>>> copied to
>>>> the DMW area in kvm_loongarch_env_init(), so it should check the PC 
>>>> range
>>>> and then finish unwinding for this special case.
>>>
>>> Hi, Tiezhu,
>>>
>>> Since kvm_loongarch_env_init copies kvm_exc_entry which similar to how
>>> trap_init copies the exception handler. We should apply the same
>>> offset-based adjustment to compute the shadow PC address:
>>>   shadow_pc = kvm_exc_entry + (cur_pc − copied_base_address)
>>> This allows the ORC unwinder to correctly locate the corresponding 
>>> unwind info.
>>
>> Thank you. I did some tests, it can unwind from kvm_handle_exit()
>> to its previous frame kvm_exc_entry() only when CONFIG_KVM=y,
>> but it can not unwind from kvm_handle_exit() to its previous frame 
>> kvm_exc_entry() when CONFIG_KVM=m because we can not get the two
>> kvm address (unsigned long)kvm_exc_entry and
>> (unsigned long)kvm_loongarch_ops->exc_entry
>> in arch/loongarch/kernel/unwind_orc.c.
> 
> Use function pointer can get get the two kvm address
> (unsigned long)kvm_exc_entry and
> (unsigned long)kvm_loongarch_ops->exc_entry
> in arch/loongarch/kernel/unwind_orc.c.
> 
> I will do more test and send v2 later.

Here are the draft changes:

----->8-----
diff --git a/arch/loongarch/kernel/unwind_guess.c 
b/arch/loongarch/kernel/unwind_guess.c
index 08d7951b2f60..64c50c483cbb 100644
--- a/arch/loongarch/kernel/unwind_guess.c
+++ b/arch/loongarch/kernel/unwind_guess.c
@@ -5,6 +5,11 @@
  #include <asm/unwind.h>
  #include <linux/export.h>

+#if IS_ENABLED(CONFIG_KVM)
+void (*get_kvm_entry_info)(unsigned long *old, unsigned long *new, 
unsigned long *size);
+EXPORT_SYMBOL_GPL(get_kvm_entry_info);
+#endif
+
  unsigned long unwind_get_return_address(struct unwind_state *state)
  {
         return __unwind_get_return_address(state);
diff --git a/arch/loongarch/kernel/unwind_orc.c 
b/arch/loongarch/kernel/unwind_orc.c
index 1d60a593479a..ef8bb6cd7af8 100644
--- a/arch/loongarch/kernel/unwind_orc.c
+++ b/arch/loongarch/kernel/unwind_orc.c
@@ -356,6 +356,11 @@ static bool is_entry_func(unsigned long addr)
         return addr >= (unsigned long)&kernel_entry && addr < (unsigned 
long)&kernel_entry_end;
  }

+#if IS_ENABLED(CONFIG_KVM)
+void (*get_kvm_entry_info)(unsigned long *old, unsigned long *new, 
unsigned long *size);
+EXPORT_SYMBOL_GPL(get_kvm_entry_info);
+#endif
+
  static inline unsigned long bt_address(unsigned long ra)
  {
         extern unsigned long eentry;
@@ -386,6 +391,16 @@ static inline unsigned long bt_address(unsigned 
long ra)
                 return func + offset;
         }

+#if IS_ENABLED(CONFIG_KVM)
+       unsigned long old, new, size;
+
+       if (get_kvm_entry_info) {
+               get_kvm_entry_info(&old, &new, &size);
+               if (ra >= new && ra < new + size)
+                       return old + (ra - new);
+       }
+#endif
+
         return ra;
  }

diff --git a/arch/loongarch/kernel/unwind_prologue.c 
b/arch/loongarch/kernel/unwind_prologue.c
index 729e775bd40d..42c210b0a378 100644
--- a/arch/loongarch/kernel/unwind_prologue.c
+++ b/arch/loongarch/kernel/unwind_prologue.c
@@ -28,6 +28,11 @@ extern unsigned long eentry;
  extern unsigned long pcpu_handlers[NR_CPUS];
  #endif

+#if IS_ENABLED(CONFIG_KVM)
+void (*get_kvm_entry_info)(unsigned long *old, unsigned long *new, 
unsigned long *size);
+EXPORT_SYMBOL_GPL(get_kvm_entry_info);
+#endif
+
  static inline bool scan_handlers(unsigned long entry_offset)
  {
         int idx, offset;
diff --git a/arch/loongarch/kvm/main.c b/arch/loongarch/kvm/main.c
index 80ea63d465b8..3606554e43e0 100644
--- a/arch/loongarch/kvm/main.c
+++ b/arch/loongarch/kvm/main.c
@@ -338,6 +338,13 @@ void kvm_arch_disable_virtualization_cpu(void)
         kvm_flush_tlb_all();
  }

+static void kvm_entry_info(unsigned long *old, unsigned long *new, 
unsigned long *size)
+{
+       *old = (unsigned long)kvm_exc_entry;
+       *new = (unsigned long)kvm_loongarch_ops->exc_entry;
+       *size = kvm_exception_size;
+}
+
  static int kvm_loongarch_env_init(void)
  {
         int cpu, order, ret;
@@ -430,6 +437,7 @@ static void kvm_loongarch_env_exit(void)
         kvm_unregister_perf_callbacks();
  }

+extern void (*get_kvm_entry_info)(unsigned long *old, unsigned long 
*new, unsigned long *size);
  static int kvm_loongarch_init(void)
  {
         int r;
@@ -442,6 +450,8 @@ static int kvm_loongarch_init(void)
         if (r)
                 return r;

+       get_kvm_entry_info = kvm_entry_info;
+
         return kvm_init(sizeof(struct kvm_vcpu), 0, THIS_MODULE);
  }

diff --git a/arch/loongarch/kvm/switch.S b/arch/loongarch/kvm/switch.S
index f1768b7a6194..9eaad5dbed91 100644
--- a/arch/loongarch/kvm/switch.S
+++ b/arch/loongarch/kvm/switch.S
@@ -104,7 +104,7 @@
         .text
         .cfi_sections   .debug_frame
  SYM_CODE_START(kvm_exc_entry)
-       UNWIND_HINT_UNDEFINED
+       UNWIND_HINT_END_OF_STACK
         csrwr   a2,   KVM_TEMP_KS
         csrrd   a2,   KVM_VCPU_KS
         addi.d  a2,   a2, KVM_VCPU_ARCH
----->8-----

I tested with config UNWINDER_ORC, it can unwind from kvm_handle_exit()
to its previous frame kvm_exc_entry() which is the end of stack, there
is no "unreliable stack" in debug mode and also no timeout for kernel
livepatching.

I also tested with config UNWINDER_PROLOGUE and config UNWINDER_GUESS,
no build errors and the virtual machine can boot normally.

I would like to receive comments for the draft changes first and then
send the formal v2, the function and variable name may be not proper,
so any comments are welcome.

Since the merge window is coming soon and I am busy with the other
higher priority stuff, so maybe I will send v2 after the merge window.

Thanks,
Tiezhu

Re: [PATCH v1] LoongArch: Handle special PC in unwind_next_frame()
Posted by Bibo Mao 5 days, 14 hours ago

On 2025/11/26 下午5:09, Tiezhu Yang wrote:
> Cc: Bibo Mao <maobibo@loongson.cn>
> 
> On 2025/11/26 下午2:28, Tiezhu Yang wrote:
>> On 2025/11/26 下午2:08, Tiezhu Yang wrote:
>>> On 2025/11/25 下午6:52, Jinyang He wrote:
>>>> On 2025-11-25 14:33, Tiezhu Yang wrote:
>>>>
>>>>> When running virtual machine before testing the kernel live 
>>>>> patching with
>>>>> "modprobe livepatch-sample", there is a timeout over 15 seconds, 
>>>>> the dmesg
>>>>> command shows "unreliable stack" for user tasks in debug mode.
>>>>>
>>>>> The "unreliable stack" is because it can not unwind from 
>>>>> kvm_handle_exit()
>>>>> to its previous frame kvm_exc_entry() due to the PC is not a valid 
>>>>> kernel
>>>>> address, the root cause is that the code of kvm_exc_entry() was 
>>>>> copied to
>>>>> the DMW area in kvm_loongarch_env_init(), so it should check the PC 
>>>>> range
>>>>> and then finish unwinding for this special case.
>>>>
>>>> Hi, Tiezhu,
>>>>
>>>> Since kvm_loongarch_env_init copies kvm_exc_entry which similar to how
>>>> trap_init copies the exception handler. We should apply the same
>>>> offset-based adjustment to compute the shadow PC address:
>>>>   shadow_pc = kvm_exc_entry + (cur_pc − copied_base_address)
>>>> This allows the ORC unwinder to correctly locate the corresponding 
>>>> unwind info.
>>>
>>> Thank you. I did some tests, it can unwind from kvm_handle_exit()
>>> to its previous frame kvm_exc_entry() only when CONFIG_KVM=y,
>>> but it can not unwind from kvm_handle_exit() to its previous frame 
>>> kvm_exc_entry() when CONFIG_KVM=m because we can not get the two
>>> kvm address (unsigned long)kvm_exc_entry and
>>> (unsigned long)kvm_loongarch_ops->exc_entry
>>> in arch/loongarch/kernel/unwind_orc.c.
>>
>> Use function pointer can get get the two kvm address
>> (unsigned long)kvm_exc_entry and
>> (unsigned long)kvm_loongarch_ops->exc_entry
>> in arch/loongarch/kernel/unwind_orc.c.
>>
>> I will do more test and send v2 later.
> 
> Here are the draft changes:
> 
> ----->8-----
> diff --git a/arch/loongarch/kernel/unwind_guess.c 
> b/arch/loongarch/kernel/unwind_guess.c
> index 08d7951b2f60..64c50c483cbb 100644
> --- a/arch/loongarch/kernel/unwind_guess.c
> +++ b/arch/loongarch/kernel/unwind_guess.c
> @@ -5,6 +5,11 @@
>   #include <asm/unwind.h>
>   #include <linux/export.h>
> 
> +#if IS_ENABLED(CONFIG_KVM)
> +void (*get_kvm_entry_info)(unsigned long *old, unsigned long *new, 
> unsigned long *size);
> +EXPORT_SYMBOL_GPL(get_kvm_entry_info);
> +#endif
> +
>   unsigned long unwind_get_return_address(struct unwind_state *state)
>   {
>          return __unwind_get_return_address(state);
> diff --git a/arch/loongarch/kernel/unwind_orc.c 
> b/arch/loongarch/kernel/unwind_orc.c
> index 1d60a593479a..ef8bb6cd7af8 100644
> --- a/arch/loongarch/kernel/unwind_orc.c
> +++ b/arch/loongarch/kernel/unwind_orc.c
> @@ -356,6 +356,11 @@ static bool is_entry_func(unsigned long addr)
>          return addr >= (unsigned long)&kernel_entry && addr < (unsigned 
> long)&kernel_entry_end;
>   }
> 
> +#if IS_ENABLED(CONFIG_KVM)
> +void (*get_kvm_entry_info)(unsigned long *old, unsigned long *new, 
> unsigned long *size);
> +EXPORT_SYMBOL_GPL(get_kvm_entry_info);
> +#endif
this method mixes kvm and unwind components and it is obvious hack 
method. If there are other modules which have the similar problem, how 
to handle it? Add get_MODULE_1_entry_info/get_MODULE_2_entry_info API :)

KVM module copy exception function to allocated memory, it breaks unwind 
rules. KVM can compile exception function in kernel and do not copy the 
exception functions or LoongArch kernel provides unwind hint APIs to 
handle it.

> +
>   static inline unsigned long bt_address(unsigned long ra)
>   {
>          extern unsigned long eentry;
> @@ -386,6 +391,16 @@ static inline unsigned long bt_address(unsigned 
> long ra)
>                  return func + offset;
>          }
> 
> +#if IS_ENABLED(CONFIG_KVM)
> +       unsigned long old, new, size;
> +
> +       if (get_kvm_entry_info) {
> +               get_kvm_entry_info(&old, &new, &size);
> +               if (ra >= new && ra < new + size)
> +                       return old + (ra - new);
> +       }
> +#endif
> +
>          return ra;
>   }
> 
> diff --git a/arch/loongarch/kernel/unwind_prologue.c 
> b/arch/loongarch/kernel/unwind_prologue.c
> index 729e775bd40d..42c210b0a378 100644
> --- a/arch/loongarch/kernel/unwind_prologue.c
> +++ b/arch/loongarch/kernel/unwind_prologue.c
> @@ -28,6 +28,11 @@ extern unsigned long eentry;
>   extern unsigned long pcpu_handlers[NR_CPUS];
>   #endif
> 
> +#if IS_ENABLED(CONFIG_KVM)
> +void (*get_kvm_entry_info)(unsigned long *old, unsigned long *new, 
> unsigned long *size);
> +EXPORT_SYMBOL_GPL(get_kvm_entry_info);
> +#endif
> +
>   static inline bool scan_handlers(unsigned long entry_offset)
>   {
>          int idx, offset;
> diff --git a/arch/loongarch/kvm/main.c b/arch/loongarch/kvm/main.c
> index 80ea63d465b8..3606554e43e0 100644
> --- a/arch/loongarch/kvm/main.c
> +++ b/arch/loongarch/kvm/main.c
> @@ -338,6 +338,13 @@ void kvm_arch_disable_virtualization_cpu(void)
>          kvm_flush_tlb_all();
>   }
> 
> +static void kvm_entry_info(unsigned long *old, unsigned long *new, 
> unsigned long *size)
> +{
> +       *old = (unsigned long)kvm_exc_entry;
> +       *new = (unsigned long)kvm_loongarch_ops->exc_entry;
> +       *size = kvm_exception_size;
> +}
> +
>   static int kvm_loongarch_env_init(void)
>   {
>          int cpu, order, ret;
> @@ -430,6 +437,7 @@ static void kvm_loongarch_env_exit(void)
>          kvm_unregister_perf_callbacks();
>   }
> 
> +extern void (*get_kvm_entry_info)(unsigned long *old, unsigned long 
> *new, unsigned long *size);
>   static int kvm_loongarch_init(void)
>   {
>          int r;
> @@ -442,6 +450,8 @@ static int kvm_loongarch_init(void)
>          if (r)
>                  return r;
> 
> +       get_kvm_entry_info = kvm_entry_info;
Is this API get_kvm_entry_info() general for all modules or kernel 
components?

Regards
Bibo Mao
> +
>          return kvm_init(sizeof(struct kvm_vcpu), 0, THIS_MODULE);
>   }
> 
> diff --git a/arch/loongarch/kvm/switch.S b/arch/loongarch/kvm/switch.S
> index f1768b7a6194..9eaad5dbed91 100644
> --- a/arch/loongarch/kvm/switch.S
> +++ b/arch/loongarch/kvm/switch.S
> @@ -104,7 +104,7 @@
>          .text
>          .cfi_sections   .debug_frame
>   SYM_CODE_START(kvm_exc_entry)
> -       UNWIND_HINT_UNDEFINED
> +       UNWIND_HINT_END_OF_STACK
>          csrwr   a2,   KVM_TEMP_KS
>          csrrd   a2,   KVM_VCPU_KS
>          addi.d  a2,   a2, KVM_VCPU_ARCH
> ----->8-----
> 
> I tested with config UNWINDER_ORC, it can unwind from kvm_handle_exit()
> to its previous frame kvm_exc_entry() which is the end of stack, there
> is no "unreliable stack" in debug mode and also no timeout for kernel
> livepatching.
> 
> I also tested with config UNWINDER_PROLOGUE and config UNWINDER_GUESS,
> no build errors and the virtual machine can boot normally.
> 
> I would like to receive comments for the draft changes first and then
> send the formal v2, the function and variable name may be not proper,
> so any comments are welcome.
> 
> Since the merge window is coming soon and I am busy with the other
> higher priority stuff, so maybe I will send v2 after the merge window.
> 
> Thanks,
> Tiezhu
> 

Re: [PATCH v1] LoongArch: Handle special PC in unwind_next_frame()
Posted by Tiezhu Yang 4 days, 22 hours ago
On 2025/11/26 下午5:56, Bibo Mao wrote:
> 
> 
> On 2025/11/26 下午5:09, Tiezhu Yang wrote:
>> Cc: Bibo Mao <maobibo@loongson.cn>
...
>> +#if IS_ENABLED(CONFIG_KVM)
>> +void (*get_kvm_entry_info)(unsigned long *old, unsigned long *new, 
>> unsigned long *size);
>> +EXPORT_SYMBOL_GPL(get_kvm_entry_info);
>> +#endif
> this method mixes kvm and unwind components and it is obvious hack 
> method. If there are other modules which have the similar problem, how 
> to handle it? Add get_MODULE_1_entry_info/get_MODULE_2_entry_info API :)

Currently, there is no other similar issue and something that should not
happen in the future, this is "concrete question concrete analysis" and
"handle special cases with special methods".

> KVM module copy exception function to allocated memory, it breaks unwind 
> rules. KVM can compile exception function in kernel and do not copy the 
> exception functions or LoongArch kernel provides unwind hint APIs to 
> handle it.

That is better if it is possible for KVM, no general API for kernel IMO.

>>   static inline unsigned long bt_address(unsigned long ra)
...
>> +       get_kvm_entry_info = kvm_entry_info;
> Is this API get_kvm_entry_info() general for all modules or kernel 
> components?

No, it is just to get the necessary exception info for this special KVM
case, we can use something like EXPORT_SYMBOL_FOR_KVM_INTERNAL to avoid
the potential misuse if possible (not tested yet).

Thanks,
Tiezhu

Re: [PATCH v1] LoongArch: Handle special PC in unwind_next_frame()
Posted by Bibo Mao 4 days, 22 hours ago

On 2025/11/27 上午9:39, Tiezhu Yang wrote:
> On 2025/11/26 下午5:56, Bibo Mao wrote:
>>
>>
>> On 2025/11/26 下午5:09, Tiezhu Yang wrote:
>>> Cc: Bibo Mao <maobibo@loongson.cn>
> ...
>>> +#if IS_ENABLED(CONFIG_KVM)
>>> +void (*get_kvm_entry_info)(unsigned long *old, unsigned long *new, 
>>> unsigned long *size);
>>> +EXPORT_SYMBOL_GPL(get_kvm_entry_info);
>>> +#endif
>> this method mixes kvm and unwind components and it is obvious hack 
>> method. If there are other modules which have the similar problem, how 
>> to handle it? Add get_MODULE_1_entry_info/get_MODULE_2_entry_info API :)
> 
> Currently, there is no other similar issue and something that should not
> happen in the future, this is "concrete question concrete analysis" and
> "handle special cases with special methods".
If so, I can think LoongArch unwind method is nasty. If this method is 
special for KVM module. KVM prefer to compile the exception function 
with built-in method, rather than using this nasty method.

Just be curious, it is the same orc unwind method. why is clean with 
file arch/x86/kernel/unwind_orc.c, however there is special handling 
bt_address() in file arch/loongarch/kernel/unwind_orc.c ?

> 
>> KVM module copy exception function to allocated memory, it breaks 
>> unwind rules. KVM can compile exception function in kernel and do not 
>> copy the exception functions or LoongArch kernel provides unwind hint 
>> APIs to handle it.
> 
> That is better if it is possible for KVM, no general API for kernel IMO.
> 
>>>   static inline unsigned long bt_address(unsigned long ra)
> ...
>>> +       get_kvm_entry_info = kvm_entry_info;
>> Is this API get_kvm_entry_info() general for all modules or kernel 
>> components?
> 
> No, it is just to get the necessary exception info for this special KVM
> case, we can use something like EXPORT_SYMBOL_FOR_KVM_INTERNAL to avoid
> the potential misuse if possible (not tested yet).
> 
> Thanks,
> Tiezhu

Re: [PATCH v1] LoongArch: Handle special PC in unwind_next_frame()
Posted by Jinyang He 4 days, 21 hours ago
On 2025-11-27 09:53, Bibo Mao wrote:

>
> Just be curious, it is the same orc unwind method. why is clean with 
> file arch/x86/kernel/unwind_orc.c, however there is special handling 
> bt_address() in file arch/loongarch/kernel/unwind_orc.c ?
>
I'm not familiar with x86. Does it also copies exception handler to
other address like LoongArch? When backtrace to the copied exception
handler, its ORC info is not collected. The bt_address finds a
shadow PC to get the right ORC info and go on.

Thanks,
Jinyang
Re: [PATCH v1] LoongArch: Handle special PC in unwind_next_frame()
Posted by Bibo Mao 4 days, 21 hours ago

On 2025/11/27 上午10:53, Jinyang He wrote:
> On 2025-11-27 09:53, Bibo Mao wrote:
> 
>>
>> Just be curious, it is the same orc unwind method. why is clean with 
>> file arch/x86/kernel/unwind_orc.c, however there is special handling 
>> bt_address() in file arch/loongarch/kernel/unwind_orc.c ?
>>
> I'm not familiar with x86. Does it also copies exception handler to
> other address like LoongArch? When backtrace to the copied exception
> handler, its ORC info is not collected. The bt_address finds a
> shadow PC to get the right ORC info and go on.
I am not familiar with x86 and ORC also. So can ORC unwind handle copied 
text also? If not, why not disable text copy or provide general API to 
handle this.

Regards
Bibo Mao
> 
> Thanks,
> Jinyang
> 

Re: [PATCH v1] LoongArch: Handle special PC in unwind_next_frame()
Posted by Huacai Chen 5 days, 14 hours ago
On Wed, Nov 26, 2025 at 5:09 PM Tiezhu Yang <yangtiezhu@loongson.cn> wrote:
>
> Cc: Bibo Mao <maobibo@loongson.cn>
>
> On 2025/11/26 下午2:28, Tiezhu Yang wrote:
> > On 2025/11/26 下午2:08, Tiezhu Yang wrote:
> >> On 2025/11/25 下午6:52, Jinyang He wrote:
> >>> On 2025-11-25 14:33, Tiezhu Yang wrote:
> >>>
> >>>> When running virtual machine before testing the kernel live patching
> >>>> with
> >>>> "modprobe livepatch-sample", there is a timeout over 15 seconds, the
> >>>> dmesg
> >>>> command shows "unreliable stack" for user tasks in debug mode.
> >>>>
> >>>> The "unreliable stack" is because it can not unwind from
> >>>> kvm_handle_exit()
> >>>> to its previous frame kvm_exc_entry() due to the PC is not a valid
> >>>> kernel
> >>>> address, the root cause is that the code of kvm_exc_entry() was
> >>>> copied to
> >>>> the DMW area in kvm_loongarch_env_init(), so it should check the PC
> >>>> range
> >>>> and then finish unwinding for this special case.
> >>>
> >>> Hi, Tiezhu,
> >>>
> >>> Since kvm_loongarch_env_init copies kvm_exc_entry which similar to how
> >>> trap_init copies the exception handler. We should apply the same
> >>> offset-based adjustment to compute the shadow PC address:
> >>> shadow_pc = kvm_exc_entry + (cur_pc − copied_base_address)
> >>> This allows the ORC unwinder to correctly locate the corresponding
> >>> unwind info.
> >>
> >> Thank you. I did some tests, it can unwind from kvm_handle_exit()
> >> to its previous frame kvm_exc_entry() only when CONFIG_KVM=y,
> >> but it can not unwind from kvm_handle_exit() to its previous frame
> >> kvm_exc_entry() when CONFIG_KVM=m because we can not get the two
> >> kvm address (unsigned long)kvm_exc_entry and
> >> (unsigned long)kvm_loongarch_ops->exc_entry
> >> in arch/loongarch/kernel/unwind_orc.c.
> >
> > Use function pointer can get get the two kvm address
> > (unsigned long)kvm_exc_entry and
> > (unsigned long)kvm_loongarch_ops->exc_entry
> > in arch/loongarch/kernel/unwind_orc.c.
> >
> > I will do more test and send v2 later.
>
> Here are the draft changes:
>
> ----->8-----
> diff --git a/arch/loongarch/kernel/unwind_guess.c
> b/arch/loongarch/kernel/unwind_guess.c
> index 08d7951b2f60..64c50c483cbb 100644
> --- a/arch/loongarch/kernel/unwind_guess.c
> +++ b/arch/loongarch/kernel/unwind_guess.c
> @@ -5,6 +5,11 @@
>   #include <asm/unwind.h>
>   #include <linux/export.h>
>
> +#if IS_ENABLED(CONFIG_KVM)
> +void (*get_kvm_entry_info)(unsigned long *old, unsigned long *new,
> unsigned long *size);
> +EXPORT_SYMBOL_GPL(get_kvm_entry_info);
> +#endif
Define in unwind.c then you don't need to duplicate it.

> +
>   unsigned long unwind_get_return_address(struct unwind_state *state)
>   {
>          return __unwind_get_return_address(state);
> diff --git a/arch/loongarch/kernel/unwind_orc.c
> b/arch/loongarch/kernel/unwind_orc.c
> index 1d60a593479a..ef8bb6cd7af8 100644
> --- a/arch/loongarch/kernel/unwind_orc.c
> +++ b/arch/loongarch/kernel/unwind_orc.c
> @@ -356,6 +356,11 @@ static bool is_entry_func(unsigned long addr)
>          return addr >= (unsigned long)&kernel_entry && addr < (unsigned
> long)&kernel_entry_end;
>   }
>
> +#if IS_ENABLED(CONFIG_KVM)
> +void (*get_kvm_entry_info)(unsigned long *old, unsigned long *new,
> unsigned long *size);
> +EXPORT_SYMBOL_GPL(get_kvm_entry_info);
> +#endif
> +
>   static inline unsigned long bt_address(unsigned long ra)
>   {
>          extern unsigned long eentry;
> @@ -386,6 +391,16 @@ static inline unsigned long bt_address(unsigned
> long ra)
>                  return func + offset;
>          }
>
> +#if IS_ENABLED(CONFIG_KVM)
> +       unsigned long old, new, size;
Define them in the if block, and you can consider removing all "#if
IS_ENABLED(CONFIG_KVM)".


Huacai

> +
> +       if (get_kvm_entry_info) {
> +               get_kvm_entry_info(&old, &new, &size);
> +               if (ra >= new && ra < new + size)
> +                       return old + (ra - new);
> +       }
> +#endif
> +
>          return ra;
>   }
>
> diff --git a/arch/loongarch/kernel/unwind_prologue.c
> b/arch/loongarch/kernel/unwind_prologue.c
> index 729e775bd40d..42c210b0a378 100644
> --- a/arch/loongarch/kernel/unwind_prologue.c
> +++ b/arch/loongarch/kernel/unwind_prologue.c
> @@ -28,6 +28,11 @@ extern unsigned long eentry;
>   extern unsigned long pcpu_handlers[NR_CPUS];
>   #endif
>
> +#if IS_ENABLED(CONFIG_KVM)
> +void (*get_kvm_entry_info)(unsigned long *old, unsigned long *new,
> unsigned long *size);
> +EXPORT_SYMBOL_GPL(get_kvm_entry_info);
> +#endif
> +
>   static inline bool scan_handlers(unsigned long entry_offset)
>   {
>          int idx, offset;
> diff --git a/arch/loongarch/kvm/main.c b/arch/loongarch/kvm/main.c
> index 80ea63d465b8..3606554e43e0 100644
> --- a/arch/loongarch/kvm/main.c
> +++ b/arch/loongarch/kvm/main.c
> @@ -338,6 +338,13 @@ void kvm_arch_disable_virtualization_cpu(void)
>          kvm_flush_tlb_all();
>   }
>
> +static void kvm_entry_info(unsigned long *old, unsigned long *new,
> unsigned long *size)
> +{
> +       *old = (unsigned long)kvm_exc_entry;
> +       *new = (unsigned long)kvm_loongarch_ops->exc_entry;
> +       *size = kvm_exception_size;
> +}
> +
>   static int kvm_loongarch_env_init(void)
>   {
>          int cpu, order, ret;
> @@ -430,6 +437,7 @@ static void kvm_loongarch_env_exit(void)
>          kvm_unregister_perf_callbacks();
>   }
>
> +extern void (*get_kvm_entry_info)(unsigned long *old, unsigned long
> *new, unsigned long *size);
>   static int kvm_loongarch_init(void)
>   {
>          int r;
> @@ -442,6 +450,8 @@ static int kvm_loongarch_init(void)
>          if (r)
>                  return r;
>
> +       get_kvm_entry_info = kvm_entry_info;
> +
>          return kvm_init(sizeof(struct kvm_vcpu), 0, THIS_MODULE);
>   }
>
> diff --git a/arch/loongarch/kvm/switch.S b/arch/loongarch/kvm/switch.S
> index f1768b7a6194..9eaad5dbed91 100644
> --- a/arch/loongarch/kvm/switch.S
> +++ b/arch/loongarch/kvm/switch.S
> @@ -104,7 +104,7 @@
>          .text
>          .cfi_sections   .debug_frame
>   SYM_CODE_START(kvm_exc_entry)
> -       UNWIND_HINT_UNDEFINED
> +       UNWIND_HINT_END_OF_STACK
>          csrwr   a2,   KVM_TEMP_KS
>          csrrd   a2,   KVM_VCPU_KS
>          addi.d  a2,   a2, KVM_VCPU_ARCH
> ----->8-----
>
> I tested with config UNWINDER_ORC, it can unwind from kvm_handle_exit()
> to its previous frame kvm_exc_entry() which is the end of stack, there
> is no "unreliable stack" in debug mode and also no timeout for kernel
> livepatching.
>
> I also tested with config UNWINDER_PROLOGUE and config UNWINDER_GUESS,
> no build errors and the virtual machine can boot normally.
>
> I would like to receive comments for the draft changes first and then
> send the formal v2, the function and variable name may be not proper,
> so any comments are welcome.
>
> Since the merge window is coming soon and I am busy with the other
> higher priority stuff, so maybe I will send v2 after the merge window.
>
> Thanks,
> Tiezhu
>
Re: [PATCH v1] LoongArch: Handle special PC in unwind_next_frame()
Posted by Tiezhu Yang 4 days, 22 hours ago
On 2025/11/26 下午5:27, Huacai Chen wrote:
> On Wed, Nov 26, 2025 at 5:09 PM Tiezhu Yang <yangtiezhu@loongson.cn> wrote:
...
>> +#if IS_ENABLED(CONFIG_KVM)
>> +void (*get_kvm_entry_info)(unsigned long *old, unsigned long *new,
>> unsigned long *size);
>> +EXPORT_SYMBOL_GPL(get_kvm_entry_info);
>> +#endif
> Define in unwind.c then you don't need to duplicate it.

OK, makes sense.

>>    unsigned long unwind_get_return_address(struct unwind_state *state)
...
>> +#if IS_ENABLED(CONFIG_KVM)
>> +       unsigned long old, new, size;
> Define them in the if block, and you can consider removing all "#if
> IS_ENABLED(CONFIG_KVM)".

OK, will do it in the next version.

Thanks,
Tiezhu

Re: [PATCH v1] LoongArch: Handle special PC in unwind_next_frame()
Posted by Huacai Chen 6 days, 15 hours ago
Hi, Tiezhu,

On Tue, Nov 25, 2025 at 2:34 PM Tiezhu Yang <yangtiezhu@loongson.cn> wrote:
>
> When running virtual machine before testing the kernel live patching with
> "modprobe livepatch-sample", there is a timeout over 15 seconds, the dmesg
> command shows "unreliable stack" for user tasks in debug mode.
>
> The "unreliable stack" is because it can not unwind from kvm_handle_exit()
> to its previous frame kvm_exc_entry() due to the PC is not a valid kernel
> address, the root cause is that the code of kvm_exc_entry() was copied to
> the DMW area in kvm_loongarch_env_init(), so it should check the PC range
> and then finish unwinding for this special case.
>
> How to test:
>
> (1) Update kernel with LIVEPATCH
>
>   git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
>   cd linux && make mrproper defconfig
>   scripts/config -e FTRACE -e FUNCTION_TRACER \
>   -e LIVEPATCH -e SAMPLES -m SAMPLE_LIVEPATCH
>   make olddefconfig all -j"$(nproc)"
>   sudo make modules_install
>   sudo make install
>   sudo reboot
>
> (2) Set up a VM with "-accel kvm", no need to specify kernel and initrd
>
>   sudo yum -y install edk2-loongarch64 qemu
>   qemu-system-loongarch64 -serial stdio \
>   -machine virt -cpu la464 -smp 8 -m 4G \
>   -bios /usr/share/edk2/loongarch64/QEMU_EFI.fd \
>   -nodefaults -no-reboot -nographic -accel kvm
>
> (3) Test the kernel live patching
>
>   cat /proc/cmdline
>   sudo modprobe livepatch-sample
>   cat /proc/cmdline
>   sudo sh -c "echo 0 > /sys/kernel/livepatch/livepatch_sample/enabled"
>   sudo rmmod livepatch_sample
>   cat /proc/cmdline
>   dmesg -T
>
> Cc: stable@vger.kernel.org # v6.9+
> Fixes: cb8a2ef0848c ("LoongArch: Add ORC stack unwinder support")
> Reported-by: Xi Zhang <zhangxi@kylinos.cn>
> Reported-by: Xianglai Li <lixianglai@loongson.cn>
> Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
> ---
>  arch/loongarch/kernel/unwind_orc.c | 3 +++
>  1 file changed, 3 insertions(+)
>
> diff --git a/arch/loongarch/kernel/unwind_orc.c b/arch/loongarch/kernel/unwind_orc.c
> index 0d5fa64a2225..1d60a593479a 100644
> --- a/arch/loongarch/kernel/unwind_orc.c
> +++ b/arch/loongarch/kernel/unwind_orc.c
> @@ -506,6 +506,9 @@ bool unwind_next_frame(struct unwind_state *state)
>                 goto err;
>         }
>
> +       if (pc >= (unsigned long)_end && pc < (unsigned long)XKVRANGE)
> +               goto end;
The __kernel_text_address() judgement after bt_address() do the same
thing exactly, so why do we need this?

Huacai

> +
>         state->pc = bt_address(pc);
>         if (!state->pc) {
>                 pr_err("cannot find unwind pc at %p\n", (void *)pc);
> --
> 2.42.0
>
>
Re: [PATCH v1] LoongArch: Handle special PC in unwind_next_frame()
Posted by Tiezhu Yang 6 days, 15 hours ago
On 2025/11/25 下午4:08, Huacai Chen wrote:
> Hi, Tiezhu,
> 
> On Tue, Nov 25, 2025 at 2:34 PM Tiezhu Yang <yangtiezhu@loongson.cn> wrote:
>>
>> When running virtual machine before testing the kernel live patching with
>> "modprobe livepatch-sample", there is a timeout over 15 seconds, the dmesg
>> command shows "unreliable stack" for user tasks in debug mode.
>>
>> The "unreliable stack" is because it can not unwind from kvm_handle_exit()
>> to its previous frame kvm_exc_entry() due to the PC is not a valid kernel
>> address, the root cause is that the code of kvm_exc_entry() was copied to
>> the DMW area in kvm_loongarch_env_init(), so it should check the PC range
>> and then finish unwinding for this special case.
>>
>> How to test:
>>
>> (1) Update kernel with LIVEPATCH
>>
>>    git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
>>    cd linux && make mrproper defconfig
>>    scripts/config -e FTRACE -e FUNCTION_TRACER \
>>    -e LIVEPATCH -e SAMPLES -m SAMPLE_LIVEPATCH
>>    make olddefconfig all -j"$(nproc)"
>>    sudo make modules_install
>>    sudo make install
>>    sudo reboot
>>
>> (2) Set up a VM with "-accel kvm", no need to specify kernel and initrd
>>
>>    sudo yum -y install edk2-loongarch64 qemu
>>    qemu-system-loongarch64 -serial stdio \
>>    -machine virt -cpu la464 -smp 8 -m 4G \
>>    -bios /usr/share/edk2/loongarch64/QEMU_EFI.fd \
>>    -nodefaults -no-reboot -nographic -accel kvm
>>
>> (3) Test the kernel live patching
>>
>>    cat /proc/cmdline
>>    sudo modprobe livepatch-sample
>>    cat /proc/cmdline
>>    sudo sh -c "echo 0 > /sys/kernel/livepatch/livepatch_sample/enabled"
>>    sudo rmmod livepatch_sample
>>    cat /proc/cmdline
>>    dmesg -T
>>
>> Cc: stable@vger.kernel.org # v6.9+
>> Fixes: cb8a2ef0848c ("LoongArch: Add ORC stack unwinder support")
>> Reported-by: Xi Zhang <zhangxi@kylinos.cn>
>> Reported-by: Xianglai Li <lixianglai@loongson.cn>
>> Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
>> ---
>>   arch/loongarch/kernel/unwind_orc.c | 3 +++
>>   1 file changed, 3 insertions(+)
>>
>> diff --git a/arch/loongarch/kernel/unwind_orc.c b/arch/loongarch/kernel/unwind_orc.c
>> index 0d5fa64a2225..1d60a593479a 100644
>> --- a/arch/loongarch/kernel/unwind_orc.c
>> +++ b/arch/loongarch/kernel/unwind_orc.c
>> @@ -506,6 +506,9 @@ bool unwind_next_frame(struct unwind_state *state)
>>                  goto err;
>>          }
>>
>> +       if (pc >= (unsigned long)_end && pc < (unsigned long)XKVRANGE)
>> +               goto end;
> The __kernel_text_address() judgement after bt_address() do the same
> thing exactly, so why do we need this?

They are different code paths, the current path is "goto err", it will
set state->error as true, then arch_stack_walk_reliable() will return
-EINVAL.

With this patch, the code path is "goto end" for this case, it will
not set state->error as true, then arch_stack_walk_reliable() will
return 0.

Thanks,
Tiezhu

Re: [PATCH v1] LoongArch: Handle special PC in unwind_next_frame()
Posted by Huacai Chen 6 days, 14 hours ago
On Tue, Nov 25, 2025 at 4:54 PM Tiezhu Yang <yangtiezhu@loongson.cn> wrote:
>
> On 2025/11/25 下午4:08, Huacai Chen wrote:
> > Hi, Tiezhu,
> >
> > On Tue, Nov 25, 2025 at 2:34 PM Tiezhu Yang <yangtiezhu@loongson.cn> wrote:
> >>
> >> When running virtual machine before testing the kernel live patching with
> >> "modprobe livepatch-sample", there is a timeout over 15 seconds, the dmesg
> >> command shows "unreliable stack" for user tasks in debug mode.
> >>
> >> The "unreliable stack" is because it can not unwind from kvm_handle_exit()
> >> to its previous frame kvm_exc_entry() due to the PC is not a valid kernel
> >> address, the root cause is that the code of kvm_exc_entry() was copied to
> >> the DMW area in kvm_loongarch_env_init(), so it should check the PC range
> >> and then finish unwinding for this special case.
> >>
> >> How to test:
> >>
> >> (1) Update kernel with LIVEPATCH
> >>
> >>    git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
> >>    cd linux && make mrproper defconfig
> >>    scripts/config -e FTRACE -e FUNCTION_TRACER \
> >>    -e LIVEPATCH -e SAMPLES -m SAMPLE_LIVEPATCH
> >>    make olddefconfig all -j"$(nproc)"
> >>    sudo make modules_install
> >>    sudo make install
> >>    sudo reboot
> >>
> >> (2) Set up a VM with "-accel kvm", no need to specify kernel and initrd
> >>
> >>    sudo yum -y install edk2-loongarch64 qemu
> >>    qemu-system-loongarch64 -serial stdio \
> >>    -machine virt -cpu la464 -smp 8 -m 4G \
> >>    -bios /usr/share/edk2/loongarch64/QEMU_EFI.fd \
> >>    -nodefaults -no-reboot -nographic -accel kvm
> >>
> >> (3) Test the kernel live patching
> >>
> >>    cat /proc/cmdline
> >>    sudo modprobe livepatch-sample
> >>    cat /proc/cmdline
> >>    sudo sh -c "echo 0 > /sys/kernel/livepatch/livepatch_sample/enabled"
> >>    sudo rmmod livepatch_sample
> >>    cat /proc/cmdline
> >>    dmesg -T
> >>
> >> Cc: stable@vger.kernel.org # v6.9+
> >> Fixes: cb8a2ef0848c ("LoongArch: Add ORC stack unwinder support")
> >> Reported-by: Xi Zhang <zhangxi@kylinos.cn>
> >> Reported-by: Xianglai Li <lixianglai@loongson.cn>
> >> Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
> >> ---
> >>   arch/loongarch/kernel/unwind_orc.c | 3 +++
> >>   1 file changed, 3 insertions(+)
> >>
> >> diff --git a/arch/loongarch/kernel/unwind_orc.c b/arch/loongarch/kernel/unwind_orc.c
> >> index 0d5fa64a2225..1d60a593479a 100644
> >> --- a/arch/loongarch/kernel/unwind_orc.c
> >> +++ b/arch/loongarch/kernel/unwind_orc.c
> >> @@ -506,6 +506,9 @@ bool unwind_next_frame(struct unwind_state *state)
> >>                  goto err;
> >>          }
> >>
> >> +       if (pc >= (unsigned long)_end && pc < (unsigned long)XKVRANGE)
> >> +               goto end;
> > The __kernel_text_address() judgement after bt_address() do the same
> > thing exactly, so why do we need this?
>
> They are different code paths, the current path is "goto err", it will
> set state->error as true, then arch_stack_walk_reliable() will return
> -EINVAL.
>
> With this patch, the code path is "goto end" for this case, it will
> not set state->error as true, then arch_stack_walk_reliable() will
> return 0.
Then can we replace "goto err" with "goto end" at  __kernel_text_address()?

Huacai

>
> Thanks,
> Tiezhu
>
Re: [PATCH v1] LoongArch: Handle special PC in unwind_next_frame()
Posted by Tiezhu Yang 5 days, 18 hours ago
On 2025/11/25 下午5:05, Huacai Chen wrote:
> On Tue, Nov 25, 2025 at 4:54 PM Tiezhu Yang <yangtiezhu@loongson.cn> wrote:

...

>> They are different code paths, the current path is "goto err", it will
>> set state->error as true, then arch_stack_walk_reliable() will return
>> -EINVAL.
>>
>> With this patch, the code path is "goto end" for this case, it will
>> not set state->error as true, then arch_stack_walk_reliable() will
>> return 0.
> Then can we replace "goto err" with "goto end" at  __kernel_text_address()?

No, this "goto err" path is useful to indicate that there is
something wrong.

Thanks,
Tiezhu