2022-12-07 14:02:46 +00:00
|
|
|
#include "thread/Thread.h"
|
2023-07-10 17:46:57 +00:00
|
|
|
#include "Log.h"
|
|
|
|
#include "memory/MemoryManager.h"
|
|
|
|
#include <luna/Alignment.h>
|
2022-12-16 19:40:04 +00:00
|
|
|
#include <luna/CString.h>
|
2023-07-10 17:46:57 +00:00
|
|
|
#include <luna/Check.h>
|
2022-12-07 14:02:46 +00:00
|
|
|
|
|
|
|
bool is_in_kernel(Registers* regs)
|
|
|
|
{
|
|
|
|
return regs->cs == 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Thread::set_ip(u64 ip)
|
|
|
|
{
|
|
|
|
regs.rip = ip;
|
|
|
|
}
|
|
|
|
|
|
|
|
u64 Thread::ip()
|
|
|
|
{
|
|
|
|
return regs.rip;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Thread::set_sp(u64 sp)
|
|
|
|
{
|
|
|
|
regs.rsp = sp;
|
|
|
|
}
|
|
|
|
|
|
|
|
u64 Thread::sp()
|
|
|
|
{
|
|
|
|
return regs.rsp;
|
|
|
|
}
|
|
|
|
|
2023-03-18 22:45:48 +00:00
|
|
|
void Thread::set_return(u64 ret)
|
|
|
|
{
|
|
|
|
regs.rax = ret;
|
|
|
|
}
|
|
|
|
|
2023-07-10 17:46:57 +00:00
|
|
|
u64 Thread::return_register()
|
|
|
|
{
|
|
|
|
return regs.rax;
|
|
|
|
}
|
|
|
|
|
2022-12-07 14:02:46 +00:00
|
|
|
void Thread::init_regs_kernel()
|
|
|
|
{
|
|
|
|
memset(®s, 0, sizeof(Registers));
|
|
|
|
regs.cs = 0x08;
|
|
|
|
regs.ss = 0x10;
|
2022-12-07 14:55:58 +00:00
|
|
|
regs.rflags = 1 << 9; // IF (Interrupt enable flag)
|
2022-12-07 14:02:46 +00:00
|
|
|
}
|
|
|
|
|
2022-12-26 11:46:07 +00:00
|
|
|
void Thread::init_regs_user()
|
|
|
|
{
|
|
|
|
memset(®s, 0, sizeof(Registers));
|
|
|
|
regs.cs = 0x18 | 3;
|
|
|
|
regs.ss = 0x20 | 3;
|
|
|
|
regs.rflags = 1 << 9; // IF (Interrupt enable flag)
|
|
|
|
}
|
|
|
|
|
2022-12-07 14:02:46 +00:00
|
|
|
void Thread::set_arguments(u64 arg1, u64 arg2, u64 arg3, u64 arg4)
|
|
|
|
{
|
|
|
|
regs.rdi = arg1;
|
|
|
|
regs.rsi = arg2;
|
|
|
|
regs.rdx = arg3;
|
|
|
|
regs.rcx = arg4;
|
|
|
|
}
|
|
|
|
|
|
|
|
void switch_context(Thread* old_thread, Thread* new_thread, Registers* regs)
|
|
|
|
{
|
2022-12-07 14:14:58 +00:00
|
|
|
if (!old_thread->is_idle()) memcpy(&old_thread->regs, regs, sizeof(Registers));
|
2022-12-07 14:02:46 +00:00
|
|
|
|
|
|
|
memcpy(regs, &new_thread->regs, sizeof(Registers));
|
2023-01-02 12:07:29 +00:00
|
|
|
}
|
2023-07-10 17:46:57 +00:00
|
|
|
|
|
|
|
// FIXME: Move this function to a common location (also used in ThreadImage)
|
|
|
|
Result<u64> Thread::push_mem_on_stack(const u8* mem, usize size)
|
|
|
|
{
|
|
|
|
if ((regs.rsp - size) < stack.bottom()) return err(E2BIG);
|
|
|
|
|
|
|
|
if (!MemoryManager::validate_user_write((void*)(regs.rsp - size), size)) return err(EFAULT);
|
|
|
|
|
|
|
|
regs.rsp -= size;
|
|
|
|
|
|
|
|
memcpy((void*)regs.rsp, mem, size);
|
|
|
|
|
|
|
|
return regs.rsp;
|
|
|
|
}
|
|
|
|
|
|
|
|
Result<u64> Thread::pop_mem_from_stack(u8* mem, usize size)
|
|
|
|
{
|
|
|
|
if ((regs.rsp + size) > stack.top()) return err(E2BIG);
|
|
|
|
|
|
|
|
if (!MemoryManager::validate_user_read((void*)regs.rsp, size)) return err(EFAULT);
|
|
|
|
|
|
|
|
memcpy(mem, (void*)regs.rsp, size);
|
|
|
|
|
|
|
|
regs.rsp += size;
|
|
|
|
|
|
|
|
return regs.rsp;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Thread::deliver_signal(int signo, Registers* current_regs)
|
|
|
|
{
|
|
|
|
auto handler = signal_handlers[signo - 1];
|
|
|
|
check(handler.sa_handler != SIG_IGN);
|
|
|
|
check(handler.sa_handler != SIG_DFL);
|
|
|
|
|
|
|
|
memcpy(®s, current_regs, sizeof(regs));
|
|
|
|
|
|
|
|
kinfoln("signal: delivering signal %d for thread %ld, ip=%p, sp=%p, handler=%p, sigreturn=%p", signo, id,
|
|
|
|
(void*)regs.rip, (void*)regs.rsp, (void*)handler.sa_handler, (void*)handler.__sa_sigreturn);
|
|
|
|
|
|
|
|
regs.rsp -= 128; // Skip the red zone
|
|
|
|
|
2023-07-15 09:53:50 +00:00
|
|
|
fp_data.save();
|
|
|
|
|
2023-07-10 17:46:57 +00:00
|
|
|
if (push_mem_on_stack((u8*)current_regs, sizeof(*current_regs)).has_error()) return false;
|
|
|
|
if (push_mem_on_stack((u8*)&signal_mask, sizeof(signal_mask)).has_error()) return false;
|
2023-07-15 09:53:50 +00:00
|
|
|
if (push_mem_on_stack((u8*)fp_data.data(), fp_data.size()).has_error()) return false;
|
2023-07-10 17:46:57 +00:00
|
|
|
|
|
|
|
u64 rsp = regs.rsp;
|
|
|
|
|
|
|
|
regs.rsp = align_down<16>(regs.rsp);
|
|
|
|
if (push_mem_on_stack((u8*)&rsp, sizeof(u64)).has_error()) return false;
|
|
|
|
if (push_mem_on_stack((u8*)&handler.__sa_sigreturn, sizeof(void*)).has_error()) return false;
|
|
|
|
|
2023-07-10 19:54:04 +00:00
|
|
|
signal_mask = handler.sa_mask;
|
|
|
|
if ((handler.sa_flags & SA_NODEFER) == 0) signal_mask |= (1 << (signo - 1));
|
2023-07-10 17:46:57 +00:00
|
|
|
|
|
|
|
rsp = regs.rsp;
|
|
|
|
|
|
|
|
init_regs_user();
|
|
|
|
regs.rsp = rsp;
|
|
|
|
regs.rip = (u64)handler.sa_handler;
|
|
|
|
regs.rdi = signo;
|
|
|
|
|
|
|
|
memcpy(current_regs, ®s, sizeof(regs));
|
|
|
|
|
2023-07-10 19:54:04 +00:00
|
|
|
if (handler.sa_flags & SA_RESETHAND)
|
|
|
|
{
|
|
|
|
handler.sa_handler = SIG_DFL;
|
|
|
|
handler.sa_mask = 0;
|
|
|
|
handler.sa_flags = 0;
|
|
|
|
signal_handlers[signo - 1] = handler;
|
|
|
|
}
|
|
|
|
|
2023-07-10 17:46:57 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Thread::sigreturn(Registers* current_regs)
|
|
|
|
{
|
|
|
|
memcpy(®s, current_regs, sizeof(regs));
|
|
|
|
|
2023-07-15 09:54:48 +00:00
|
|
|
u64 rflags = current_regs->rflags;
|
|
|
|
|
2023-07-10 17:46:57 +00:00
|
|
|
u64 rsp;
|
|
|
|
pop_mem_from_stack((u8*)&rsp, sizeof(rsp));
|
|
|
|
regs.rsp = rsp;
|
2023-07-15 09:53:50 +00:00
|
|
|
pop_mem_from_stack((u8*)fp_data.data(), fp_data.size());
|
2023-07-10 17:46:57 +00:00
|
|
|
pop_mem_from_stack((u8*)&signal_mask, sizeof(signal_mask));
|
|
|
|
pop_mem_from_stack((u8*)current_regs, sizeof(*current_regs));
|
|
|
|
memcpy(®s, current_regs, sizeof(regs));
|
|
|
|
regs.cs = 0x18 | 3;
|
|
|
|
regs.ss = 0x20 | 3;
|
2023-07-15 09:54:48 +00:00
|
|
|
regs.rflags = (rflags & ~0xdff) | (regs.rflags & 0xdff);
|
2023-07-10 17:46:57 +00:00
|
|
|
|
2023-07-15 09:53:50 +00:00
|
|
|
fp_data.restore();
|
|
|
|
|
2023-07-10 17:46:57 +00:00
|
|
|
kinfoln("sigreturn: restored program state, sp=%p, ip=%p", (void*)regs.rsp, (void*)regs.rip);
|
|
|
|
|
|
|
|
memcpy(current_regs, ®s, sizeof(regs));
|
|
|
|
}
|