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:
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user