From 585bfcdac85d3258590e0924e99e5afea25a0928 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Thu, 10 Oct 2024 18:09:38 -0400 Subject: [PATCH 01/67] ipc: declarations for signal macros --- src/include/kernel/signal.h | 50 +++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 src/include/kernel/signal.h diff --git a/src/include/kernel/signal.h b/src/include/kernel/signal.h new file mode 100644 index 0000000..83b761d --- /dev/null +++ b/src/include/kernel/signal.h @@ -0,0 +1,50 @@ +/* + * lux - a lightweight unix-like operating system + * Omar Elghoul, 2024 + * + * Core Microkernel + */ + +#pragma once + +#include + +/* Signal Handler Macros */ +#define SIG_DFL (void (*)(int))0 +#define SIG_ERR (void (*)(int))1 +#define SIG_HOLD (void (*)(int))2 +#define SIG_IGN (void (*)(int))3 + +/* ISO C Signals */ +#define SIGABRT 0 +#define SIGFPE 1 +#define SIGILL 2 +#define SIGINT 3 +#define SIGSEGV 4 +#define SIGTERM 5 + +/* POSIX Extension Signals */ +#define SIGALRM 6 +#define SIGBUS 7 +#define SIGCHLD 8 +#define SIGCONT 9 +#define SIGHUP 10 +#define SIGKILL 11 +#define SIGPIPE 12 +#define SIGQUIT 13 +#define SIGSEGV 14 +#define SIGSTOP 15 +#define SIGTSTP 16 +#define SIGTTIN 17 +#define SIGTTOU 18 +#define SIGUSR1 19 +#define SIGUSR2 20 +#define SIGPOLL 21 +#define SIGSYS 22 +#define SIGTRAP 23 +#define SIGURG 24 +#define SIGVTALRM 25 +#define SIGXCPU 26 +#define SIGXFSZ 27 + +typedef volatile uint32_t sig_atomic_t; From f0cdf9691517958b9467caafca20ffd1785e8ad3 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Thu, 10 Oct 2024 18:23:42 -0400 Subject: [PATCH 02/67] ipc: incremented signal numbers to account for null signal --- src/include/kernel/signal.h | 56 ++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/include/kernel/signal.h b/src/include/kernel/signal.h index 83b761d..4a06b5f 100644 --- a/src/include/kernel/signal.h +++ b/src/include/kernel/signal.h @@ -16,35 +16,35 @@ #define SIG_IGN (void (*)(int))3 /* ISO C Signals */ -#define SIGABRT 0 -#define SIGFPE 1 -#define SIGILL 2 -#define SIGINT 3 -#define SIGSEGV 4 -#define SIGTERM 5 +#define SIGABRT 1 +#define SIGFPE 2 +#define SIGILL 3 +#define SIGINT 4 +#define SIGSEGV 5 +#define SIGTERM 6 /* POSIX Extension Signals */ -#define SIGALRM 6 -#define SIGBUS 7 -#define SIGCHLD 8 -#define SIGCONT 9 -#define SIGHUP 10 -#define SIGKILL 11 -#define SIGPIPE 12 -#define SIGQUIT 13 -#define SIGSEGV 14 -#define SIGSTOP 15 -#define SIGTSTP 16 -#define SIGTTIN 17 -#define SIGTTOU 18 -#define SIGUSR1 19 -#define SIGUSR2 20 -#define SIGPOLL 21 -#define SIGSYS 22 -#define SIGTRAP 23 -#define SIGURG 24 -#define SIGVTALRM 25 -#define SIGXCPU 26 -#define SIGXFSZ 27 +#define SIGALRM 7 +#define SIGBUS 8 +#define SIGCHLD 9 +#define SIGCONT 10 +#define SIGHUP 11 +#define SIGKILL 12 +#define SIGPIPE 13 +#define SIGQUIT 14 +#define SIGSEGV 15 +#define SIGSTOP 16 +#define SIGTSTP 17 +#define SIGTTIN 18 +#define SIGTTOU 19 +#define SIGUSR1 20 +#define SIGUSR2 21 +#define SIGPOLL 22 +#define SIGSYS 23 +#define SIGTRAP 24 +#define SIGURG 25 +#define SIGVTALRM 26 +#define SIGXCPU 27 +#define SIGXFSZ 28 typedef volatile uint32_t sig_atomic_t; From 97e97ae3abc6c353681996573af190ca4a5e1499 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 15 Oct 2024 21:31:27 -0400 Subject: [PATCH 03/67] x86_64: bugfix in memset() --- src/platform/x86_64/string.asm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/x86_64/string.asm b/src/platform/x86_64/string.asm index 8d31693..81786a3 100644 --- a/src/platform/x86_64/string.asm +++ b/src/platform/x86_64/string.asm @@ -68,7 +68,7 @@ memset: mov ax, si ; 32 bits mov esi, eax shr rax, 32 - mov eax, esi ; full 64 bits + or rax, rsi ; full 64 bits mov rcx, rdx shr rcx, 3 ; div 8 From 02ef5168d1f5f62328152ca7ced6beb63c6d86c2 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Thu, 24 Oct 2024 18:18:42 -0400 Subject: [PATCH 04/67] syscalls: avoid blocking accept() when not necessary --- src/include/kernel/syscalls.h | 1 + src/syscalls/queue.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/include/kernel/syscalls.h b/src/include/kernel/syscalls.h index eb9df2d..7751c7a 100644 --- a/src/include/kernel/syscalls.h +++ b/src/include/kernel/syscalls.h @@ -15,6 +15,7 @@ /* IPC syscall indexes, this range will be used for immediate handling without * waiting for the kernel thread to dispatch the syscall */ +#define SYSCALL_ACCEPT 44 // accept() #define SYSCALL_IPC_START 42 // bind() #define SYSCALL_IPC_END 46 // send() diff --git a/src/syscalls/queue.c b/src/syscalls/queue.c index be13683..c3a9239 100644 --- a/src/syscalls/queue.c +++ b/src/syscalls/queue.c @@ -28,7 +28,8 @@ void syscallHandle(void *ctx) { // allow immediate handling of IPC syscalls without going through the // syscall queue for performance if((req->function >= SYSCALL_IPC_START && req->function <= SYSCALL_IPC_END) || - (req->function >= SYSCALL_RW_START && req->function <= SYSCALL_RW_END)) { + (req->function >= SYSCALL_RW_START && req->function <= SYSCALL_RW_END) || + (req->function == SYSCALL_ACCEPT)) { setLocalSched(false); syscallDispatchTable[req->function](req); From cea50c6c0b7b7e505aba3126088b91a3b203769c Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Mon, 4 Nov 2024 21:48:43 -0500 Subject: [PATCH 05/67] ipc: added more signal structures and prototypes --- src/include/kernel/signal.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/include/kernel/signal.h b/src/include/kernel/signal.h index 4a06b5f..54f28be 100644 --- a/src/include/kernel/signal.h +++ b/src/include/kernel/signal.h @@ -8,6 +8,7 @@ #pragma once #include +#include /* Signal Handler Macros */ #define SIG_DFL (void (*)(int))0 @@ -48,3 +49,31 @@ #define SIGXFSZ 28 typedef volatile uint32_t sig_atomic_t; +typedef uint64_t sigset_t; + +typedef struct { + int si_signo, si_code, si_errno, si_status; + pid_t si_pid; + uid_t si_uid; + void *si_addr; + long si_band; +} siginfo_t; + +struct sigaction { + union handler { + void (*)(int) sa_handler; + void (*)(int, siginfo_t *, void *) sa_sigaction; + }; + + sigset_t sa_mask; + int sa_flags; +}; + +int sigemptyset(sigset_t *); +int sigfillset(sigset_t *); +int sigaddset(sigset_t *, int); +int sigdelset(sigset_t *, int); +int sigismember(sigset_t *, int); + +int kill(Thread *, pid_t, int); +int sigaction(Thread *, int, const struct sigaction *, struct sigaction *); From 9895a4185fbd779b99b9518379baf7a7699495ba Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Mon, 4 Nov 2024 21:55:40 -0500 Subject: [PATCH 06/67] ipc: syntax and definition fixes in signal.h --- src/include/kernel/signal.h | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/include/kernel/signal.h b/src/include/kernel/signal.h index 54f28be..0feb110 100644 --- a/src/include/kernel/signal.h +++ b/src/include/kernel/signal.h @@ -33,20 +33,21 @@ #define SIGKILL 12 #define SIGPIPE 13 #define SIGQUIT 14 -#define SIGSEGV 15 -#define SIGSTOP 16 -#define SIGTSTP 17 -#define SIGTTIN 18 -#define SIGTTOU 19 -#define SIGUSR1 20 -#define SIGUSR2 21 -#define SIGPOLL 22 -#define SIGSYS 23 -#define SIGTRAP 24 -#define SIGURG 25 -#define SIGVTALRM 26 -#define SIGXCPU 27 -#define SIGXFSZ 28 +#define SIGSTOP 15 +#define SIGTSTP 16 +#define SIGTTIN 17 +#define SIGTTOU 18 +#define SIGUSR1 19 +#define SIGUSR2 20 +#define SIGPOLL 21 +#define SIGSYS 22 +#define SIGTRAP 23 +#define SIGURG 24 +#define SIGVTALRM 25 +#define SIGXCPU 26 +#define SIGXFSZ 27 + +#define MAX_SIGNAL 27 typedef volatile uint32_t sig_atomic_t; typedef uint64_t sigset_t; @@ -61,8 +62,8 @@ typedef struct { struct sigaction { union handler { - void (*)(int) sa_handler; - void (*)(int, siginfo_t *, void *) sa_sigaction; + void (*sa_handler)(int); + void (*sa_sigaction)(int, siginfo_t *, void *); }; sigset_t sa_mask; From 5039f5944e8295e739cc3564fa6edeed80b6ba99 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Mon, 4 Nov 2024 21:55:47 -0500 Subject: [PATCH 07/67] ipc: signal set manipulation --- src/ipc/signal.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 src/ipc/signal.c diff --git a/src/ipc/signal.c b/src/ipc/signal.c new file mode 100644 index 0000000..70cefe8 --- /dev/null +++ b/src/ipc/signal.c @@ -0,0 +1,76 @@ +/* + * lux - a lightweight unix-like operating system + * Omar Elghoul, 2024 + * + * Core Microkernel + */ + +#include +#include +#include + +/* Implementation of ISO C and POSIX Signals */ + +/* sigemptyset(): clears a set of signals + * params: set - set of signals + * returns: zero + */ + +int sigemptyset(sigset_t *set) { + *set = 0; + return 0; +} + +/* sigfillset(): fills a set of signals with all supported signals + * params: set - set of signals + * returns: zero + */ + +int sigfillset(sigset_t *set) { + *set = 0; + + for(int i = 0; i < MAX_SIGNAL; i++) + *set |= (1 << i); + + return 0; +} + +/* sigaddset(): adds a signal to a set of signals + * params: set - set of signals + * params: signum - signal to add + * returns: zero on success + */ + +int sigaddset(sigset_t *set, int signum) { + if(signum > MAX_SIGNAL) return -EINVAL; + + *set |= (1 << signum); + return 0; +} + +/* sigdelset(): removes a signal from a set of signals + * params: set - set of signals + * params: signum - signal to be removed + * returns: zero on success + */ + +int sigdelset(sigset_t *set, int signum) { + if(signum > MAX_SIGNAL) return -EINVAL; + + *set &= ~(1 << signum); + return 0; +} + +/* sigismember(): tests if a signal is in a set of signals + * params: set - set of signals + * params: signum - signal to be checked + * returns: zero if absent, one if present, negative error code on fail + */ + +int sigismember(sigset_t *set, int signum) { + if(signum > MAX_SIGNAL) return -EINVAL; + + if(*set & (1 << signum)) return 1; + else return 0; +} + From 15a8a59a220c1251058e936bcf8253eb9e8b4baa Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Mon, 4 Nov 2024 22:06:54 -0500 Subject: [PATCH 08/67] ipc: syntax fix in sigaction union --- src/include/kernel/signal.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/include/kernel/signal.h b/src/include/kernel/signal.h index 0feb110..5fe7586 100644 --- a/src/include/kernel/signal.h +++ b/src/include/kernel/signal.h @@ -61,10 +61,10 @@ typedef struct { } siginfo_t; struct sigaction { - union handler { + union { void (*sa_handler)(int); void (*sa_sigaction)(int, siginfo_t *, void *); - }; + } handler; sigset_t sa_mask; int sa_flags; From b5c97e8a60823ac3116cf73898656bce332f5afe Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Mon, 4 Nov 2024 22:07:11 -0500 Subject: [PATCH 09/67] ipc: better input validation in signal set manipulation --- src/ipc/signal.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/ipc/signal.c b/src/ipc/signal.c index 70cefe8..1e735b7 100644 --- a/src/ipc/signal.c +++ b/src/ipc/signal.c @@ -42,7 +42,8 @@ int sigfillset(sigset_t *set) { */ int sigaddset(sigset_t *set, int signum) { - if(signum > MAX_SIGNAL) return -EINVAL; + if(signum < 0 || signum > MAX_SIGNAL) + return -EINVAL; *set |= (1 << signum); return 0; @@ -55,7 +56,8 @@ int sigaddset(sigset_t *set, int signum) { */ int sigdelset(sigset_t *set, int signum) { - if(signum > MAX_SIGNAL) return -EINVAL; + if(signum < 0 || signum > MAX_SIGNAL) + return -EINVAL; *set &= ~(1 << signum); return 0; @@ -68,7 +70,8 @@ int sigdelset(sigset_t *set, int signum) { */ int sigismember(sigset_t *set, int signum) { - if(signum > MAX_SIGNAL) return -EINVAL; + if(signum < 0 || signum > MAX_SIGNAL) + return -EINVAL; if(*set & (1 << signum)) return 1; else return 0; From df0c52e6cb5c79cdaf0b0aa2d82ea96dd4dd6192 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 5 Nov 2024 13:45:32 -0500 Subject: [PATCH 10/67] sched: added signal handler pointer to thread structure --- src/include/kernel/sched.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/include/kernel/sched.h b/src/include/kernel/sched.h index 3b301d0..c194fb2 100644 --- a/src/include/kernel/sched.h +++ b/src/include/kernel/sched.h @@ -45,7 +45,9 @@ typedef struct Thread { uint64_t time; // timeslice OR sleep time if sleeping thread bool normalExit; // true when the thread ends by exit() and is not forcefully killed - bool clean; // true when the exit status has been read by waitpid() + bool clean; // true when the exit status has been read by waitpid() + + void *signals; SyscallRequest syscall; // for when the thread is blocked int exitStatus; // for zombie threads From 24ec52d921c8f7d4e898264335ef8c7797d2d961 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 5 Nov 2024 13:49:14 -0500 Subject: [PATCH 11/67] ipc: signal default handler setup --- src/include/kernel/signal.h | 2 ++ src/ipc/signal.c | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/include/kernel/signal.h b/src/include/kernel/signal.h index 5fe7586..b32c138 100644 --- a/src/include/kernel/signal.h +++ b/src/include/kernel/signal.h @@ -76,5 +76,7 @@ int sigaddset(sigset_t *, int); int sigdelset(sigset_t *, int); int sigismember(sigset_t *, int); +void *signalDefaults(); + int kill(Thread *, pid_t, int); int sigaction(Thread *, int, const struct sigaction *, struct sigaction *); diff --git a/src/ipc/signal.c b/src/ipc/signal.c index 1e735b7..b158359 100644 --- a/src/ipc/signal.c +++ b/src/ipc/signal.c @@ -6,6 +6,7 @@ */ #include +#include #include #include @@ -77,3 +78,17 @@ int sigismember(sigset_t *set, int signum) { else return 0; } +/* signalDefaults(): sets up the default signal handlers for a thread + * params: none + * returns: pointer to the signal handler array, NULL on fail + */ + +void *signalDefaults() { + uintptr_t *ptr = calloc(MAX_SIGNAL+1, sizeof(uintptr_t)); + if(!ptr) return NULL; + + for(int i = 0; i < MAX_SIGNAL; i++) + *ptr = (uintptr_t) SIG_DFL; // default + + return (void *) ptr; +} From 577002e99366509ca46f507990c126d261d6081f Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 5 Nov 2024 13:53:22 -0500 Subject: [PATCH 12/67] sched: set default signal handlers on exec() --- src/sched/exec.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sched/exec.c b/src/sched/exec.c index 54b7b92..45c1593 100644 --- a/src/sched/exec.c +++ b/src/sched/exec.c @@ -14,6 +14,7 @@ #include #include #include +#include int execmve(Thread *, void *, const char **, const char **); @@ -323,6 +324,9 @@ int execmve(Thread *t, void *image, const char **argv, const char **envp) { } } + // set up default signal handlers + t->signals = signalDefaults(); + // TODO: here we've successfully loaded the new program, but we also need // to free up memory used by the original program platformCleanThread(oldctx, oldHighest); From b0d7f511b727bfdf80647310b8209285dc77411b Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 5 Nov 2024 13:56:33 -0500 Subject: [PATCH 13/67] ipc: clone signal handlers --- src/include/kernel/signal.h | 1 + src/ipc/signal.c | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/include/kernel/signal.h b/src/include/kernel/signal.h index b32c138..4226dac 100644 --- a/src/include/kernel/signal.h +++ b/src/include/kernel/signal.h @@ -77,6 +77,7 @@ int sigdelset(sigset_t *, int); int sigismember(sigset_t *, int); void *signalDefaults(); +void *signalClone(const void *); int kill(Thread *, pid_t, int); int sigaction(Thread *, int, const struct sigaction *, struct sigaction *); diff --git a/src/ipc/signal.c b/src/ipc/signal.c index b158359..389b7bc 100644 --- a/src/ipc/signal.c +++ b/src/ipc/signal.c @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -84,7 +85,7 @@ int sigismember(sigset_t *set, int signum) { */ void *signalDefaults() { - uintptr_t *ptr = calloc(MAX_SIGNAL+1, sizeof(uintptr_t)); + uintptr_t *ptr = malloc((MAX_SIGNAL+1) * sizeof(uintptr_t)); if(!ptr) return NULL; for(int i = 0; i < MAX_SIGNAL; i++) @@ -92,3 +93,15 @@ void *signalDefaults() { return (void *) ptr; } + +/* signalClone(): clones the signal handlers of a thread + * params: h - template signal handlers + * returns: pointer to the signal handler array, NULL on fail + */ + +void *signalClone(const void *h) { + void *new = malloc((MAX_SIGNAL+1) * sizeof(uintptr_t)); + if(!new) return NULL; + + return memcpy(new, h, (MAX_SIGNAL+1) * sizeof(uintptr_t)); +} \ No newline at end of file From 7d82e01681630711c848f2df729be96673b2467f Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 5 Nov 2024 13:58:08 -0500 Subject: [PATCH 14/67] ipc: use defaults when cloning non-existent signals --- src/ipc/signal.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ipc/signal.c b/src/ipc/signal.c index 389b7bc..5122745 100644 --- a/src/ipc/signal.c +++ b/src/ipc/signal.c @@ -95,11 +95,13 @@ void *signalDefaults() { } /* signalClone(): clones the signal handlers of a thread - * params: h - template signal handlers + * params: h - template signal handlers, NULL to use defaults * returns: pointer to the signal handler array, NULL on fail */ void *signalClone(const void *h) { + if(!h) return signalDefaults(); + void *new = malloc((MAX_SIGNAL+1) * sizeof(uintptr_t)); if(!new) return NULL; From 6199b912d1f78858aa16f85253d8c9352f0947b8 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 5 Nov 2024 13:58:44 -0500 Subject: [PATCH 15/67] sched: clone signal handlers in fork() --- src/sched/fork.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sched/fork.c b/src/sched/fork.c index ceb6877..03580e8 100644 --- a/src/sched/fork.c +++ b/src/sched/fork.c @@ -11,6 +11,7 @@ #include #include #include +#include /* fork(): forks the running thread * params: t - pointer to thread structure @@ -77,6 +78,9 @@ pid_t fork(Thread *t) { return -1; } + // clone signal handlers + p->threads[0]->signals = signalClone(t->signals); + // clone I/O descriptors Process *parent = getProcess(t->pid); if(parent) { From 0889c6be151979166ddafa3636b12d4baedf63d9 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 5 Nov 2024 14:12:37 -0500 Subject: [PATCH 16/67] ipc: added signal flag declarations --- src/include/kernel/signal.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/include/kernel/signal.h b/src/include/kernel/signal.h index 4226dac..02dbe98 100644 --- a/src/include/kernel/signal.h +++ b/src/include/kernel/signal.h @@ -49,6 +49,24 @@ #define MAX_SIGNAL 27 +/* Signal Flags */ +#define SA_NOCLDSTOP 0x0001 +#define SA_ONSTACK 0x0002 +#define SA_RESETHAND 0x0004 +#define SA_RESTART 0x0008 +#define SA_SIGINFO 0x0010 +#define SA_NOCLDWAIT 0x0020 +#define SA_NODEFER 0x0040 + +#define SIG_BLOCK 0x0001 +#define SIG_UNBLOCK 0x0002 + +#define SS_ONSTACK 0x0001 +#define SS_DISABLE 0x0002 + +#define MINSIGSTKSZ 4096 +#define SIGSTKSZ 16384 + typedef volatile uint32_t sig_atomic_t; typedef uint64_t sigset_t; From aa92131a007c689ccc22732729e396e15833d977 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Fri, 8 Nov 2024 15:21:00 -0500 Subject: [PATCH 17/67] platform: prototype for platform-specific signal mechanism --- src/include/platform/platform.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/include/platform/platform.h b/src/include/platform/platform.h index 2707d00..e0f3021 100644 --- a/src/include/platform/platform.h +++ b/src/include/platform/platform.h @@ -61,4 +61,5 @@ int platformGetMaxIRQ(); // maximum interrupt implemented by hardware int platformConfigureIRQ(Thread *, int, IRQHandler *); // configure an IRQ pin IRQCommand *platformGetIRQCommand(); // per-CPU IRQ command structure void platformIdle(); // to be called when the CPU is idle -void platformCleanThread(void *, uintptr_t); // garbage collector after thread is killed or replaced by exec() \ No newline at end of file +void platformCleanThread(void *, uintptr_t); // garbage collector after thread is killed or replaced by exec() +int platformSendSignal(Thread *, pid_t, int); From ff6a661261be8b73448d627ef896e03faf20fda5 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Fri, 8 Nov 2024 17:14:44 -0500 Subject: [PATCH 18/67] ipc: relay kill() to a platform-specific implementation --- src/ipc/signal.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/ipc/signal.c b/src/ipc/signal.c index 5122745..daed477 100644 --- a/src/ipc/signal.c +++ b/src/ipc/signal.c @@ -10,6 +10,7 @@ #include #include #include +#include /* Implementation of ISO C and POSIX Signals */ @@ -106,4 +107,25 @@ void *signalClone(const void *h) { if(!new) return NULL; return memcpy(new, h, (MAX_SIGNAL+1) * sizeof(uintptr_t)); +} + +/* kill(): sends a signal to a process or thread + * params: t - calling thread + * params: pid - pid of the process/thread to send a signal to + * pid > 0 refers to the process/thread whose PID/TID is exactly pid + * pid == 0 refers to processes whose process group ID is that of the sender + * pid == -1 refers to all processes that may receive the signal + * pid < -1 refers to the process group whose ID is the abs(pid) + * params: sig - signal to be sent, zero to test PID validitiy + * returns: zero on success, negative error code on fail + */ + +int kill(Thread *t, pid_t pid, int sig) { + if(sig < 0 || sig > MAX_SIGNAL) return -EINVAL; + + Thread *dest = getThread(pid); + if(!dest) return -ESRCH; + if(!sig) return 0; // verified that pid exists + + return platformSendSignal(t, pid, sig); } \ No newline at end of file From 597e27ca79bda29c9cbb42d8c62bdd294b1d5c52 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Fri, 8 Nov 2024 18:07:30 -0500 Subject: [PATCH 19/67] platform: removed implied redundancy in platform-specific signal mechanism --- src/include/platform/platform.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/platform/platform.h b/src/include/platform/platform.h index e0f3021..b36c471 100644 --- a/src/include/platform/platform.h +++ b/src/include/platform/platform.h @@ -62,4 +62,4 @@ int platformConfigureIRQ(Thread *, int, IRQHandler *); // configure an IRQ pin IRQCommand *platformGetIRQCommand(); // per-CPU IRQ command structure void platformIdle(); // to be called when the CPU is idle void platformCleanThread(void *, uintptr_t); // garbage collector after thread is killed or replaced by exec() -int platformSendSignal(Thread *, pid_t, int); +int platformSendSignal(Thread *, Thread *, int); From 46bc99ed3a28461a581151b9fd6b2e4ff35b34f9 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Fri, 8 Nov 2024 18:07:48 -0500 Subject: [PATCH 20/67] ipc: fixed invocation to match prototype --- src/ipc/signal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ipc/signal.c b/src/ipc/signal.c index daed477..4dc6cc1 100644 --- a/src/ipc/signal.c +++ b/src/ipc/signal.c @@ -127,5 +127,5 @@ int kill(Thread *t, pid_t pid, int sig) { if(!dest) return -ESRCH; if(!sig) return 0; // verified that pid exists - return platformSendSignal(t, pid, sig); + return platformSendSignal(t, dest, sig); } \ No newline at end of file From e36a9046e59fa90e5293e758f431656013cdb335 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Sun, 10 Nov 2024 20:38:12 -0500 Subject: [PATCH 21/67] ipc: added default signal handlers --- src/include/kernel/signal.h | 6 ++++++ src/ipc/signal.c | 43 +++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/src/include/kernel/signal.h b/src/include/kernel/signal.h index 02dbe98..83ef8aa 100644 --- a/src/include/kernel/signal.h +++ b/src/include/kernel/signal.h @@ -16,6 +16,12 @@ #define SIG_HOLD (void (*)(int))2 #define SIG_IGN (void (*)(int))3 +#define SIG_T 1 /* terminate */ +#define SIG_A 2 /* abort */ +#define SIG_C 3 /* continue */ +#define SIG_S 4 /* stop */ +#define SIG_I 5 /* ignore */ + /* ISO C Signals */ #define SIGABRT 1 #define SIGFPE 2 diff --git a/src/ipc/signal.c b/src/ipc/signal.c index 4dc6cc1..3a3d037 100644 --- a/src/ipc/signal.c +++ b/src/ipc/signal.c @@ -95,6 +95,49 @@ void *signalDefaults() { return (void *) ptr; } +/* signalDefaultHandler(): returns the default handler for a signal + * params: signum - signal number + * returns: default handler macro, zero on fail + */ + +int signalDefaultHandler(int signum) { + switch(signum) { + case SIGABRT: + case SIGBUS: + case SIGFPE: + case SIGILL: + case SIGQUIT: + case SIGSEGV: + case SIGSYS: + case SIGTRAP: + case SIGXCPU: + case SIGXFSZ: + return SIG_A; + + case SIGALRM: + case SIGHUP: + case SIGINT: + case SIGKILL: + case SIGPIPE: + case SIGTERM: + case SIGUSR1: + case SIGUSR2: + case SIGPOLL: + case SIGVTALRM: + return SIG_T; + + case SIGCHLD: + case SIGURG: + return SIG_I; + + case SIGCONT: + return SIG_C; + + default: + return 0; + } +} + /* signalClone(): clones the signal handlers of a thread * params: h - template signal handlers, NULL to use defaults * returns: pointer to the signal handler array, NULL on fail From 3ce6a59b0d54bc9ae971984c389c189b72a8717d Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Sun, 10 Nov 2024 20:41:07 -0500 Subject: [PATCH 22/67] ipc: exposed signal default handlers --- src/include/kernel/signal.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/include/kernel/signal.h b/src/include/kernel/signal.h index 83ef8aa..b37dc1e 100644 --- a/src/include/kernel/signal.h +++ b/src/include/kernel/signal.h @@ -101,6 +101,7 @@ int sigdelset(sigset_t *, int); int sigismember(sigset_t *, int); void *signalDefaults(); +int signalDefaultHandler(int); void *signalClone(const void *); int kill(Thread *, pid_t, int); From 3196c8565b5e3557dee6a82acd45e0138c280d29 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Sun, 10 Nov 2024 21:09:30 -0500 Subject: [PATCH 23/67] ipc: reworking signal mechanism --- src/ipc/signal.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ipc/signal.c b/src/ipc/signal.c index 3a3d037..45002a6 100644 --- a/src/ipc/signal.c +++ b/src/ipc/signal.c @@ -170,5 +170,6 @@ int kill(Thread *t, pid_t pid, int sig) { if(!dest) return -ESRCH; if(!sig) return 0; // verified that pid exists - return platformSendSignal(t, dest, sig); + /* todo */ + return 0; } \ No newline at end of file From b185537e28e00658e9833edc2679e328e255f449 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Sun, 10 Nov 2024 21:15:15 -0500 Subject: [PATCH 24/67] sched: added signal queue to thread control structure --- src/include/kernel/sched.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/include/kernel/sched.h b/src/include/kernel/sched.h index c194fb2..8ea7810 100644 --- a/src/include/kernel/sched.h +++ b/src/include/kernel/sched.h @@ -39,6 +39,12 @@ #define WNOHANG 0x02 #define WUNTRACED 0x04 +typedef struct SignalQueue { + struct SignalQueue *next; + int signum; + uintptr_t handler; +} SignalQueue; + typedef struct Thread { int status, cpu, priority; pid_t pid, tid; // pid == tid for the main thread @@ -48,6 +54,7 @@ typedef struct Thread { bool clean; // true when the exit status has been read by waitpid() void *signals; + SignalQueue *signalQueue; SyscallRequest syscall; // for when the thread is blocked int exitStatus; // for zombie threads From 5e007c5b614b13c0ab2556d472edcbf3723e9be1 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Mon, 11 Nov 2024 15:29:46 -0500 Subject: [PATCH 25/67] ipc: prototype for signal processing --- src/include/kernel/signal.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/include/kernel/signal.h b/src/include/kernel/signal.h index b37dc1e..6a13084 100644 --- a/src/include/kernel/signal.h +++ b/src/include/kernel/signal.h @@ -103,6 +103,7 @@ int sigismember(sigset_t *, int); void *signalDefaults(); int signalDefaultHandler(int); void *signalClone(const void *); +int signalProcess(Thread *); int kill(Thread *, pid_t, int); int sigaction(Thread *, int, const struct sigaction *, struct sigaction *); From b2f6164fd88e3e83f9bda651909b075e2e89fcf4 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Mon, 11 Nov 2024 16:09:09 -0500 Subject: [PATCH 26/67] ipc: implemented signal sending mechanism --- src/ipc/signal.c | 74 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 70 insertions(+), 4 deletions(-) diff --git a/src/ipc/signal.c b/src/ipc/signal.c index 45002a6..19feac8 100644 --- a/src/ipc/signal.c +++ b/src/ipc/signal.c @@ -10,6 +10,7 @@ #include #include #include +#include #include /* Implementation of ISO C and POSIX Signals */ @@ -166,10 +167,75 @@ void *signalClone(const void *h) { int kill(Thread *t, pid_t pid, int sig) { if(sig < 0 || sig > MAX_SIGNAL) return -EINVAL; - Thread *dest = getThread(pid); - if(!dest) return -ESRCH; - if(!sig) return 0; // verified that pid exists + pid_t group; + Process *parent; + Thread *dest; + + if(pid == -1) return -EPERM; /* placeholder */ + + if(pid < -1) group = -1 * pid; + else if(!pid) group = t->pid; + else group = 0; + + if(group) { + parent = getProcess(group); + if(!parent) return -ESRCH; + } else { + dest = getThread(pid); + if(!dest) return -ESRCH; + } + + if(!sig) return 0; // null signal verifies that pid is valid + + if(group) { + // send the signal to all threads of the parent as well as all threads + // of all the children + if(!parent->threads || !parent->threadCount) return 0; + + for(int i = 0; i < parent->threadCount; i++) { + dest = parent->threads[i]; + if(dest) { + int status = kill(t, dest->tid, sig); + if(status) return status; + } + } + + if(!parent->children || !parent->childrenCount) return 0; + + Process *child; + for(int i = 0; i < parent->childrenCount; i++) { + child = parent->children[i]; + if(!child || !child->threads || !child->threadCount) + continue; + + for(int j = 0; j < child->threadCount; j++) { + dest = child->threads[j]; + if(dest) { + int status = kill(t, dest->tid, sig); + if(status) return status; + } + } + } + } else { + // send the signal to the exact thread specified by pid + SignalQueue *s = calloc(1, sizeof(SignalQueue)); + if(!s) return -ENOMEM; + + s->signum = sig; + s->next = NULL; + + acquireLockBlocking(&dest->lock); + + SignalQueue *q = dest->signalQueue; + if(!q) { + dest->signalQueue = s; + } else { + while(q->next) q = q->next; + q->next = s; + } + + releaseLock(&dest->lock); + } - /* todo */ return 0; } \ No newline at end of file From c6904739e952aeea89cf9ecb16a9f8e84042161c Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 12 Nov 2024 11:53:15 -0500 Subject: [PATCH 27/67] sched: remove unnecessary lock from yield syscall --- src/sched/sched.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/sched/sched.c b/src/sched/sched.c index 8cdefd7..9bc33f8 100644 --- a/src/sched/sched.c +++ b/src/sched/sched.c @@ -513,12 +513,8 @@ void unblockThread(Thread *t) { */ int yield(Thread *t) { - acquireLockBlocking(&lock); - t->status = THREAD_QUEUED; t->time = schedTimeslice(t, t->priority); - - releaseLock(&lock); return 0; } From 20c0714bc70ddfd63e95bbbd00b7fc0210fefed0 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 19 Nov 2024 15:35:13 -0500 Subject: [PATCH 28/67] libc: remove uncached malloc --- src/include/stdlib.h | 1 - src/libc/stdlib.c | 22 ---------------------- 2 files changed, 23 deletions(-) diff --git a/src/include/stdlib.h b/src/include/stdlib.h index f344244..48d0ce2 100644 --- a/src/include/stdlib.h +++ b/src/include/stdlib.h @@ -19,7 +19,6 @@ char *itoa(int, char *, int); int atoi(const char *); char *ltoa(long, char *, int); long atol(const char *); -void *mallocUC(size_t); void *malloc(size_t); void *calloc(size_t, size_t); void *realloc(void *, size_t); diff --git a/src/libc/stdlib.c b/src/libc/stdlib.c index 951769e..3c56b23 100644 --- a/src/libc/stdlib.c +++ b/src/libc/stdlib.c @@ -122,28 +122,6 @@ void *malloc(size_t size) { return (void *)((uintptr_t)ptr + sizeof(struct mallocHeader)); } -void *mallocUC(size_t size) { - /* special case for malloc that uses uncacheable memory */ - if(!size) return NULL; - size_t pageSize = (size + sizeof(struct mallocHeader) + PAGE_SIZE - 1) / PAGE_SIZE; - - acquireLockBlocking(&lock); - - uintptr_t ptr = vmmAllocate(KERNEL_HEAP_BASE, KERNEL_HEAP_LIMIT, pageSize, VMM_WRITE | VMM_NO_CACHE); - if(!ptr) { - releaseLock(&lock); - return NULL; - } - - struct mallocHeader *header = (struct mallocHeader *)ptr; - header->byteSize = size; - header->pageSize = pageSize; - - releaseLock(&lock); - - return (void *)((uintptr_t)ptr + sizeof(struct mallocHeader)); -} - void *calloc(size_t num, size_t size) { void *ptr = malloc(num * size); if(!ptr) return NULL; From c9f7bc57a194fd3b86ff3beed833c4e1dc8c6d0a Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 19 Nov 2024 15:53:02 -0500 Subject: [PATCH 29/67] x86_64: defined user space signal struct addresses --- src/platform/x86_64/include/platform/mmap.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/platform/x86_64/include/platform/mmap.h b/src/platform/x86_64/include/platform/mmap.h index e1c6ea4..d19e984 100644 --- a/src/platform/x86_64/include/platform/mmap.h +++ b/src/platform/x86_64/include/platform/mmap.h @@ -19,5 +19,7 @@ #define KERNEL_HEAP_LIMIT (uintptr_t)0xFFFF8FFFFFFFFFFF #define KERNEL_MMIO_LIMIT ((uint64_t)KERNEL_BASE_MAPPED << 30) #define USER_BASE_ADDRESS 0x400000 // 4 MB, user programs will be loaded here +#define USER_HEAP_BASE (uintptr_t)0x00006FFF80000000 // for signal structures +#define USER_HEAP_LIMIT (uintptr_t)0x00006FFFFFFFFFFF // 2 GB of space #define USER_MMIO_BASE (uintptr_t)0x0000700000000000 // for mmap() and similar syscalls #define USER_LIMIT_ADDRESS (KERNEL_BASE_ADDRESS-1) // maximum limit for the lower half From 585092c56c41f44aeb944e6de6d8f5425444b0d7 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 19 Nov 2024 15:53:49 -0500 Subject: [PATCH 30/67] libc: malloc() family for user space --- src/include/stdlib.h | 3 +++ src/libc/stdlib.c | 57 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/src/include/stdlib.h b/src/include/stdlib.h index 48d0ce2..fcb9d43 100644 --- a/src/include/stdlib.h +++ b/src/include/stdlib.h @@ -22,6 +22,9 @@ long atol(const char *); void *malloc(size_t); void *calloc(size_t, size_t); void *realloc(void *, size_t); +void *umalloc(size_t); +void *ucalloc(size_t, size_t); +void *urealloc(void *, size_t); void free(void *); int rand(); void srand(unsigned int); diff --git a/src/libc/stdlib.c b/src/libc/stdlib.c index 3c56b23..103d183 100644 --- a/src/libc/stdlib.c +++ b/src/libc/stdlib.c @@ -122,6 +122,33 @@ void *malloc(size_t size) { return (void *)((uintptr_t)ptr + sizeof(struct mallocHeader)); } +void *umalloc(size_t size) { + /* this is the exact same as malloc() but allocates in the user space to + * be used for signal structures */ + if(!size) return NULL; + size_t pageSize = (size + sizeof(struct mallocHeader) + PAGE_SIZE - 1) / PAGE_SIZE; + + acquireLockBlocking(&lock); + + uintptr_t ptr = vmmAllocate(USER_HEAP_BASE, USER_HEAP_LIMIT, pageSize, VMM_WRITE | VMM_USER); + if(!ptr) { + releaseLock(&lock); + return NULL; + } + + struct mallocHeader *header = (struct mallocHeader *)ptr; + header->byteSize = size; + header->pageSize = pageSize; + + // allocate a guard page as well + uintptr_t guard = ptr + (pageSize*PAGE_SIZE); + platformMapPage(guard, 0, 0); + + releaseLock(&lock); + + return (void *)((uintptr_t)ptr + sizeof(struct mallocHeader)); +} + void *calloc(size_t num, size_t size) { void *ptr = malloc(num * size); if(!ptr) return NULL; @@ -129,6 +156,13 @@ void *calloc(size_t num, size_t size) { return ptr; } +void *ucalloc(size_t num, size_t size) { + void *ptr = umalloc(num * size); + if(!ptr) return NULL; + memset(ptr, 0, num * size); + return ptr; +} + void *realloc(void *ptr, size_t newSize) { if(!newSize) return NULL; if(!ptr) return malloc(newSize); @@ -152,6 +186,29 @@ void *realloc(void *ptr, size_t newSize) { return newPtr; } +void *urealloc(void *ptr, size_t newSize) { + if(!newSize) return NULL; + if(!ptr) return umalloc(newSize); + + void *newPtr = umalloc(newSize); + if(!newPtr) return NULL; + + uintptr_t oldBase = (uintptr_t)ptr; + oldBase &= ~(PAGE_SIZE-1); + struct mallocHeader *header = (struct mallocHeader *)oldBase; + size_t oldSize = header->byteSize; + + if(oldSize > newSize) { + // we're shrinking the memory, copy the new size only + memcpy(newPtr, ptr, newSize); + } else { + memcpy(newPtr, ptr, oldSize); + } + + free(ptr); + return newPtr; +} + void free(void *ptr) { if(!ptr) return; uintptr_t base = (uintptr_t)ptr; From 69498349b32ab9e72aa0782d7c4e51fedcba15fa Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 19 Nov 2024 17:08:47 -0500 Subject: [PATCH 31/67] sched: added signal handle flag to thread structure --- src/include/kernel/sched.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/include/kernel/sched.h b/src/include/kernel/sched.h index ba7b07d..bf7a7c0 100644 --- a/src/include/kernel/sched.h +++ b/src/include/kernel/sched.h @@ -54,6 +54,7 @@ typedef struct Thread { bool normalExit; // true when the thread ends by exit() and is not forcefully killed bool clean; // true when the exit status has been read by waitpid() + bool handlingSignal; // true inside a signal handler void *signals; SignalQueue *signalQueue; From 4d98671d9b8228b6de090e7afd82fa17ef3a326a Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 19 Nov 2024 17:17:53 -0500 Subject: [PATCH 32/67] ipc: process signal queue for default signals --- src/include/kernel/signal.h | 2 +- src/ipc/signal.c | 44 +++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/include/kernel/signal.h b/src/include/kernel/signal.h index 6a13084..a6e9156 100644 --- a/src/include/kernel/signal.h +++ b/src/include/kernel/signal.h @@ -103,7 +103,7 @@ int sigismember(sigset_t *, int); void *signalDefaults(); int signalDefaultHandler(int); void *signalClone(const void *); -int signalProcess(Thread *); +void signalHandle(Thread *); int kill(Thread *, pid_t, int); int sigaction(Thread *, int, const struct sigaction *, struct sigaction *); diff --git a/src/ipc/signal.c b/src/ipc/signal.c index 19feac8..ca41177 100644 --- a/src/ipc/signal.c +++ b/src/ipc/signal.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -238,4 +239,47 @@ int kill(Thread *t, pid_t pid, int sig) { } return 0; +} + +/* signalHandle(): checks the signal queue and invokes a signal handler + * params: t - thread to check + * returns: nothing + */ + +void signalHandle(Thread *t) { + if(t->handlingSignal || t->signalQueue) return; + + // linked list structure + SignalQueue *s = t->signalQueue; + t->signalQueue = s->next; + + uintptr_t *handlers = (uintptr_t *) t->signals; + uintptr_t handler = handlers[s->signum]; + int def = 0; + + switch(handler) { + case (uintptr_t) SIG_IGN: + case (uintptr_t) SIG_HOLD: + return; + case (uintptr_t) SIG_DFL: + def = signalDefaultHandler(s->signum); + break; + } + + switch(def) { + case SIG_I: + case SIG_C: + return; + case SIG_T: + case SIG_A: + case SIG_S: + schedLock(); + terminateThread(t, -1, true); + schedRelease(); + break; + default: + // TODO: execute the custom signal handler here + KERROR("TODO: execute custom signal handler\n"); + for(;;); + } } \ No newline at end of file From 0d98132bc07be71a299a47669d142636891f9df0 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 19 Nov 2024 17:18:41 -0500 Subject: [PATCH 33/67] ipc: typo in null pointer check --- src/ipc/signal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ipc/signal.c b/src/ipc/signal.c index ca41177..9031f85 100644 --- a/src/ipc/signal.c +++ b/src/ipc/signal.c @@ -247,7 +247,7 @@ int kill(Thread *t, pid_t pid, int sig) { */ void signalHandle(Thread *t) { - if(t->handlingSignal || t->signalQueue) return; + if(t->handlingSignal || !t->signalQueue) return; // linked list structure SignalQueue *s = t->signalQueue; From 856aeb5c9910da85c3d4fb24494cc6dc898ea49f Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 19 Nov 2024 17:20:04 -0500 Subject: [PATCH 34/67] sched: handle signals upon task switch --- src/sched/sched.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sched/sched.c b/src/sched/sched.c index 9bc33f8..2d5309a 100644 --- a/src/sched/sched.c +++ b/src/sched/sched.c @@ -12,6 +12,7 @@ #include #include #include +#include #include static bool scheduling = false; @@ -353,6 +354,7 @@ void schedule() { if(current && (current->status == THREAD_RUNNING)) current->status = THREAD_QUEUED; + signalHandle(t); t->status = THREAD_RUNNING; t->time = schedTimeslice(t, t->priority); t->cpu = cpu; From 237463eedb165c8b170d3a5aa7b6f7d011d5ed5e Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 19 Nov 2024 17:25:19 -0500 Subject: [PATCH 35/67] syscalls: bumped max syscall index --- src/include/kernel/syscalls.h | 2 +- src/syscalls/dispatch.c | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/include/kernel/syscalls.h b/src/include/kernel/syscalls.h index 7751c7a..75f959d 100644 --- a/src/include/kernel/syscalls.h +++ b/src/include/kernel/syscalls.h @@ -11,7 +11,7 @@ #include #include -#define MAX_SYSCALL 56 +#define MAX_SYSCALL 58 /* IPC syscall indexes, this range will be used for immediate handling without * waiting for the kernel thread to dispatch the syscall */ diff --git a/src/syscalls/dispatch.c b/src/syscalls/dispatch.c index 0d94a27..e061d82 100644 --- a/src/syscalls/dispatch.c +++ b/src/syscalls/dispatch.c @@ -584,17 +584,19 @@ void (*syscallDispatchTable[])(SyscallRequest *) = { syscallDispatchRecv, // 45 - recv() syscallDispatchSend, // 46 - send() NULL, // 47 - kill() + NULL, // 48 - sigaction() + NULL, // 49 - sigreturn() /* group 4: memory management */ - syscallDispatchSBrk, // 48 - sbrk() - NULL, // 49 - mmap() - NULL, // 50 - munmap() + syscallDispatchSBrk, // 50 - sbrk() + NULL, // 51 - mmap() + NULL, // 52 - munmap() /* group 5: driver I/O functions */ - syscallDispatchIoperm, // 51 - ioperm() - syscallDispatchIRQ, // 52 - irq() - syscallDispatchIoctl, // 53 - ioctl() - syscallDispatchMMIO, // 54 - mmio() - syscallDispatchPContig, // 55 - pcontig() - syscallDispatchVToP, // 56 - vtop() + syscallDispatchIoperm, // 53 - ioperm() + syscallDispatchIRQ, // 54 - irq() + syscallDispatchIoctl, // 55 - ioctl() + syscallDispatchMMIO, // 56 - mmio() + syscallDispatchPContig, // 57 - pcontig() + syscallDispatchVToP, // 58 - vtop() }; From 99ef1064147bc81c04c7c618ed356b9127396890 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 19 Nov 2024 17:31:26 -0500 Subject: [PATCH 36/67] syscalls: dispatch kill() --- src/syscalls/dispatch.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/syscalls/dispatch.c b/src/syscalls/dispatch.c index e061d82..e1ea8ed 100644 --- a/src/syscalls/dispatch.c +++ b/src/syscalls/dispatch.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -478,6 +479,11 @@ void syscallDispatchSend(SyscallRequest *req) { } } +void syscallDispatchKill(SyscallRequest *req) { + req->ret = kill(req->thread, req->params[0], req->params[1]); + req->unblock = true; +} + /* Group 4: Memory Management */ void syscallDispatchSBrk(SyscallRequest *req) { @@ -583,7 +589,7 @@ void (*syscallDispatchTable[])(SyscallRequest *) = { syscallDispatchAccept, // 44 - accept() syscallDispatchRecv, // 45 - recv() syscallDispatchSend, // 46 - send() - NULL, // 47 - kill() + syscallDispatchKill, // 47 - kill() NULL, // 48 - sigaction() NULL, // 49 - sigreturn() From e0b8afceb1f40e5400f2c105b76e8eed373f7687 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 19 Nov 2024 21:22:08 -0500 Subject: [PATCH 37/67] sched: check thread exit status when signals are raised --- src/sched/sched.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/sched/sched.c b/src/sched/sched.c index 2d5309a..2025718 100644 --- a/src/sched/sched.c +++ b/src/sched/sched.c @@ -355,11 +355,15 @@ void schedule() { current->status = THREAD_QUEUED; signalHandle(t); - t->status = THREAD_RUNNING; - t->time = schedTimeslice(t, t->priority); - t->cpu = cpu; - releaseLock(&lock); - platformSwitchContext(t); + + if(t->status == THREAD_QUEUED) { + // check status again because the signal handler may terminate a thread + t->status = THREAD_RUNNING; + t->time = schedTimeslice(t, t->priority); + t->cpu = cpu; + releaseLock(&lock); + platformSwitchContext(t); + } } t = t->next; From 43416aa2c2b2cce641492203fa2eccdacf711e79 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 19 Nov 2024 21:22:35 -0500 Subject: [PATCH 38/67] ipc: typo in default signal handler setup --- src/ipc/signal.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/ipc/signal.c b/src/ipc/signal.c index 9031f85..9a5603d 100644 --- a/src/ipc/signal.c +++ b/src/ipc/signal.c @@ -92,7 +92,7 @@ void *signalDefaults() { if(!ptr) return NULL; for(int i = 0; i < MAX_SIGNAL; i++) - *ptr = (uintptr_t) SIG_DFL; // default + ptr[i] = (uintptr_t) SIG_DFL; // default return (void *) ptr; } @@ -273,13 +273,11 @@ void signalHandle(Thread *t) { case SIG_T: case SIG_A: case SIG_S: - schedLock(); terminateThread(t, -1, true); - schedRelease(); break; default: // TODO: execute the custom signal handler here - KERROR("TODO: execute custom signal handler\n"); + KERROR("TODO: execute custom signal handler: handler = %X, def = %d\n", handler, def); for(;;); } } \ No newline at end of file From 95197ac19890c2fbee5415f48118481d657a3751 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 19 Nov 2024 21:28:32 -0500 Subject: [PATCH 39/67] ipc: cleaned up signal handler and removed memory leak --- src/ipc/signal.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/ipc/signal.c b/src/ipc/signal.c index 9a5603d..81a57d6 100644 --- a/src/ipc/signal.c +++ b/src/ipc/signal.c @@ -249,20 +249,27 @@ int kill(Thread *t, pid_t pid, int sig) { void signalHandle(Thread *t) { if(t->handlingSignal || !t->signalQueue) return; + acquireLockBlocking(&t->lock); + // linked list structure SignalQueue *s = t->signalQueue; t->signalQueue = s->next; + releaseLock(&t->lock); + + int signum = s->signum; uintptr_t *handlers = (uintptr_t *) t->signals; - uintptr_t handler = handlers[s->signum]; + uintptr_t handler = handlers[signum]; int def = 0; + + free(s); switch(handler) { case (uintptr_t) SIG_IGN: case (uintptr_t) SIG_HOLD: return; case (uintptr_t) SIG_DFL: - def = signalDefaultHandler(s->signum); + def = signalDefaultHandler(signum); break; } From c102c4b726d109f8d191b1b9b1f4a4fc575921c1 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Wed, 20 Nov 2024 13:19:29 -0500 Subject: [PATCH 40/67] ipc: refined signal handler structures --- src/include/kernel/signal.h | 2 +- src/ipc/signal.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/include/kernel/signal.h b/src/include/kernel/signal.h index a6e9156..44a39a6 100644 --- a/src/include/kernel/signal.h +++ b/src/include/kernel/signal.h @@ -88,7 +88,7 @@ struct sigaction { union { void (*sa_handler)(int); void (*sa_sigaction)(int, siginfo_t *, void *); - } handler; + }; sigset_t sa_mask; int sa_flags; diff --git a/src/ipc/signal.c b/src/ipc/signal.c index 81a57d6..41fe19e 100644 --- a/src/ipc/signal.c +++ b/src/ipc/signal.c @@ -88,11 +88,11 @@ int sigismember(sigset_t *set, int signum) { */ void *signalDefaults() { - uintptr_t *ptr = malloc((MAX_SIGNAL+1) * sizeof(uintptr_t)); + struct sigaction *ptr = malloc((MAX_SIGNAL+1) * sizeof(struct sigaction)); if(!ptr) return NULL; for(int i = 0; i < MAX_SIGNAL; i++) - ptr[i] = (uintptr_t) SIG_DFL; // default + ptr[i].sa_handler = SIG_DFL; // default return (void *) ptr; } @@ -148,10 +148,10 @@ int signalDefaultHandler(int signum) { void *signalClone(const void *h) { if(!h) return signalDefaults(); - void *new = malloc((MAX_SIGNAL+1) * sizeof(uintptr_t)); + void *new = malloc((MAX_SIGNAL+1) * sizeof(struct sigaction)); if(!new) return NULL; - return memcpy(new, h, (MAX_SIGNAL+1) * sizeof(uintptr_t)); + return memcpy(new, h, (MAX_SIGNAL+1) * sizeof(struct sigaction)); } /* kill(): sends a signal to a process or thread @@ -258,8 +258,8 @@ void signalHandle(Thread *t) { releaseLock(&t->lock); int signum = s->signum; - uintptr_t *handlers = (uintptr_t *) t->signals; - uintptr_t handler = handlers[signum]; + struct sigaction *handlers = (struct sigaction *) t->signals; + uintptr_t handler = (uintptr_t) handlers[signum].sa_handler; int def = 0; free(s); From d9b90f059789e7bcf6119056ab3daf78ed1f33a6 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Wed, 20 Nov 2024 13:31:29 -0500 Subject: [PATCH 41/67] ipc: signal numbering fixes --- src/ipc/signal.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ipc/signal.c b/src/ipc/signal.c index 41fe19e..fdc9776 100644 --- a/src/ipc/signal.c +++ b/src/ipc/signal.c @@ -47,7 +47,7 @@ int sigfillset(sigset_t *set) { */ int sigaddset(sigset_t *set, int signum) { - if(signum < 0 || signum > MAX_SIGNAL) + if(signum <= 0 || signum > MAX_SIGNAL) return -EINVAL; *set |= (1 << signum); @@ -61,7 +61,7 @@ int sigaddset(sigset_t *set, int signum) { */ int sigdelset(sigset_t *set, int signum) { - if(signum < 0 || signum > MAX_SIGNAL) + if(signum <= 0 || signum > MAX_SIGNAL) return -EINVAL; *set &= ~(1 << signum); @@ -75,7 +75,7 @@ int sigdelset(sigset_t *set, int signum) { */ int sigismember(sigset_t *set, int signum) { - if(signum < 0 || signum > MAX_SIGNAL) + if(signum <= 0 || signum > MAX_SIGNAL) return -EINVAL; if(*set & (1 << signum)) return 1; @@ -257,7 +257,7 @@ void signalHandle(Thread *t) { releaseLock(&t->lock); - int signum = s->signum; + int signum = s->signum - 1; // change to zero-based struct sigaction *handlers = (struct sigaction *) t->signals; uintptr_t handler = (uintptr_t) handlers[signum].sa_handler; int def = 0; @@ -269,7 +269,7 @@ void signalHandle(Thread *t) { case (uintptr_t) SIG_HOLD: return; case (uintptr_t) SIG_DFL: - def = signalDefaultHandler(signum); + def = signalDefaultHandler(signum + 1); break; } From 2db1134465bec5753497f017ef5f8e5c17722fd9 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Wed, 20 Nov 2024 13:42:11 -0500 Subject: [PATCH 42/67] ipc: implemented sigaction() --- src/ipc/signal.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/ipc/signal.c b/src/ipc/signal.c index fdc9776..7c5c146 100644 --- a/src/ipc/signal.c +++ b/src/ipc/signal.c @@ -12,6 +12,7 @@ #include #include #include +#include #include /* Implementation of ISO C and POSIX Signals */ @@ -287,4 +288,40 @@ void signalHandle(Thread *t) { KERROR("TODO: execute custom signal handler: handler = %X, def = %d\n", handler, def); for(;;); } +} + +/* sigaction(): manipulate a signal handler + * params: t - calling thread + * params: sig - signal number + * params: act - new signal handler, NULL to query the current signal handler + * params: oact - old signal handler, NULL if not requested + * returns: zero on success, negative errno on fail + */ + +int sigaction(Thread *t, int sig, const struct sigaction *act, struct sigaction *oact) { + if(sig <= 0 || sig > MAX_SIGNAL) return -EINVAL; + + struct sigaction *handlers = (struct sigaction *) t->signals; + + if(!act) { + // query signal handler + if(!oact) return 0; + memcpy(oact, &handlers[sig-1], sizeof(struct sigaction)); + return 0; + } + + uintptr_t handler = (uintptr_t) act->sa_handler; + if(handler != (uintptr_t) SIG_DFL && handler != (uintptr_t) SIG_IGN && + handler < USER_BASE_ADDRESS) + return -EINVAL; + + acquireLockBlocking(&t->lock); + + // save the old signal handler if necessary + if(oact) + memcpy(oact, &handlers[sig-1], sizeof(struct sigaction)); + + memcpy(&handlers[sig-1], act, sizeof(struct sigaction)); + releaseLock(&t->lock); + return 0; } \ No newline at end of file From 2ad11c9dcbb59179b5653b23f234911a7ba4343a Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Wed, 20 Nov 2024 13:48:24 -0500 Subject: [PATCH 43/67] syscalls: dispatch sigaction() --- src/syscalls/dispatch.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/syscalls/dispatch.c b/src/syscalls/dispatch.c index e1ea8ed..da4116d 100644 --- a/src/syscalls/dispatch.c +++ b/src/syscalls/dispatch.c @@ -484,6 +484,14 @@ void syscallDispatchKill(SyscallRequest *req) { req->unblock = true; } +void syscallDispatchSigAction(SyscallRequest *req) { + if((!req->params[1] || (req->params[1] && syscallVerifyPointer(req, req->params[1], sizeof(struct sigaction)))) && + (!req->params[2] || (req->params[2] && syscallVerifyPointer(req, req->params[2], sizeof(struct sigaction))))) { + req->ret = sigaction(req->thread, req->params[0], (const struct sigaction *) req->params[1], (struct sigaction *) req->params[2]); + req->unblock = true; + } +} + /* Group 4: Memory Management */ void syscallDispatchSBrk(SyscallRequest *req) { @@ -590,7 +598,7 @@ void (*syscallDispatchTable[])(SyscallRequest *) = { syscallDispatchRecv, // 45 - recv() syscallDispatchSend, // 46 - send() syscallDispatchKill, // 47 - kill() - NULL, // 48 - sigaction() + syscallDispatchSigAction, // 48 - sigaction() NULL, // 49 - sigreturn() /* group 4: memory management */ From de035473227ba8c61f07fa91d1bc14908e0a03d4 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Wed, 20 Nov 2024 15:20:31 -0500 Subject: [PATCH 44/67] syscalls: ensure thread still exists when handling syscalls --- src/syscalls/queue.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/syscalls/queue.c b/src/syscalls/queue.c index c3a9239..33b06e3 100644 --- a/src/syscalls/queue.c +++ b/src/syscalls/queue.c @@ -106,6 +106,7 @@ int syscallProcess() { if(!requests) return 0; SyscallRequest *syscall = syscallDequeue(); if(!syscall) return 0; + if(syscall->thread->status != THREAD_BLOCKED) return 0; setLocalSched(false); From 9c4716fedb0258298e52d545454a5c4afb38c70a Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Wed, 20 Nov 2024 15:30:34 -0500 Subject: [PATCH 45/67] syscalls: unblock threads when a signal is raised --- src/syscalls/queue.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/syscalls/queue.c b/src/syscalls/queue.c index 33b06e3..4a7df54 100644 --- a/src/syscalls/queue.c +++ b/src/syscalls/queue.c @@ -9,6 +9,7 @@ #include #include #include +#include #include static SyscallRequest *requests = NULL; // sort of a linked list in a sense @@ -118,10 +119,17 @@ int syscallProcess() { terminateThread(syscall->thread, -1, false); schedRelease(); } else { - threadUseContext(syscall->thread->tid); - syscallDispatchTable[syscall->function](syscall); - platformSetContextStatus(syscall->thread->context, syscall->ret); - //threadUseContext(getTid()); + signalHandle(syscall->thread); + if(syscall->thread->status == THREAD_ZOMBIE) { + setLocalSched(true); + return 1; + } else if(syscall->thread->status == THREAD_QUEUED) { + syscallEnqueue(syscall); + } else if(syscall->thread->status == THREAD_BLOCKED) { + threadUseContext(syscall->thread->tid); + syscallDispatchTable[syscall->function](syscall); + platformSetContextStatus(syscall->thread->context, syscall->ret); + } } if((syscall->thread->status == THREAD_BLOCKED) && syscall->unblock) { From c2d873dd2bf7e1d07f1eec340bcdead17e4b3d3a Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Wed, 20 Nov 2024 17:54:21 -0500 Subject: [PATCH 46/67] libc: malloc() variant with execute perms --- src/include/stdlib.h | 1 + src/libc/stdlib.c | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/include/stdlib.h b/src/include/stdlib.h index fcb9d43..47922a7 100644 --- a/src/include/stdlib.h +++ b/src/include/stdlib.h @@ -23,6 +23,7 @@ void *malloc(size_t); void *calloc(size_t, size_t); void *realloc(void *, size_t); void *umalloc(size_t); +void *uxmalloc(size_t); void *ucalloc(size_t, size_t); void *urealloc(void *, size_t); void free(void *); diff --git a/src/libc/stdlib.c b/src/libc/stdlib.c index 103d183..3290762 100644 --- a/src/libc/stdlib.c +++ b/src/libc/stdlib.c @@ -149,6 +149,33 @@ void *umalloc(size_t size) { return (void *)((uintptr_t)ptr + sizeof(struct mallocHeader)); } +void *uxmalloc(size_t size) { + /* again exactly the same umalloc() but with execute permissions, this will + * be used for installing platform-specific signal trampoline code */ + if(!size) return NULL; + size_t pageSize = (size + sizeof(struct mallocHeader) + PAGE_SIZE - 1) / PAGE_SIZE; + + acquireLockBlocking(&lock); + + uintptr_t ptr = vmmAllocate(USER_HEAP_BASE, USER_HEAP_LIMIT, pageSize, VMM_WRITE | VMM_USER | VMM_EXEC); + if(!ptr) { + releaseLock(&lock); + return NULL; + } + + struct mallocHeader *header = (struct mallocHeader *)ptr; + header->byteSize = size; + header->pageSize = pageSize; + + // allocate a guard page as well + uintptr_t guard = ptr + (pageSize*PAGE_SIZE); + platformMapPage(guard, 0, 0); + + releaseLock(&lock); + + return (void *)((uintptr_t)ptr + sizeof(struct mallocHeader)); +} + void *calloc(size_t num, size_t size) { void *ptr = malloc(num * size); if(!ptr) return NULL; From 22fe3840ffb4b171323ee178b1dc9e8937cccb1b Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Wed, 20 Nov 2024 18:13:02 -0500 Subject: [PATCH 47/67] x86_64: signal trampoline code --- src/platform/x86_64/ipc/sigstub.asm | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/platform/x86_64/ipc/sigstub.asm diff --git a/src/platform/x86_64/ipc/sigstub.asm b/src/platform/x86_64/ipc/sigstub.asm new file mode 100644 index 0000000..4449bca --- /dev/null +++ b/src/platform/x86_64/ipc/sigstub.asm @@ -0,0 +1,25 @@ + +; lux - a lightweight unix-like operating system +; Omar Elghoul, 2024 + +[bits 64] + +; Signal Trampoline Code +; this simply invokes the sigreturn() system call to allow the kernel to +; restore the state of the thread before the signal was raised + +SYSCALL_SIGRETURN equ 49 + +section .data + +global sigstub +align 16 +sigstub: + mov rax, SYSCALL_SIGRETURN + syscall + +sigstubEnd: + +global sigstubSize +align 16 +sigstubSize: dq sigstubEnd - sigstub From 2fdd8d74712d335f4c4f60ce6f27171025c4bfb0 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 26 Nov 2024 14:45:56 -0500 Subject: [PATCH 48/67] sched: added signal trampoline and context to thread structure --- src/include/kernel/sched.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/include/kernel/sched.h b/src/include/kernel/sched.h index bf7a7c0..69ba277 100644 --- a/src/include/kernel/sched.h +++ b/src/include/kernel/sched.h @@ -58,6 +58,7 @@ typedef struct Thread { void *signals; SignalQueue *signalQueue; + uintptr_t signalTrampoline; SyscallRequest syscall; // for when the thread is blocked int exitStatus; // for zombie threads @@ -66,6 +67,7 @@ typedef struct Thread { struct Thread *next; void *context; // platform-specific (page tables, registers, etc) + void *signalContext; uintptr_t highest; } Thread; From 8adc92f90dbdb822b778a78740e3b7b8c069cd72 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 26 Nov 2024 14:48:36 -0500 Subject: [PATCH 49/67] sched: allocate memory for signal context in fork() --- src/sched/fork.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sched/fork.c b/src/sched/fork.c index 03580e8..1afc7eb 100644 --- a/src/sched/fork.c +++ b/src/sched/fork.c @@ -53,6 +53,7 @@ pid_t fork(Thread *t) { p->threads[0]->pid = pid; p->threads[0]->tid = pid; p->threads[0]->context = calloc(1, PLATFORM_CONTEXT_SIZE); + p->threads[0]->signalContext = calloc(1, PLATFORM_CONTEXT_SIZE); p->threads[0]->highest = t->highest; p->threads[0]->pages = t->pages; @@ -60,7 +61,7 @@ pid_t fork(Thread *t) { // entire process memory, but just the calling thread p->pages = t->pages; - if(!p->threads[0]->context) { + if(!p->threads[0]->context || !p->threads[0]->signalContext) { free(p->threads[0]); free(p->threads); free(p); From 002f2e78fbef88cce573196f6ed1467b804a2398 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 26 Nov 2024 14:55:40 -0500 Subject: [PATCH 50/67] x86_64: declaration for signal trampoline setup --- src/platform/x86_64/include/platform/context.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/platform/x86_64/include/platform/context.h b/src/platform/x86_64/include/platform/context.h index 5fae4a4..8f545c0 100644 --- a/src/platform/x86_64/include/platform/context.h +++ b/src/platform/x86_64/include/platform/context.h @@ -50,6 +50,7 @@ typedef struct { void *platformCreateContext(void *, int, uintptr_t, uintptr_t); int platformSetContext(Thread *, uintptr_t, uintptr_t, const char **, const char **); +int platformSignalSetup(Thread *); #define PLATFORM_CONTEXT_SIZE sizeof(ThreadContext) From f756686aa840cebd361f9da8ee8fb2dcb37bcb5c Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 26 Nov 2024 14:55:59 -0500 Subject: [PATCH 51/67] x86_64: set up signal trampoline in context initializer --- src/platform/x86_64/sched/context.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/platform/x86_64/sched/context.c b/src/platform/x86_64/sched/context.c index 35b7e1e..0cc5ff0 100644 --- a/src/platform/x86_64/sched/context.c +++ b/src/platform/x86_64/sched/context.c @@ -135,6 +135,8 @@ int platformSetContext(Thread *t, uintptr_t entry, uintptr_t highest, const char /* this sets up an entry point for the thread that's something like * void _start(const char **argv, const char **envp) */ + if(platformSignalSetup(t)) return -1; + ThreadContext *ctx = (ThreadContext *)t->context; ctx->regs.rip = entry; ctx->regs.rdi = (uint64_t)argv; From 2eae8dec7d61c3fec75622dee1bfd71d35a81a56 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 26 Nov 2024 14:58:42 -0500 Subject: [PATCH 52/67] x86_64: allocate signal trampoline in thread user space --- src/platform/x86_64/ipc/signal.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/platform/x86_64/ipc/signal.c diff --git a/src/platform/x86_64/ipc/signal.c b/src/platform/x86_64/ipc/signal.c new file mode 100644 index 0000000..283fa97 --- /dev/null +++ b/src/platform/x86_64/ipc/signal.c @@ -0,0 +1,30 @@ +/* + * lux - a lightweight unix-like operating system + * Omar Elghoul, 2024 + * + * Platform-Specific Code for x86_64 + */ + +#include +#include +#include +#include +#include +#include + +extern size_t sigstubSize; +extern uint8_t sigstub[]; + +/* platformSignalSetup(): sets up the signal trampoline code in a user process + * params: t - thread structure + * returns: zero on success + */ + +int platformSignalSetup(Thread *t) { + void *trampoline = uxmalloc(sigstubSize); + if(!trampoline) return -1; + + memcpy(trampoline, sigstub, sigstubSize); + t->signalTrampoline = (uintptr_t) trampoline; + return 0; +} \ No newline at end of file From bc4bc299f32b0a186364a208dcb9edddbd70a300 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 26 Nov 2024 16:44:02 -0500 Subject: [PATCH 53/67] sched: track sender thread in signal queue --- src/include/kernel/sched.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/kernel/sched.h b/src/include/kernel/sched.h index 69ba277..6a22bd0 100644 --- a/src/include/kernel/sched.h +++ b/src/include/kernel/sched.h @@ -43,7 +43,7 @@ typedef struct SignalQueue { struct SignalQueue *next; int signum; - uintptr_t handler; + struct Thread *sender; } SignalQueue; typedef struct Thread { From 1ba84b100331694cab47a65f674da64daf944818 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 26 Nov 2024 16:45:37 -0500 Subject: [PATCH 54/67] ipc: maintain sender thread in kill() --- src/ipc/signal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ipc/signal.c b/src/ipc/signal.c index 7c5c146..b81c534 100644 --- a/src/ipc/signal.c +++ b/src/ipc/signal.c @@ -224,6 +224,7 @@ int kill(Thread *t, pid_t pid, int sig) { if(!s) return -ENOMEM; s->signum = sig; + s->sender = t; s->next = NULL; acquireLockBlocking(&dest->lock); @@ -262,6 +263,7 @@ void signalHandle(Thread *t) { struct sigaction *handlers = (struct sigaction *) t->signals; uintptr_t handler = (uintptr_t) handlers[signum].sa_handler; int def = 0; + Thread *sender = s->sender; free(s); @@ -284,8 +286,6 @@ void signalHandle(Thread *t) { terminateThread(t, -1, true); break; default: - // TODO: execute the custom signal handler here - KERROR("TODO: execute custom signal handler: handler = %X, def = %d\n", handler, def); for(;;); } } From 90ccb5aa7541522c0fd5408b2b49c376b19196c8 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 26 Nov 2024 16:56:23 -0500 Subject: [PATCH 55/67] ipc: dispatch arch-specific signal mechanism --- src/ipc/signal.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ipc/signal.c b/src/ipc/signal.c index b81c534..95147c0 100644 --- a/src/ipc/signal.c +++ b/src/ipc/signal.c @@ -263,7 +263,6 @@ void signalHandle(Thread *t) { struct sigaction *handlers = (struct sigaction *) t->signals; uintptr_t handler = (uintptr_t) handlers[signum].sa_handler; int def = 0; - Thread *sender = s->sender; free(s); @@ -286,6 +285,8 @@ void signalHandle(Thread *t) { terminateThread(t, -1, true); break; default: + t->handlingSignal = true; + platformSendSignal(s->sender, t, s->signum); for(;;); } } From b936a31581bd6d315da5fa6d12aeab7876d9b2fd Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 26 Nov 2024 17:37:03 -0500 Subject: [PATCH 56/67] platform: redeclared prototype for arch-specific signal mechanism --- src/include/platform/platform.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/platform/platform.h b/src/include/platform/platform.h index b36c471..a0709b4 100644 --- a/src/include/platform/platform.h +++ b/src/include/platform/platform.h @@ -62,4 +62,4 @@ int platformConfigureIRQ(Thread *, int, IRQHandler *); // configure an IRQ pin IRQCommand *platformGetIRQCommand(); // per-CPU IRQ command structure void platformIdle(); // to be called when the CPU is idle void platformCleanThread(void *, uintptr_t); // garbage collector after thread is killed or replaced by exec() -int platformSendSignal(Thread *, Thread *, int); +int platformSendSignal(Thread *, Thread *, int, uintptr_t); From 76f0d5e0967ba4339ecd87d3ea2cae6a063fe6d1 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 26 Nov 2024 17:37:19 -0500 Subject: [PATCH 57/67] ipc: fix null pointer access in signal handling --- src/ipc/signal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ipc/signal.c b/src/ipc/signal.c index 95147c0..b74ef1c 100644 --- a/src/ipc/signal.c +++ b/src/ipc/signal.c @@ -262,6 +262,7 @@ void signalHandle(Thread *t) { int signum = s->signum - 1; // change to zero-based struct sigaction *handlers = (struct sigaction *) t->signals; uintptr_t handler = (uintptr_t) handlers[signum].sa_handler; + Thread *sender = s->sender; int def = 0; free(s); @@ -286,8 +287,7 @@ void signalHandle(Thread *t) { break; default: t->handlingSignal = true; - platformSendSignal(s->sender, t, s->signum); - for(;;); + platformSendSignal(sender, t, signum + 1, handler); } } From b95b8d07e05602cca3b6bb0a910cd4abe0c18dc2 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 26 Nov 2024 17:37:35 -0500 Subject: [PATCH 58/67] x86_64: dispatch signals to their handlers --- src/platform/x86_64/ipc/signal.c | 36 ++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/platform/x86_64/ipc/signal.c b/src/platform/x86_64/ipc/signal.c index 283fa97..f191fa1 100644 --- a/src/platform/x86_64/ipc/signal.c +++ b/src/platform/x86_64/ipc/signal.c @@ -26,5 +26,41 @@ int platformSignalSetup(Thread *t) { memcpy(trampoline, sigstub, sigstubSize); t->signalTrampoline = (uintptr_t) trampoline; + return 0; +} + +/* platformSendSignal(): dispatches a signal to a thread + * params: sender - thread sending the signal + * params: dest - thread receiving the signal + * params: signum - signal number + * params: handler - function to dispatch + * returns: zero on success + */ + +int platformSendSignal(Thread *sender, Thread *dest, int signum, uintptr_t handler) { + memcpy(dest->signalContext, dest->context, PLATFORM_CONTEXT_SIZE); + + /* TODO: enter the function as func(int sig, siginfo_t *info, void *ctx) + * instead of just func(int sig) + * https://pubs.opengroup.org/onlinepubs/007904875/functions/sigaction.html + */ + + ThreadContext *ctx = (ThreadContext *) dest->context; + platformUseContext(ctx); + + ctx->regs.rip = handler; + ctx->regs.rdi = signum; + ctx->regs.rflags = 0x202; + ctx->regs.rsp -= 128; // downwards of the red zone + + // ensure stack is 16-byte aligned on entry + while(ctx->regs.rsp & 0x0F) + ctx->regs.rsp--; + ctx->regs.rbp = ctx->regs.rsp; + + // inject signal trampoline + uint64_t *stack = (uint64_t *) ctx->regs.rsp; + *stack = dest->signalTrampoline; + return 0; } \ No newline at end of file From 7e209defa483b07d57a4d4a390b53f5e9a9b9dd0 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 26 Nov 2024 17:44:33 -0500 Subject: [PATCH 59/67] platform: declaration for arch-specific sigreturn() --- src/include/platform/platform.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/include/platform/platform.h b/src/include/platform/platform.h index a0709b4..a4aac77 100644 --- a/src/include/platform/platform.h +++ b/src/include/platform/platform.h @@ -63,3 +63,4 @@ IRQCommand *platformGetIRQCommand(); // per-CPU IRQ command structure void platformIdle(); // to be called when the CPU is idle void platformCleanThread(void *, uintptr_t); // garbage collector after thread is killed or replaced by exec() int platformSendSignal(Thread *, Thread *, int, uintptr_t); +void platformSigreturn(Thread *); \ No newline at end of file From 521d935d3efb26c99165af7a2776a40528ee457a Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 26 Nov 2024 17:44:48 -0500 Subject: [PATCH 60/67] ipc: relay sigreturn() to arch-specific implementation --- src/include/kernel/signal.h | 1 + src/ipc/signal.c | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/src/include/kernel/signal.h b/src/include/kernel/signal.h index 44a39a6..87ff905 100644 --- a/src/include/kernel/signal.h +++ b/src/include/kernel/signal.h @@ -107,3 +107,4 @@ void signalHandle(Thread *); int kill(Thread *, pid_t, int); int sigaction(Thread *, int, const struct sigaction *, struct sigaction *); +void sigreturn(Thread *); \ No newline at end of file diff --git a/src/ipc/signal.c b/src/ipc/signal.c index b74ef1c..e376c7f 100644 --- a/src/ipc/signal.c +++ b/src/ipc/signal.c @@ -325,4 +325,15 @@ int sigaction(Thread *t, int sig, const struct sigaction *act, struct sigaction memcpy(&handlers[sig-1], act, sizeof(struct sigaction)); releaseLock(&t->lock); return 0; +} + +/* sigreturn(): returns from a signal handler and restores previous state + * params: t - calling thread + * returns: nothing + */ + +void sigreturn(Thread *t) { + if(!t->handlingSignal) return; + platformSigreturn(t); + t->handlingSignal = false; } \ No newline at end of file From 65bdc0bf18a988620615c39bc16b571d849c3cca Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 26 Nov 2024 19:00:17 -0500 Subject: [PATCH 61/67] x86_64: architecture-dependent sigreturn() implementation --- src/platform/x86_64/ipc/signal.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/platform/x86_64/ipc/signal.c b/src/platform/x86_64/ipc/signal.c index f191fa1..26621fa 100644 --- a/src/platform/x86_64/ipc/signal.c +++ b/src/platform/x86_64/ipc/signal.c @@ -63,4 +63,13 @@ int platformSendSignal(Thread *sender, Thread *dest, int signum, uintptr_t handl *stack = dest->signalTrampoline; return 0; +} + +/* platformSigreturn(): restores context before a signal handler was invoked + * params: t - thread to restore + * returns: nothing + */ + +void platformSigreturn(Thread *t) { + memcpy(t->context, t->signalContext, PLATFORM_CONTEXT_SIZE); } \ No newline at end of file From 589e6cbdb2d8b96647dfced24aac1e65f39cff06 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 26 Nov 2024 19:02:31 -0500 Subject: [PATCH 62/67] syscalls: dispatch sigreturn() --- src/syscalls/dispatch.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/syscalls/dispatch.c b/src/syscalls/dispatch.c index da4116d..e807ccc 100644 --- a/src/syscalls/dispatch.c +++ b/src/syscalls/dispatch.c @@ -492,6 +492,11 @@ void syscallDispatchSigAction(SyscallRequest *req) { } } +void syscallDispatchSigreturn(SyscallRequest *req) { + sigreturn(req->thread); + req->unblock = true; +} + /* Group 4: Memory Management */ void syscallDispatchSBrk(SyscallRequest *req) { @@ -599,7 +604,7 @@ void (*syscallDispatchTable[])(SyscallRequest *) = { syscallDispatchSend, // 46 - send() syscallDispatchKill, // 47 - kill() syscallDispatchSigAction, // 48 - sigaction() - NULL, // 49 - sigreturn() + syscallDispatchSigreturn, // 49 - sigreturn() /* group 4: memory management */ syscallDispatchSBrk, // 50 - sbrk() From eb4f6d23bac58ae6332d4ce4397e3fc1f3d2e332 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 26 Nov 2024 19:03:57 -0500 Subject: [PATCH 63/67] sched: add siginfo and signal user context to thread struct --- src/include/kernel/sched.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/include/kernel/sched.h b/src/include/kernel/sched.h index 6a22bd0..b6331d6 100644 --- a/src/include/kernel/sched.h +++ b/src/include/kernel/sched.h @@ -59,6 +59,8 @@ typedef struct Thread { void *signals; SignalQueue *signalQueue; uintptr_t signalTrampoline; + uintptr_t siginfo; + uintptr_t signalUserContext; SyscallRequest syscall; // for when the thread is blocked int exitStatus; // for zombie threads From 6347458b01d8812df349ad1622a32a0c7493e480 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 26 Nov 2024 19:07:11 -0500 Subject: [PATCH 64/67] x86_64: allocate memory for siginfo and context for signals --- src/platform/x86_64/ipc/signal.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/platform/x86_64/ipc/signal.c b/src/platform/x86_64/ipc/signal.c index 26621fa..05d6351 100644 --- a/src/platform/x86_64/ipc/signal.c +++ b/src/platform/x86_64/ipc/signal.c @@ -24,8 +24,23 @@ int platformSignalSetup(Thread *t) { void *trampoline = uxmalloc(sigstubSize); if(!trampoline) return -1; + void *siginfo = umalloc(sizeof(siginfo_t)); + if(!siginfo) { + free(trampoline); + return -1; + } + + void *sigctx = umalloc(PLATFORM_CONTEXT_SIZE); + if(!sigctx) { + free(trampoline); + free(siginfo); + return -1; + } + memcpy(trampoline, sigstub, sigstubSize); t->signalTrampoline = (uintptr_t) trampoline; + t->siginfo = (uintptr_t) siginfo; + t->signalUserContext = (uintptr_t) sigctx; return 0; } From cd5faa937c324a058a1fcc88de297cc8c3bf01f9 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 26 Nov 2024 19:12:17 -0500 Subject: [PATCH 65/67] x86_64: pass signal info in the format dictated by sigaction() --- src/platform/x86_64/ipc/signal.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/platform/x86_64/ipc/signal.c b/src/platform/x86_64/ipc/signal.c index 05d6351..44e8ddd 100644 --- a/src/platform/x86_64/ipc/signal.c +++ b/src/platform/x86_64/ipc/signal.c @@ -55,16 +55,33 @@ int platformSignalSetup(Thread *t) { int platformSendSignal(Thread *sender, Thread *dest, int signum, uintptr_t handler) { memcpy(dest->signalContext, dest->context, PLATFORM_CONTEXT_SIZE); - /* TODO: enter the function as func(int sig, siginfo_t *info, void *ctx) - * instead of just func(int sig) - * https://pubs.opengroup.org/onlinepubs/007904875/functions/sigaction.html - */ - ThreadContext *ctx = (ThreadContext *) dest->context; platformUseContext(ctx); + Process *p = NULL; + if(sender) p = getProcess(sender->pid); + + siginfo_t *siginfo = (siginfo_t *) dest->siginfo; + siginfo->si_signo = signum; + siginfo->si_pid = sender->tid; + + if(p) siginfo->si_uid = p->user; + else siginfo->si_uid = 0; + + siginfo->si_code = 0; // TODO + + ThreadContext *uctx = (ThreadContext *) dest->signalUserContext; + memcpy(uctx, dest->context, PLATFORM_CONTEXT_SIZE); + + // signal entry point + // func(int sig, siginfo_t *info, void *ctx) + // https://pubs.opengroup.org/onlinepubs/007904875/functions/sigaction.html + ctx->regs.rip = handler; - ctx->regs.rdi = signum; + ctx->regs.rdi = signum; // int sig + ctx->regs.rsi = (uint64_t) siginfo; // siginfo_t *info + ctx->regs.rdx = (uint64_t) uctx; // void *ctx + ctx->regs.rflags = 0x202; ctx->regs.rsp -= 128; // downwards of the red zone From 070ffb787227614fb0e3aec4ffd57a745eb24aac Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 26 Nov 2024 19:21:34 -0500 Subject: [PATCH 66/67] x86_64: null pointer check in signal dispatch --- src/platform/x86_64/ipc/signal.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/platform/x86_64/ipc/signal.c b/src/platform/x86_64/ipc/signal.c index 44e8ddd..1b6e697 100644 --- a/src/platform/x86_64/ipc/signal.c +++ b/src/platform/x86_64/ipc/signal.c @@ -63,7 +63,8 @@ int platformSendSignal(Thread *sender, Thread *dest, int signum, uintptr_t handl siginfo_t *siginfo = (siginfo_t *) dest->siginfo; siginfo->si_signo = signum; - siginfo->si_pid = sender->tid; + if(sender) siginfo->si_pid = sender->tid; + else siginfo->si_pid = 0; // we will use pid 0 for the kernel if(p) siginfo->si_uid = p->user; else siginfo->si_uid = 0; From aaa6fd68de48629e9d495bbac6f0e7c50181e3d7 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Tue, 26 Nov 2024 19:23:13 -0500 Subject: [PATCH 67/67] syscalls: remove redundant conditional in sigaction() dispatch --- src/syscalls/dispatch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/syscalls/dispatch.c b/src/syscalls/dispatch.c index e807ccc..cfe1bf8 100644 --- a/src/syscalls/dispatch.c +++ b/src/syscalls/dispatch.c @@ -485,8 +485,8 @@ void syscallDispatchKill(SyscallRequest *req) { } void syscallDispatchSigAction(SyscallRequest *req) { - if((!req->params[1] || (req->params[1] && syscallVerifyPointer(req, req->params[1], sizeof(struct sigaction)))) && - (!req->params[2] || (req->params[2] && syscallVerifyPointer(req, req->params[2], sizeof(struct sigaction))))) { + if((!req->params[1] || syscallVerifyPointer(req, req->params[1], sizeof(struct sigaction))) && + (!req->params[2] || syscallVerifyPointer(req, req->params[2], sizeof(struct sigaction)))) { req->ret = sigaction(req->thread, req->params[0], (const struct sigaction *) req->params[1], (struct sigaction *) req->params[2]); req->unblock = true; }