[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <45cf4a09-8895-73fb-c019-1b1f88501eed@loongson.cn>
Date: Wed, 26 Nov 2025 17:09:16 +0800
From: Tiezhu Yang <yangtiezhu@...ngson.cn>
To: Jinyang He <hejinyang@...ngson.cn>
Cc: Huacai Chen <chenhuacai@...nel.org>, Xi Zhang <zhangxi@...inos.cn>,
Xianglai Li <lixianglai@...ngson.cn>, loongarch@...ts.linux.dev,
linux-kernel@...r.kernel.org, Bibo Mao <maobibo@...ngson.cn>
Subject: Re: [PATCH v1] LoongArch: Handle special PC in unwind_next_frame()
Cc: Bibo Mao <maobibo@...ngson.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
Powered by blists - more mailing lists