kernel/arch/riscv64: fix crash on userland thread exit

Set first stack frame return address to
<commpage>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 <[email protected]>
This commit is contained in:
X512
2021-10-11 17:38:20 +00:00
committed by Alex von Gluck IV
parent 812397ffd9
commit 5ab0674c38
3 changed files with 30 additions and 19 deletions
@@ -10,9 +10,7 @@
# error Must not be included directly. Include <commpage_defs.h> instead! # error Must not be included directly. Include <commpage_defs.h> instead!
#endif #endif
#define COMMPAGE_ENTRY_RISCV64_SIGNAL_HANDLER \ #define COMMPAGE_ENTRY_RISCV64_SIGNAL_HANDLER (COMMPAGE_ENTRY_FIRST_ARCH_SPECIFIC + 0)
(COMMPAGE_ENTRY_FIRST_ARCH_SPECIFIC + 0) #define COMMPAGE_ENTRY_RISCV64_THREAD_EXIT (COMMPAGE_ENTRY_FIRST_ARCH_SPECIFIC + 1)
#define COMMPAGE_ENTRY_RISCV64_SIGNAL_THREAD_EXIT \
(COMMPAGE_ENTRY_FIRST_ARCH_SPECIFIC + 1)
#endif /* _SYSTEM_ARCH_RISCV64_COMMPAGE_DEFS_H */ #endif /* _SYSTEM_ARCH_RISCV64_COMMPAGE_DEFS_H */
@@ -83,7 +83,7 @@ arch_commpage_init_post_cpus(void)
(addr_t)&arch_user_signal_handler); (addr_t)&arch_user_signal_handler);
register_commpage_function("arch_user_thread_exit", 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); (addr_t)&arch_user_thread_exit);
return B_OK; return B_OK;
+27 -14
View File
@@ -127,22 +127,35 @@ status_t
arch_thread_enter_userspace(Thread *thread, addr_t entry, void *arg1, arch_thread_enter_userspace(Thread *thread, addr_t entry, void *arg1,
void *arg2) 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(); disable_interrupts();
if (arch_setjmp(&thread->arch_info.context) == 0) {
SstatusReg status(Sstatus()); iframe frame;
status.pie = (1 << modeS); // enable interrupts when enter userspace memset(&frame, 0, sizeof(frame));
status.spp = modeU;
SetSstatus(status.val); SstatusReg status(Sstatus());
SetStvec((addr_t)SVecU); status.pie = (1 << modeS); // enable interrupts when enter userspace
SetSepc(entry); status.spp = modeU;
RestoreUserRegs(); SetSstatus(status.val);
arch_enter_userspace(arg1, arg2,
thread->user_stack_base + thread->user_stack_size); frame.epc = entry;
} else { frame.a0 = (addr_t)arg1;
panic("return from userspace"); 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; return B_ERROR;
} }