Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion kernel/include/kernel/process.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <kernel/fs/vfs.h>
#include <kernel/idt.h>
#include <kernel/signal.h>
#include <stdbool.h>
#include <stdint.h>
#include <utils/hashmap32.h>
Expand All @@ -13,7 +14,7 @@
typedef struct process process;
typedef struct process_queue process_queue;

typedef enum { TASK_RUNNING, TASK_READY, TASK_BLOCKED, TASK_DEAD } task_state_t;
typedef enum { TASK_RUNNING, TASK_READY, TASK_BLOCKED, TASK_STOPPED, TASK_DEAD } task_state_t;

typedef union {
int32_t raw;
Expand Down Expand Up @@ -43,6 +44,10 @@ struct process {
process* p_parent;
exit_status p_exitstatus;
int64_t p_waitforchild;
process_queue* p_waiting_on_queue;
uint64_t p_pending;
uint64_t p_sigmask;
sigaction p_sigactions[NSIG];
};

struct process_queue {
Expand All @@ -59,6 +64,10 @@ int enqueue_process (process_queue* queue, process* new_process);

void process_block (process_queue* wait_queue);
void process_unblock (process* p);
void process_signal_wakeup (process* p);

int send_signal (process* target, int signum);
void deliver_pending_signals (registers_t* registers);

void schedule (registers_t* registers);

Expand Down
65 changes: 65 additions & 0 deletions kernel/include/kernel/signal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#pragma once

#include <stdint.h>

#define SIGHUP 1 /* hangup */
#define SIGINT 2 /* interrupt */
#define SIGQUIT 3 /* quit */
#define SIGILL 4 /* illegal instruction (not reset when caught) */
#define SIGTRAP 5 /* trace trap (not reset when caught) */
#define SIGIOT 6 /* IOT instruction */
#define SIGABRT 6 /* used by abort, replace SIGIOT in the future */
#define SIGEMT 7 /* EMT instruction */
#define SIGFPE 8 /* floating point exception */
#define SIGKILL 9 /* kill (cannot be caught or ignored) */
#define SIGBUS 10 /* bus error */
#define SIGSEGV 11 /* segmentation violation */
#define SIGSYS 12 /* bad argument to system call */
#define SIGPIPE 13 /* write on a pipe with no one to read it */
#define SIGALRM 14 /* alarm clock */
#define SIGTERM 15 /* software termination signal from kill */
#define SIGURG 16 /* urgent condition on IO channel */
#define SIGSTOP 17 /* sendable stop signal not from tty */
#define SIGTSTP 18 /* stop signal from tty */
#define SIGCONT 19 /* continue a stopped process */
#define SIGCHLD 20 /* to parent on child stop or exit */
#define SIGCLD 20 /* System V name for SIGCHLD */
#define SIGTTIN 21 /* to readers pgrp upon background tty read */
#define SIGTTOU 22 /* like TTIN for output if (tp->t_local&LTOSTOP) */
#define SIGIO 23 /* input/output possible signal */
#define SIGXCPU 24 /* exceeded CPU time limit */
#define SIGXFSZ 25 /* exceeded file size limit */
#define SIGVTALRM 26 /* virtual time alarm */
#define SIGPROF 27 /* profiling time alarm */
#define SIGWINCH 28 /* window changed */
#define SIGLOST 29 /* resource lost (eg, record-lock lost) */
#define SIGUSR1 30 /* user defined signal 1 */
#define SIGUSR2 31 /* user defined signal 2 */
#define NSIG 32 /* signal 0 implied */

#define SIG_DFL ((_sig_func_ptr)0) /* Default action */
#define SIG_IGN ((_sig_func_ptr)1) /* Ignore action */
#define SIG_ERR ((_sig_func_ptr) - 1) /* Error return */

extern uint8_t signal_trampoline_start[];
extern uint8_t signal_trampoline_end[];

typedef unsigned long sigset_t;
typedef void (*_sig_func_ptr) (int);

typedef struct {
_sig_func_ptr sa_handler;
sigset_t sa_mask;
int sa_flags;
} sigaction;

typedef struct {
uint64_t rax, rbx, rcx, rdx, rbp, rsi, rdi;
uint64_t r8, r9, r10, r11, r12, r13, r14, r15;
uint64_t rip;
uint64_t rflags;
uint64_t rsp;
uint64_t cs, ss;
uint8_t trampoline[8];
uint64_t saved_sigmask;
} signal_frame_t;
2 changes: 2 additions & 0 deletions kernel/include/kernel/syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

// The following will have numbers changed

#define SYSCALL_SYS_RT_SIGACTION 239
#define SYSCALL_SYS_RT_SIGRETURN 240
#define SYSCALL_SYS_IOCTL 241
#define SYSCALL_SYS_GETCWD 242
#define SYSCALL_SYS_CHDIR 243
Expand Down
5 changes: 4 additions & 1 deletion kernel/src/kernel/fs/chardev/chardev.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,11 @@ static int stdin_read (inode* node, file* f, void* buffer, size_t size) {
bool stdio_buf = con_update_cache_set ();
for (size_t i = 0; i < size; i++) {
unsigned char c = 255;
while ((c = pop_next_char ()) == 255)
while ((c = pop_next_char ()) == 255) {
process_block (&tty1_ptr->i_info.chardev_info->rsrc_wait_queue);
process* current = get_current_process ();
if (current->p_pending & ~current->p_sigmask) return -EINTR;
}
if (c == '\x7F') {
if (i > 0) {
i -= 2;
Expand Down
7 changes: 4 additions & 3 deletions kernel/src/kernel/handlers.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
#include <kernel/handlers.h>
#include <kernel/idt.h>
#include <kernel/process.h>
#include <kernel/signal.h>

void handle_gpf (registers_t* registers) {
kserial_printf ("Triggered GPF on PID #%lld\n", get_current_process ()->p_id);
kserial_printf ("Triggered GPF on PID #%lld. Sending SIGILL.\n", get_current_process ()->p_id);
log_registers_to_serial (registers);
for (;;)
;
send_signal (get_current_process (), SIGILL);
deliver_pending_signals (registers);
}

void init_handlers (void) { idt_register_handler (0xD, handle_gpf); }
8 changes: 5 additions & 3 deletions kernel/src/kernel/memory/memmgt.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <kernel/memmgt.h>
#include <kernel/memory/pmm.h>
#include <kernel/process.h>
#include <kernel/signal.h>
#include <kernel/syscall.h>

#define ALIGNUP(x, o) ((x + o - 1) & ~(o - 1))
Expand Down Expand Up @@ -40,11 +41,12 @@ static void page_fault_handler (registers_t* registers) {
uint64_t cr2;
__asm__ volatile ("mov %%cr2, %0" : "=r"(cr2));

kserial_printf ("\nEncountered a page fault!\nFaulting address: 0x%llx\n", cr2);
kserial_printf ("\nEncountered a page fault!\nFaulting address: 0x%llx\nSending SIGSEGV.\n",
cr2);
log_registers_to_serial (registers);

for (;;)
;
send_signal (get_current_process (), SIGSEGV);
deliver_pending_signals (registers);
}

static uint64_t sys_brk (uint64_t addr, uint64_t arg2, uint64_t arg3) {
Expand Down
107 changes: 101 additions & 6 deletions kernel/src/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,12 @@ void schedule (registers_t* registers) {
enqueue_process (get_ready_queue (), current_process);
}

int errno = dequeue_process (get_ready_queue (), &upcoming_process);

if (upcoming_process == nullptr)
for (;;)
;
if (errno != 0) return;
do {
dequeue_process (get_ready_queue (), &upcoming_process);
if (upcoming_process == nullptr)
for (;;)
;
} while (upcoming_process->p_state == TASK_DEAD || upcoming_process->p_state == TASK_STOPPED);

current_process = upcoming_process;
current_process->p_state = TASK_RUNNING;
Expand Down Expand Up @@ -229,6 +229,11 @@ int process_fork (process* source_process, process** dest_ptr) {
new_process->p_waiting = kmalloc (sizeof (process_queue));
kmemset (new_process->p_waiting, 0, sizeof (process_queue));

new_process->p_sigmask = source_process->p_sigmask;
kmemcpy (new_process->p_sigactions, source_process->p_sigactions,
sizeof (source_process->p_sigactions));
new_process->p_pending = 0;

errno = enqueue_process (get_ready_queue (), new_process);
if (errno != 0) {
free_vpages (new_kstack, STACK_SIZE / PAGE_SIZE);
Expand All @@ -243,11 +248,35 @@ int process_fork (process* source_process, process** dest_ptr) {

void process_block (process_queue* wait_queue) {
current_process->p_state = TASK_BLOCKED;
current_process->p_waiting_on_queue = wait_queue;
enqueue_process (wait_queue, current_process);
do_sched_yield ();
current_process->p_waiting_on_queue = nullptr;
}

void process_unblock (process* p) {
p->p_state = TASK_READY;
p->p_waiting_on_queue = nullptr;
enqueue_process (&ready_queue, p);
}

void process_signal_wakeup (process* p) {
if (p->p_waiting_on_queue) {
process_queue* q = p->p_waiting_on_queue;
if (q->head == p) {
q->head = p->next;
if (q->tail == p) q->tail = nullptr;
} else {
process* cur = q->head;
while (cur && cur->next != p)
cur = cur->next;
if (cur) {
cur->next = p->next;
if (q->tail == p) q->tail = cur;
}
}
p->p_waiting_on_queue = nullptr;
}
p->p_state = TASK_READY;
enqueue_process (&ready_queue, p);
}
Expand Down Expand Up @@ -305,6 +334,9 @@ static int do_waitpid (int64_t pid, exit_status* estatus, uint64_t options) {

do {
process_block (waitproc->p_waiting);
current = get_current_process ();
if (waitproc->p_state == TASK_DEAD) break;
if (current->p_pending & ~current->p_sigmask) return -EINTR;
} while (waitproc->p_state != TASK_DEAD);

pid0_exit:
Expand Down Expand Up @@ -334,6 +366,8 @@ static uint64_t sys_exit (uint64_t status, uint64_t arg2, uint64_t arg3) {
current->p_exitstatus.info = status;
current->p_exitstatus.reason = 0;

if (current->p_parent) send_signal (current->p_parent, SIGCHLD);

for (int i = 0; i < MAX_FDS; i++)
if (current->p_fds[i]) sys_close (i, 0, 0);

Expand Down Expand Up @@ -364,6 +398,64 @@ static uint64_t sys_sched_yield (uint64_t arg1, uint64_t arg2, uint64_t arg3) {
return do_sched_yield ();
}

static uint64_t sys_kill (uint64_t pid, uint64_t signum, uint64_t unused) {
(void)unused;
process* target = (process*)hashmap_get (pid_map, pid);
if (!target) return (uint64_t)-ESRCH;
return (uint64_t)send_signal (target, (int)signum);
}

static uint64_t sys_rt_sigaction (uint64_t signum, uint64_t new_action_ptr,
uint64_t old_action_ptr) {
if (signum < 1 || signum >= NSIG) return (uint64_t)-EINVAL;
if (signum == SIGKILL || signum == SIGSTOP) return (uint64_t)-EINVAL;

process* p = get_current_process ();
if (!p) return (uint64_t)-ESRCH;

if (old_action_ptr)
kmemcpy ((void*)old_action_ptr, &p->p_sigactions[signum], sizeof (sigaction));

if (new_action_ptr)
kmemcpy (&p->p_sigactions[signum], (void*)new_action_ptr, sizeof (sigaction));

return 0;
}

static uint64_t sys_rt_sigreturn (uint64_t arg1, uint64_t arg2, uint64_t arg3) {
(void)arg1, (void)arg2, (void)arg3;

registers_t* registers = get_latest_r_frame ();
uintptr_t frame_addr = registers->rsp;
signal_frame_t* frame = (signal_frame_t*)frame_addr;

process* p = get_current_process ();
p->p_sigmask = frame->saved_sigmask;

registers->rax = frame->rax;
registers->rbx = frame->rbx;
registers->rcx = frame->rcx;
registers->rdx = frame->rdx;
registers->rbp = frame->rbp;
registers->rsi = frame->rsi;
registers->rdi = frame->rdi;
registers->r8 = frame->r8;
registers->r9 = frame->r9;
registers->r10 = frame->r10;
registers->r11 = frame->r11;
registers->r12 = frame->r12;
registers->r13 = frame->r13;
registers->r14 = frame->r14;
registers->r15 = frame->r15;
registers->rip = frame->rip;
registers->rflags = frame->rflags;
registers->rsp = frame->rsp;
registers->cs = frame->cs;
registers->ss = frame->ss;

return registers->rax;
}

void init_process (void) {
ready_queue.head = ready_queue.tail = nullptr;
next_free_pid = 2ll;
Expand All @@ -375,4 +467,7 @@ void init_process (void) {
register_syscall (SYSCALL_SYS_GETPID, sys_getpid);
register_syscall (SYSCALL_SCHED_YIELD, sys_sched_yield);
register_syscall (SYSCALL_SYS_WAITPID, sys_waitpid);
register_syscall (SYSCALL_SYS_KILL, sys_kill);
register_syscall (SYSCALL_SYS_RT_SIGACTION, sys_rt_sigaction);
register_syscall (SYSCALL_SYS_RT_SIGRETURN, sys_rt_sigreturn);
}
Loading
Loading