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 <kallisti5@unixzen.com>
This commit is contained in:
X512 2021-10-07 22:31:24 +09:00 committed by Alex von Gluck IV
parent 812397ffd9
commit 5ab0674c38
3 changed files with 30 additions and 19 deletions

View File

@ -10,9 +10,7 @@
# error Must not be included directly. Include <commpage_defs.h> 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 */

View File

@ -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;

View File

@ -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;
}