From 5ab0674c3881a8852bb21ecc34e657d02ca890be Mon Sep 17 00:00:00 2001 From: X512 Date: Thu, 7 Oct 2021 22:31:24 +0900 Subject: [PATCH] kernel/arch/riscv64: fix crash on userland thread exit Set first stack frame return address to commpage_thread_exit, so it will be called when thread entry point returns. Change-Id: Ide5cde8d4501eb7241e03ff4052174e984e78870 Reviewed-on: https://review.haiku-os.org/c/haiku/+/4493 Reviewed-by: Alex von Gluck IV --- .../system/arch/riscv64/arch_commpage_defs.h | 6 +-- .../kernel/arch/riscv64/arch_commpage.cpp | 2 +- .../kernel/arch/riscv64/arch_thread.cpp | 41 ++++++++++++------- 3 files changed, 30 insertions(+), 19 deletions(-) diff --git a/headers/private/system/arch/riscv64/arch_commpage_defs.h b/headers/private/system/arch/riscv64/arch_commpage_defs.h index df081b57e6..8a9b260231 100644 --- a/headers/private/system/arch/riscv64/arch_commpage_defs.h +++ b/headers/private/system/arch/riscv64/arch_commpage_defs.h @@ -10,9 +10,7 @@ # error Must not be included directly. Include instead! #endif -#define COMMPAGE_ENTRY_RISCV64_SIGNAL_HANDLER \ - (COMMPAGE_ENTRY_FIRST_ARCH_SPECIFIC + 0) -#define COMMPAGE_ENTRY_RISCV64_SIGNAL_THREAD_EXIT \ - (COMMPAGE_ENTRY_FIRST_ARCH_SPECIFIC + 1) +#define COMMPAGE_ENTRY_RISCV64_SIGNAL_HANDLER (COMMPAGE_ENTRY_FIRST_ARCH_SPECIFIC + 0) +#define COMMPAGE_ENTRY_RISCV64_THREAD_EXIT (COMMPAGE_ENTRY_FIRST_ARCH_SPECIFIC + 1) #endif /* _SYSTEM_ARCH_RISCV64_COMMPAGE_DEFS_H */ diff --git a/src/system/kernel/arch/riscv64/arch_commpage.cpp b/src/system/kernel/arch/riscv64/arch_commpage.cpp index e604192902..6a5c039aba 100644 --- a/src/system/kernel/arch/riscv64/arch_commpage.cpp +++ b/src/system/kernel/arch/riscv64/arch_commpage.cpp @@ -83,7 +83,7 @@ arch_commpage_init_post_cpus(void) (addr_t)&arch_user_signal_handler); register_commpage_function("arch_user_thread_exit", - COMMPAGE_ENTRY_RISCV64_SIGNAL_THREAD_EXIT, "commpage_thread_exit", + COMMPAGE_ENTRY_RISCV64_THREAD_EXIT, "commpage_thread_exit", (addr_t)&arch_user_thread_exit); return B_OK; diff --git a/src/system/kernel/arch/riscv64/arch_thread.cpp b/src/system/kernel/arch/riscv64/arch_thread.cpp index 8b25641aa5..f57ce7853e 100644 --- a/src/system/kernel/arch/riscv64/arch_thread.cpp +++ b/src/system/kernel/arch/riscv64/arch_thread.cpp @@ -127,22 +127,35 @@ status_t arch_thread_enter_userspace(Thread *thread, addr_t entry, void *arg1, void *arg2) { - // dprintf("arch_thread_enter_uspace()\n"); + //dprintf("arch_thread_enter_uspace(%" B_PRId32 "(%s))\n", thread->id, thread->name); + + addr_t commpageAdr = (addr_t)thread->team->commpage_address; + addr_t threadExitAddr; + ASSERT(user_memcpy(&threadExitAddr, + &((addr_t*)commpageAdr)[COMMPAGE_ENTRY_RISCV64_THREAD_EXIT], + sizeof(threadExitAddr)) >= B_OK); + threadExitAddr += commpageAdr; disable_interrupts(); - if (arch_setjmp(&thread->arch_info.context) == 0) { - SstatusReg status(Sstatus()); - status.pie = (1 << modeS); // enable interrupts when enter userspace - status.spp = modeU; - SetSstatus(status.val); - SetStvec((addr_t)SVecU); - SetSepc(entry); - RestoreUserRegs(); - arch_enter_userspace(arg1, arg2, - thread->user_stack_base + thread->user_stack_size); - } else { - panic("return from userspace"); - } + + iframe frame; + memset(&frame, 0, sizeof(frame)); + + SstatusReg status(Sstatus()); + status.pie = (1 << modeS); // enable interrupts when enter userspace + status.spp = modeU; + SetSstatus(status.val); + + frame.epc = entry; + frame.a0 = (addr_t)arg1; + frame.a1 = (addr_t)arg2; + frame.ra = threadExitAddr; + frame.sp = thread->user_stack_base + thread->user_stack_size; + frame.tp = thread->user_local_storage; + + arch_longjmp_iframe(&frame); + + // never return return B_ERROR; }