From d31f5e02fe289debe8fed85da282cb2d28266a89 Mon Sep 17 00:00:00 2001 From: Yi-Ting Shih Date: Sun, 4 May 2025 20:38:25 +0800 Subject: [PATCH] Feat: POSIX signal --- include/logger.h | 3 ++ kernel/include/process.h | 10 +++++++ kernel/include/signal.h | 11 ++++++++ kernel/include/syscall.h | 6 +++- kernel/lib/mbox.c | 2 +- kernel/lib/process.c | 61 ++++++++++++++++++++++------------------ kernel/lib/signal.c | 59 ++++++++++++++++++++++++++++++++++++++ kernel/lib/syscall.c | 46 +++++++++++++++++++++++++++--- kernel/lib/timer.c | 6 ++++ 9 files changed, 171 insertions(+), 33 deletions(-) create mode 100644 kernel/include/signal.h create mode 100644 kernel/lib/signal.c diff --git a/include/logger.h b/include/logger.h index 842cbe1..b2281c6 100644 --- a/include/logger.h +++ b/include/logger.h @@ -161,6 +161,9 @@ uint64_t _r_sp() // #define DEBUG_THREAD(val) DEBUG(val) #define DEBUG_THREAD(val) CLEAN +#define DEBUG_SIGNAL(val) DEBUG(val) +// #define DEBUG_SIGNAL(val) CLEAN + extern char logger_buf[LOGGER_BUFLEN]; extern char *logger_cur; extern char sp_buf[LOGGER_BUFLEN]; diff --git a/kernel/include/process.h b/kernel/include/process.h index e1c93da..d97a226 100644 --- a/kernel/include/process.h +++ b/kernel/include/process.h @@ -1,6 +1,8 @@ #pragma once #include +#include +#include typedef struct { uint64_t x0, x1; @@ -38,6 +40,13 @@ typedef struct process { void *mem; size_t mem_size; + void *sigstack; + size_t sigstack_size; + + bool sigstate[SIGNAL_NUM]; + int32_t current_signal; + signal_handler_t sighandlers[SIGNAL_NUM]; + trapframe_t *regs; } process_t; @@ -51,3 +60,4 @@ int32_t run_process(uint64_t process); process_t *fork_process(const process_t *from); extern int32_t global_pid_counter; +extern vector_t *global_processes; diff --git a/kernel/include/signal.h b/kernel/include/signal.h new file mode 100644 index 0000000..439edfa --- /dev/null +++ b/kernel/include/signal.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +#define SIGNAL_NUM 32 + +#define SIGKILL 9 + +typedef void (*signal_handler_t)(); + +void run_signal(int32_t SIGNAL); diff --git a/kernel/include/syscall.h b/kernel/include/syscall.h index 3ddf064..329b4aa 100644 --- a/kernel/include/syscall.h +++ b/kernel/include/syscall.h @@ -2,6 +2,7 @@ #include #include +#include void syscall_handler(trapframe_t *regs); @@ -12,4 +13,7 @@ int32_t sys_exec(const char *name, char *const argv[]); int32_t sys_fork(void); void sys_exit(int32_t status); int32_t sys_mbox_call(uint8_t ch, uint32_t *mbox); -void sys_kill(int32_t pid); +void sys_kill_by_id(int32_t pid); +void sys_signal(int32_t SIGNAL, signal_handler_t handler); +void sys_kill(int32_t pid, int32_t SIGNAL); +void sys_sigreturn(void); diff --git a/kernel/lib/mbox.c b/kernel/lib/mbox.c index a53e9a8..485db60 100644 --- a/kernel/lib/mbox.c +++ b/kernel/lib/mbox.c @@ -57,7 +57,7 @@ int mbox_call(unsigned char ch, unsigned int *input) { unsigned int *_mbox = kmalloc((size_t)input[0] + 0xf), *mbox = ALIGN16(_mbox); - LOG(_mbox); LOG(mbox); DEBUG((size_t)input[0]); + LOG(_mbox); LOG(mbox); DEBUG_THREAD((size_t)input[0]); memcpy(mbox, input, (size_t)input[0]); unsigned int r = (unsigned long)mbox | (unsigned int)(ch&0xf); /* wait until we can write to the mailbox */ diff --git a/kernel/lib/process.c b/kernel/lib/process.c index 00351c2..dc43864 100644 --- a/kernel/lib/process.c +++ b/kernel/lib/process.c @@ -11,15 +11,16 @@ #include int32_t global_pid_counter = 0; +vector_t *global_processes = 0x0; static inline -process_t *_make_process(const char *filename) +process_t *_make_process() { process_t *ret = kmalloc(sizeof(process_t)); - - file_node_t *file = initrd_get(initrd_root, filename); - if (file == 0x0) - panic(ERR_NOT_EXIST); + + if (!global_processes) + global_processes = make_vector(0); + VEC_PUSH(global_processes, ret); *ret = (process_t){ .pid = global_pid_counter++, @@ -33,26 +34,46 @@ process_t *_make_process(const char *filename) .mem = allocate_page(256), .mem_size = 256 << 12, + .sigstack = allocate_page(256), + .sigstack_size = 256 << 12, + + .current_signal = 0, + .regs = kmalloc(sizeof(trapframe_t)), }; - memcpy(ret->mem, file->filecontent, file->filesize); + + memset(ret->sigstate, 0x0, SIGNAL_NUM * sizeof(bool)); + memset(ret->sighandlers, 0x0, SIGNAL_NUM * sizeof(signal_handler_t)); memset(ret->regs, 0x0, sizeof(trapframe_t)); - *ret->regs = (trapframe_t){ - .spsr_el1 = 0x0, // enable all interrupt - .elr_el1 = (uint64_t)ret->mem, - .sp_el0 = ((uint64_t)ret->stack + ret->stack_size - 64), - }; return ret; } +static inline +void _init_process(process_t *process, const char *filename) +{ + file_node_t *file = initrd_get(initrd_root, filename); + if (file == 0x0) + panic(ERR_NOT_EXIST); + + memcpy(process->mem, file->filecontent, file->filesize); + *process->regs = (trapframe_t){ + .spsr_el1 = 0x0, // enable all interrupt + .elr_el1 = (uint64_t)process->mem, + .sp_el0 = ((uint64_t)process->stack + process->stack_size - 64), + }; +} + // void run_process_by_name(const char *filename) int32_t run_process_by_name(uint64_t param) { const char *filename = (void *)param; thread_t *th = get_current(); - th->process = _make_process(filename); + if (!th->process) + th->process = _make_process(); + _init_process(th->process, filename); + th->process->th = th; LOG("Run process by name"); DEBUG_THREAD(filename); LOG(th->process->stack); DEBUG_THREAD(th->process->regs->sp_el0); @@ -84,21 +105,7 @@ int32_t run_process(uint64_t param) process_t *fork_process(const process_t *from) { - process_t *ret = kmalloc(sizeof(process_t)); - *ret = (process_t){ - .pid = global_pid_counter++, - .th = 0x0, - - .exitcode = from->exitcode, - - .stack = allocate_page(256), - .stack_size = 256 << 12, - - .mem = allocate_page(256), - .mem_size = 256 << 12, - - .regs = kmalloc(sizeof(trapframe_t)), - }; + process_t *ret = _make_process(); memcpy(ret->stack, from->stack, from->stack_size); memcpy(ret->mem, from->mem, from->mem_size); *ret->regs = (trapframe_t){ diff --git a/kernel/lib/signal.c b/kernel/lib/signal.c new file mode 100644 index 0000000..118322f --- /dev/null +++ b/kernel/lib/signal.c @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +static inline +void _sighandler_wrapper(signal_handler_t handler) +{ + handler(); + asm volatile( + "mov x8, #10" ENDL + "svc 0" + ::: "x8" + ); +} + +static inline +void _sigkill_default_handler() +{ + thread_t *th = get_current(); + th->status = THREAD_STATUS_ZOMBIE; +} + +void run_signal(int32_t SIGNAL) +{ + LOG("run_signal"); DEBUG_SIGNAL(SIGNAL); + process_t *process = get_current()->process; + process->current_signal = SIGNAL; + trapframe_t *regs = kmalloc(sizeof(trapframe_t)); + memcpy(regs, process->regs, sizeof(trapframe_t)); + + if (!process->sighandlers[SIGNAL]) { + switch (SIGNAL) { + case SIGKILL: + _sigkill_default_handler(); + break; + default: + LOG("No default handler for this signal"); DEBUG_SIGNAL(SIGNAL); + return; + } + } + + *regs = (trapframe_t){ + .x0 = (uint64_t)process->sighandlers[SIGNAL], + .elr_el1 = (uint64_t)_sighandler_wrapper, + .sp_el0 = ((uint64_t)process->sigstack + process->sigstack_size - 64), + }; + + disable_interrupt(); + process->current_signal = 0x0; + process->sigstate[SIGNAL] = false; + user_exec(regs); + + __builtin_unreachable(); +} diff --git a/kernel/lib/syscall.c b/kernel/lib/syscall.c index 7e12be5..c5b7134 100644 --- a/kernel/lib/syscall.c +++ b/kernel/lib/syscall.c @@ -4,6 +4,7 @@ #include #include #include +#include void syscall_handler(trapframe_t *regs) { @@ -27,13 +28,22 @@ void syscall_handler(trapframe_t *regs) regs->x0 = sys_fork(); break; case 5: // void exit(int32_t status) - sys_exit((int)regs->x0); + sys_exit((int32_t)regs->x0); break; case 6: // int32_t mbox_call(uint8_t ch, uint32_t *mbox) regs->x0 = sys_mbox_call((uint8_t)regs->x0, (uint32_t *)regs->x1); break; - case 7: // void kill(int32_t pid) - sys_kill((int)regs->x0); + case 7: // void kill_by_id(int32_t pid) + sys_kill_by_id((int32_t)regs->x0); + break; + case 8: // void signal(int32_t SIGNAL, signal_handler_t handler) + sys_signal((int32_t)regs->x0, (signal_handler_t)regs->x1); + break; + case 9: // void kill(int32_t pid, int32_t SIGNAL) + sys_kill((int32_t)regs->x0, (int32_t)regs->x1); + break; + case 10: // void sigreturn(void) + sys_sigreturn(); break; default: LOG("unsupported syscall"); ERROR(regs->x8); @@ -74,6 +84,34 @@ void sys_exit(int32_t status) int32_t sys_mbox_call(uint8_t ch, uint32_t *mbox) { return mbox_call(ch, mbox); } -void sys_kill(int32_t pid) +void sys_kill_by_id(int32_t pid) { + if (!global_processes || global_processes->size <= (size_t)pid) { + LOG("Process not exist"); INFOR(pid); + return; + } + + process_t *process = VEC_AT(process_t, global_processes, pid); + process->th->status = THREAD_STATUS_ZOMBIE; + LOG("Process killed"); INFOR(pid); +} + +void sys_signal(int32_t SIGNAL, signal_handler_t handler) +{ + thread_t *th = get_current(); + th->process->sighandlers[SIGNAL] = handler; + LOG(handler); LOG(SIGNAL); DEBUG_SIGNAL("registered"); +} + +void sys_kill(int32_t pid, int32_t SIGNAL) +{ + process_t *process = VEC_AT(process_t, global_processes, pid); + process->sigstate[SIGNAL] = true; +} + +void sys_sigreturn(void) +{ + DEBUG_SIGNAL("sigreturn"); + thread_t *th = get_current(); + user_exec(th->process->regs); } diff --git a/kernel/lib/timer.c b/kernel/lib/timer.c index a770a6a..41da8ef 100644 --- a/kernel/lib/timer.c +++ b/kernel/lib/timer.c @@ -41,5 +41,11 @@ void timer_irq_handler(void) uint64_t cntfrq_el0; R_SYSREG(cntfrq_el0, cntfrq_el0); W_SYSREG(cntp_tval_el0, cntfrq_el0 >> 5); + + thread_t *th = get_current(); + for (int32_t i = 0; i < SIGNAL_NUM; ++i) { + if (th->process->sigstate[i]) + run_signal(i); + } schedule(); }