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:
parent
812397ffd9
commit
5ab0674c38
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user