Signals kinda work!
This commit is contained in:
@@ -145,6 +145,23 @@ void sched_set_cpu_count(size_t count) {
|
||||
sched_ncpus = count;
|
||||
}
|
||||
|
||||
struct thread *sched_find(int pid) {
|
||||
if (pid <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Search through queues
|
||||
for (size_t cpu = 0; cpu < sched_ncpus; ++cpu) {
|
||||
for (struct thread *t = sched_queue_heads[cpu]; t; t = t->next) {
|
||||
if ((int) t->pid == pid) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void sched_add_to(int cpu, struct thread *t) {
|
||||
t->next = NULL;
|
||||
|
||||
@@ -262,6 +279,23 @@ int sched(void) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (to->flags & THREAD_SIGRET) {
|
||||
to->flags &= ~THREAD_SIGRET;
|
||||
amd64_thread_sigret(to);
|
||||
}
|
||||
|
||||
if (to->sigqsz) {
|
||||
// Should we enter signal handler?
|
||||
int signum = to->sigqueue[0];
|
||||
--to->sigqsz;
|
||||
// Shift the queue
|
||||
for (size_t i = 0; i < to->sigqsz; ++i) {
|
||||
to->sigqueue[i] = to->sigqueue[i + 1];
|
||||
}
|
||||
|
||||
amd64_thread_sigenter(to, signum);
|
||||
}
|
||||
|
||||
get_cpu()->thread = to;
|
||||
|
||||
return 0;
|
||||
|
||||
+86
-2
@@ -61,7 +61,18 @@ int thread_init(
|
||||
t->data.stack3_size = rsp3_size;
|
||||
}
|
||||
|
||||
// Setup context
|
||||
|
||||
// Alloc signal handling kstack
|
||||
void *kstack_sig = kmalloc(THREAD_KSTACK_SIZE);
|
||||
_assert(kstack_sig);
|
||||
|
||||
t->data.stack0s_base = (uintptr_t) kstack_sig;
|
||||
t->data.stack0s_size = THREAD_KSTACK_SIZE;
|
||||
|
||||
// No need to setup context for signal handler stack as it will be set up on
|
||||
// signal entry
|
||||
|
||||
// Setup normal context
|
||||
struct cpu_context *ctx = (struct cpu_context *) t->data.rsp0;
|
||||
|
||||
ctx->rip = entry;
|
||||
@@ -141,6 +152,17 @@ void thread_cleanup(struct thread *t) {
|
||||
kfree(t);
|
||||
}
|
||||
|
||||
// TODO: may be moved to platform-independent file
|
||||
void thread_signal(struct thread *t, int s) {
|
||||
_assert(t);
|
||||
|
||||
if (t->sigqsz == 8) {
|
||||
panic("Thread received too many unhandled signals\n");
|
||||
}
|
||||
|
||||
t->sigqueue[t->sigqsz++] = s;
|
||||
}
|
||||
|
||||
int sys_execve(const char *filename, const char *const argv[], const char *const envp[]) {
|
||||
asm volatile ("cli");
|
||||
struct thread *thr = get_cpu()->thread;
|
||||
@@ -237,12 +259,15 @@ int sys_fork(void) {
|
||||
|
||||
// Clone process state
|
||||
void *dst_kstack = kmalloc(THREAD_KSTACK_SIZE);
|
||||
void *dst_kstack_sig = kmalloc(THREAD_KSTACK_SIZE);
|
||||
struct amd64_thread *dst_data = &thr_dst->data;
|
||||
_assert(dst_kstack);
|
||||
_assert(dst_kstack && dst_kstack_sig);
|
||||
|
||||
dst_data->data_flags |= 1 /* Don't free kstack */;
|
||||
dst_data->stack0_base = (uintptr_t) dst_kstack;
|
||||
dst_data->stack0_size = THREAD_KSTACK_SIZE;
|
||||
dst_data->stack0s_base = (uintptr_t) dst_kstack_sig;
|
||||
dst_data->stack0s_size = THREAD_KSTACK_SIZE;
|
||||
dst_data->stack3_base = thr_src->data.stack3_base;
|
||||
dst_data->stack3_size = thr_src->data.stack3_size;
|
||||
dst_data->rsp0 = dst_data->stack0_base + dst_data->stack0_size - sizeof(struct cpu_context);
|
||||
@@ -287,3 +312,62 @@ void amd64_thread_set_ip(struct thread *t, uintptr_t ip) {
|
||||
ctx->rip = ip;
|
||||
ctx->rflags = 0x248;
|
||||
}
|
||||
|
||||
void amd64_thread_sigenter(struct thread *t, int signum) {
|
||||
_assert(t);
|
||||
|
||||
// Swap contexts
|
||||
t->data.rsp0s = t->data.rsp0;
|
||||
t->data.rsp0 = t->data.stack0s_base + t->data.stack0s_size - sizeof(struct cpu_context);
|
||||
|
||||
// Setup signal handler context
|
||||
struct cpu_context *ctx = (struct cpu_context *) t->data.rsp0;
|
||||
|
||||
ctx->rip = t->sigentry;
|
||||
ctx->rflags = 0x248;
|
||||
|
||||
if (t->flags & THREAD_KERNEL) {
|
||||
panic("TODO: kernel thread signal handling\n");
|
||||
} else {
|
||||
// Give one page of user stack for signal handling
|
||||
t->sigstack = t->data.stack3_base + 4096;
|
||||
ctx->rsp = t->sigstack;
|
||||
ctx->cs = 0x23;
|
||||
ctx->ss = 0x1B;
|
||||
|
||||
ctx->ds = 0x1B;
|
||||
ctx->es = 0x1B;
|
||||
ctx->fs = 0;
|
||||
}
|
||||
|
||||
ctx->rax = 0;
|
||||
ctx->rcx = 0;
|
||||
ctx->rdx = 0;
|
||||
ctx->rdx = 0;
|
||||
ctx->rbp = 0;
|
||||
ctx->rsi = 0;
|
||||
ctx->rdi = (uintptr_t) signum;
|
||||
|
||||
ctx->cr3 = ({ _assert((uintptr_t) t->space >= 0xFFFFFF0000000000); (uintptr_t) t->space - 0xFFFFFF0000000000; });
|
||||
|
||||
ctx->r8 = 0;
|
||||
ctx->r9 = 0;
|
||||
ctx->r10 = 0;
|
||||
ctx->r11 = 0;
|
||||
ctx->r12 = 0;
|
||||
ctx->r13 = 0;
|
||||
ctx->r14 = 0;
|
||||
ctx->r15 = 0;
|
||||
|
||||
ctx->__canary = AMD64_STACK_CTX_CANARY;
|
||||
|
||||
if (t == get_cpu()->thread) {
|
||||
panic("NYI\n");
|
||||
}
|
||||
}
|
||||
|
||||
void amd64_thread_sigret(struct thread *t) {
|
||||
_assert(t);
|
||||
|
||||
t->data.rsp0 = t->data.rsp0s;
|
||||
}
|
||||
|
||||
+61
-1
@@ -3,6 +3,7 @@
|
||||
#include "sys/thread.h"
|
||||
#include "sys/string.h"
|
||||
#include "sys/assert.h"
|
||||
#include "sys/sched.h"
|
||||
#include "sys/types.h"
|
||||
#include "sys/debug.h"
|
||||
#include "sys/errno.h"
|
||||
@@ -20,10 +21,15 @@ static int sys_open(const char *filename, int flags, int mode);
|
||||
static void sys_close(int fd);
|
||||
static int sys_stat(const char *filename, struct stat *st);
|
||||
static void sys_exit(int status);
|
||||
static int sys_kill(int pid, int signum);
|
||||
static int sys_brk(void *ptr);
|
||||
|
||||
extern int sys_execve(const char *filename, const char *const argv[], const char *const envp[]);
|
||||
|
||||
// Non-compliant with linux style, but fuck'em, it just works
|
||||
static void sys_signal(uintptr_t entry);
|
||||
static void sys_sigret(void);
|
||||
|
||||
__attribute__((noreturn)) void amd64_syscall_yield_stopped(void);
|
||||
|
||||
intptr_t amd64_syscall(uintptr_t rdi, uintptr_t rsi, uintptr_t rdx, uintptr_t rcx, uintptr_t r10, uintptr_t rax) {
|
||||
@@ -45,14 +51,24 @@ intptr_t amd64_syscall(uintptr_t rdi, uintptr_t rsi, uintptr_t rdx, uintptr_t rc
|
||||
case SYSCALL_NR_READDIR:
|
||||
return sys_readdir((int) rdi, (struct dirent *) rsi);
|
||||
|
||||
case SYSCALL_NRX_SIGNAL:
|
||||
sys_signal(rdi);
|
||||
return 0;
|
||||
case SYSCALL_NR_BRK:
|
||||
return sys_brk((void *) rdi);
|
||||
case SYSCALL_NR_EXIT:
|
||||
sys_exit((int) rdi);
|
||||
amd64_syscall_yield_stopped();
|
||||
case SYSCALL_NR_KILL:
|
||||
return sys_kill((int) rdi, (int) rsi);
|
||||
case SYSCALL_NRX_SIGRET:
|
||||
sys_sigret();
|
||||
return 0;
|
||||
|
||||
default:
|
||||
kdebug("unknown syscall: %u\n", rax);
|
||||
kerror("unknown syscall: %u\n", rax);
|
||||
// TODO: I guess this should ideally crash the application
|
||||
// with invalid opcode or something
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -222,3 +238,47 @@ static void sys_exit(int status) {
|
||||
thr->flags |= THREAD_STOPPED;
|
||||
}
|
||||
|
||||
static void sys_signal(uintptr_t entry) {
|
||||
struct thread *thr = get_cpu()->thread;
|
||||
_assert(thr);
|
||||
kdebug("%u set its signal handler to %p\n", thr->pid, entry);
|
||||
thr->sigentry = entry;
|
||||
}
|
||||
|
||||
static int sys_kill(int pid, int signum) {
|
||||
asm volatile ("cli");
|
||||
struct thread *cur_thread = get_cpu()->thread;
|
||||
|
||||
// Find destination thread
|
||||
struct thread *dst_thread = sched_find(pid);
|
||||
|
||||
if (!dst_thread) {
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
// Push an item to signal queue
|
||||
thread_signal(dst_thread, signum);
|
||||
|
||||
if (cur_thread == dst_thread) {
|
||||
// Suicide signal, just hang on and wait
|
||||
// until scheduler decides it's our time
|
||||
asm volatile ("sti; hlt; cli");
|
||||
|
||||
kdebug("Returned from shit\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern void amd64_syscall_iretq(uintptr_t ctx);
|
||||
|
||||
static void sys_sigret(void) {
|
||||
struct thread *thr = get_cpu()->thread;
|
||||
_assert(thr);
|
||||
|
||||
thr->flags |= THREAD_SIGRET;
|
||||
|
||||
asm volatile ("sti; hlt; cli");
|
||||
|
||||
panic("Fuck\n");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user