aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/include/sys/proc.h5
-rw-r--r--sys/include/sys/signal.h84
-rw-r--r--sys/kern/kern_exec.c4
-rw-r--r--sys/kern/kern_fork.c2
-rw-r--r--sys/kern/kern_sched.c1
-rw-r--r--sys/kern/kern_sig.c257
-rw-r--r--sys/kern/kern_stub.c33
7 files changed, 385 insertions, 1 deletions
diff --git a/sys/include/sys/proc.h b/sys/include/sys/proc.h
index b9db603..b10ee41 100644
--- a/sys/include/sys/proc.h
+++ b/sys/include/sys/proc.h
@@ -38,6 +38,7 @@
#include <sys/syscall.h>
#include <sys/exec.h>
#include <sys/filedesc.h>
+#include <sys/signal.h>
#if defined(_KERNEL)
#include <machine/frame.h>
#include <machine/pcb.h>
@@ -48,10 +49,12 @@
#define PROC_STACK_PAGES 8
#define PROC_STACK_SIZE (PROC_STACK_PAGES * DEFAULT_PAGESIZE)
#define PROC_MAX_FILEDES 256
+#define PROC_SIGMAX 64
struct proc {
pid_t pid;
struct exec_prog exec;
+ struct ksiginfo *ksig_list[PROC_SIGMAX];
struct filedesc *fds[PROC_MAX_FILEDES];
struct trapframe tf;
struct pcb pcb;
@@ -59,6 +62,8 @@ struct proc {
bool rested;
uint32_t flags;
uintptr_t stack_base;
+ struct spinlock ksigq_lock;
+ TAILQ_HEAD(, ksiginfo) ksigq;
TAILQ_ENTRY(proc) link;
};
diff --git a/sys/include/sys/signal.h b/sys/include/sys/signal.h
new file mode 100644
index 0000000..f35ff82
--- /dev/null
+++ b/sys/include/sys/signal.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2023-2024 Ian Marco Moffett and the Osmora Team.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Hyra nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SYS_SIGNAL_H_
+#define _SYS_SIGNAL_H_
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/proc.h>
+
+#define SIGFPE 8 /* Floating point exception */
+#define SIGKILL 9 /* Kill */
+#define SIGSEGV 11 /* Segmentation violation */
+
+typedef uint32_t sigset_t;
+
+typedef struct {
+ int si_signo;
+ int si_code;
+} siginfo_t;
+
+struct sigaction {
+ void(*sa_handler)(int signo);
+ sigset_t sa_mask;
+ int sa_flags;
+ void(*sa_sigaction)(int signo, siginfo_t *si, void *p);
+};
+
+#if defined(_KERNEL)
+struct proc;
+
+struct ksiginfo {
+ int signo;
+ int sigcode;
+ struct sigaction *si;
+ TAILQ_ENTRY(ksiginfo) link;
+};
+
+/* Signal management */
+int newsig(struct proc *td, int signo, struct ksiginfo **ksig);
+int delsig(struct proc *td, int signo);
+int sendsig(struct proc *td, const sigset_t *set);
+void dispatch_signals(struct proc *td);
+int signals_init(struct proc *td);
+
+/* Sigset functions */
+int sigemptyset(sigset_t *set);
+int sigfillset(sigset_t *set);
+int sigaddset(sigset_t *set, int signo);
+int sigdelset(sigset_t *set, int signo);
+int sigismember(const sigset_t *set, int signo);
+
+/* Default handlers */
+void sigfpe_default(int signo);
+void sigkill_default(int signo);
+void sigsegv_default(int signo);
+#endif /* _KERNEL */
+#endif /* !_SYS_SIGNAL_H_ */
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
index ceb08f6..863f4ae 100644
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -32,6 +32,7 @@
#include <sys/errno.h>
#include <sys/proc.h>
#include <sys/sched.h>
+#include <sys/signal.h>
#include <vm/vm.h>
#include <vm/map.h>
#include <vm/physmem.h>
@@ -97,9 +98,10 @@ execve(struct proc *td, const struct execve_args *args)
prog.envp = args->envp;
stack_top = td->stack_base + (PROC_STACK_SIZE - 1);
- /* Setup registers and stack */
+ /* Setup registers, signals and stack */
md_td_stackinit(td, (void *)(stack_top + VM_HIGHER_HALF), &prog);
setregs(td, &prog, stack_top);
+ signals_init(td);
/* Done, reset flags and start the user thread */
td->flags &= ~PROC_EXEC;
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index 037026b..7bcff4b 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -31,6 +31,7 @@
#include <sys/proc.h>
#include <sys/errno.h>
#include <sys/sched.h>
+#include <sys/signal.h>
#include <vm/dynalloc.h>
#include <string.h>
@@ -64,6 +65,7 @@ fork1(struct proc *cur, int flags, void(*ip)(void), struct proc **newprocp)
*newprocp = newproc;
newproc->pid = ++nthreads;
+ signals_init(newproc);
sched_enqueue_td(newproc);
done:
if (status != 0)
diff --git a/sys/kern/kern_sched.c b/sys/kern/kern_sched.c
index 6d85330..5f2b019 100644
--- a/sys/kern/kern_sched.c
+++ b/sys/kern/kern_sched.c
@@ -187,6 +187,7 @@ sched_switch(struct trapframe *tf)
td = ci->curtd;
if (td != NULL) {
+ dispatch_signals(td);
td_pri_update(td);
}
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
new file mode 100644
index 0000000..ed29397
--- /dev/null
+++ b/sys/kern/kern_sig.c
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2023-2024 Ian Marco Moffett and the Osmora Team.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Hyra nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/signal.h>
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/syslog.h>
+#include <sys/param.h>
+#include <vm/dynalloc.h>
+#include <string.h>
+
+#define sigmask(SIGNO) BIT(SIGNO)
+
+static struct sigaction sa_tab[] = {
+ [SIGFPE] = {
+ .sa_handler = sigfpe_default,
+ .sa_mask = 0,
+ .sa_flags = 0,
+ .sa_sigaction = NULL
+ },
+
+ [SIGKILL] = {
+ .sa_handler = sigkill_default,
+ .sa_mask = 0,
+ .sa_flags = 0,
+ .sa_sigaction = NULL
+ },
+
+ [SIGSEGV] = {
+ .sa_handler = sigsegv_default,
+ .sa_mask = 0,
+ .sa_flags = 0,
+ .sa_sigaction = NULL
+ },
+};
+
+/*
+ * Register a new signal descriptor, set it in the process
+ * structure and return it in `ksig`.
+ *
+ * @td: Process to register signal to.
+ * @signo: Signal number to register.
+ * @ksig: Will contain a pointer to new signal descriptor.
+ */
+int
+newsig(struct proc *td, int signo, struct ksiginfo **ksig)
+{
+ struct ksiginfo *ksig_tmp;
+
+ /* Ensure we have valid args */
+ if (td == NULL || signo >= PROC_SIGMAX)
+ return -EINVAL;
+
+ /*
+ * Make sure we have a valid signal list. If we already
+ * have a signal registered in a slot, free up memory used
+ * for that signal descriptor so we can override it with the
+ * new one.
+ */
+ if (td->ksig_list == NULL)
+ return -EIO;
+ if ((ksig_tmp = td->ksig_list[signo]) != NULL)
+ dynfree(ksig_tmp);
+
+ /* Allocate our new signal */
+ ksig_tmp = dynalloc(sizeof(*ksig_tmp));
+ if (ksig_tmp == NULL)
+ return -ENOMEM;
+
+ memset(ksig_tmp, 0, sizeof(*ksig_tmp));
+ ksig_tmp->signo = signo;
+ td->ksig_list[signo] = ksig_tmp;
+ *ksig = ksig_tmp;
+ return 0;
+}
+
+/*
+ * Remove a signal from the signal table.
+ *
+ * @td: Process to remove signal from.
+ * @signo: Signal to remove.
+ */
+int
+delsig(struct proc *td, int signo)
+{
+ struct ksiginfo *ksig_tmp;
+
+ /* Ensure we have valid args */
+ if (td == NULL || signo >= PROC_SIGMAX)
+ return -EINVAL;
+
+ /* Don't do anything if it doesn't exist */
+ if ((ksig_tmp = td->ksig_list[signo]) == NULL)
+ return 0;
+
+ dynfree(ksig_tmp);
+ td->ksig_list[signo] = NULL;
+ return 0;
+}
+
+int
+sendsig(struct proc *td, const sigset_t *set)
+{
+ struct ksiginfo *ksig_tmp;
+
+ /* Ensure arguments are correct */
+ if (td == NULL || set == NULL)
+ return -EINVAL;
+
+ /* Enqueue required ksiginfo structures */
+ for (int i = 0; i < PROC_SIGMAX; ++i) {
+ if ((ksig_tmp = td->ksig_list[i]) == NULL) {
+ continue;
+ }
+
+ /* Enqueue if it is a member of the sigset */
+ if (sigismember(set, i)) {
+ spinlock_acquire(&td->ksigq_lock);
+ TAILQ_INSERT_TAIL(&td->ksigq, ksig_tmp, link);
+ spinlock_release(&td->ksigq_lock);
+ }
+ }
+
+ return 0;
+}
+
+int
+signals_init(struct proc *td)
+{
+ struct sigaction *sa;
+ struct ksiginfo *ksig;
+ int error, i;
+
+ TAILQ_INIT(&td->ksigq);
+
+ /* Populate process signal table with defaults */
+ for (i = 0; i < NELEM(sa_tab); ++i) {
+ sa = &sa_tab[i];
+
+ /* Drop actions that aren't set up */
+ if (sa->sa_handler == NULL && sa->sa_sigaction == NULL) {
+ continue;
+ }
+
+ /* Attempt to register the new signal */
+ if ((error = newsig(td, i, &ksig)) != 0) {
+ goto fail;
+ }
+
+ ksig->si = sa;
+ }
+
+ return 0;
+
+fail:
+ /*
+ * We do not want the process signal table to be in
+ * an inconsistent state so we clean up on failure.
+ */
+ for (int j = 0; j < i; ++j) {
+ if ((error = delsig(td, j)) != 0) {
+ kprintf("delsig() failed on signal %d (returned %d)\n",
+ j, error);
+ }
+ }
+
+ return error;
+}
+
+void
+dispatch_signals(struct proc *td)
+{
+ struct ksiginfo *ksig_tmp;
+ struct sigaction *action;
+
+ spinlock_acquire(&td->ksigq_lock);
+ while (!TAILQ_EMPTY(&td->ksigq)) {
+ /* Dequeue signal descriptor */
+ ksig_tmp = TAILQ_FIRST(&td->ksigq);
+ TAILQ_REMOVE(&td->ksigq, ksig_tmp, link);
+
+ /* Invoke handler */
+ action = ksig_tmp->si;
+ action->sa_handler(ksig_tmp->signo);
+ }
+
+ spinlock_release(&td->ksigq_lock);
+}
+
+int
+sigemptyset(sigset_t *set)
+{
+ *set = 0;
+ return 0;
+}
+
+int
+sigfillset(sigset_t *set)
+{
+ *set = ~(sigset_t)0;
+ return 0;
+}
+
+int
+sigaddset(sigset_t *set, int signo)
+{
+ if (signo <= 0 || signo >= PROC_SIGMAX)
+ return -EINVAL;
+
+ *set |= sigmask(signo);
+ return 0;
+}
+
+int
+sigdelset(sigset_t *set, int signo)
+{
+ if (signo <= 0 || signo >= PROC_SIGMAX)
+ return -EINVAL;
+
+ *set &= ~sigmask(signo);
+ return 0;
+}
+
+int
+sigismember(const sigset_t *set, int signo)
+{
+ if (signo <= 0 || signo >= PROC_SIGMAX)
+ return -EINVAL;
+
+ return (*set & sigmask(signo)) != 0;
+}
diff --git a/sys/kern/kern_stub.c b/sys/kern/kern_stub.c
index 65688e2..5a53cc1 100644
--- a/sys/kern/kern_stub.c
+++ b/sys/kern/kern_stub.c
@@ -30,6 +30,39 @@
#include <sys/device.h>
#include <sys/types.h>
#include <sys/errno.h>
+#include <sys/syslog.h>
+#include <sys/proc.h>
+#include <sys/signal.h>
+
+void
+sigfpe_default(int signo)
+{
+ static struct proc *td;
+
+ td = this_td();
+ kprintf("Floating point exception (pid=%d)\n", td->pid);
+ exit1(td);
+}
+
+void
+sigkill_default(int signo)
+{
+ static struct proc *td;
+
+ td = this_td();
+ kprintf("Terminated (pid=%d)\n", td->pid);
+ exit1(td);
+}
+
+void
+sigsegv_default(int signo)
+{
+ static struct proc *td;
+
+ td = this_td();
+ kprintf("Segmentation fault (pid=%d)\n", td->pid);
+ exit1(td);
+}
int
dev_noread(void)