SIGNALS
This commit is contained in:
parent
a09be369ea
commit
65fa12f482
@ -42,6 +42,7 @@ typedef struct image {
|
||||
uintptr_t heap_actual; /* Actual heap location */
|
||||
uintptr_t stack; /* Process kernel stack */
|
||||
uintptr_t user_stack; /* User stack */
|
||||
uintptr_t start;
|
||||
} image_t;
|
||||
|
||||
/* Resizable descriptor table */
|
||||
@ -56,7 +57,7 @@ typedef struct descriptor_table {
|
||||
|
||||
/* Signal Table */
|
||||
typedef struct signal_table {
|
||||
uintptr_t * functions[NUMSIGNALS];
|
||||
uintptr_t functions[NUMSIGNALS];
|
||||
} sig_table_t;
|
||||
|
||||
/* Portable process struct */
|
||||
@ -78,6 +79,9 @@ typedef struct process {
|
||||
struct regs * syscall_registers; /* Registers at interrupt */
|
||||
list_t * wait_queue;
|
||||
list_t * shm_mappings; /* Shared memory chunk mappings */
|
||||
list_t * signal_queue; /* Queued signals */
|
||||
thread_t signal_state;
|
||||
char * signal_kstack;
|
||||
} process_t;
|
||||
|
||||
void initialize_process_tree();
|
||||
@ -95,6 +99,7 @@ uint32_t process_append_fd(process_t * proc, fs_node_t * node);
|
||||
process_t * process_from_pid(pid_t pid);
|
||||
void delete_process(process_t * proc);
|
||||
uint32_t process_move_fd(process_t * proc, int src, int dest);
|
||||
int XXX_slow_process_is_queued(process_t * proc);
|
||||
|
||||
volatile process_t * current_process;
|
||||
|
||||
|
@ -107,6 +107,8 @@ struct regs {
|
||||
unsigned int eip, cs, eflags, useresp, ss;
|
||||
};
|
||||
|
||||
typedef struct regs regs_t;
|
||||
|
||||
typedef void (*irq_handler_t) (struct regs *);
|
||||
|
||||
/* Panic */
|
||||
@ -357,4 +359,10 @@ typedef struct {
|
||||
int wakeup_queue(list_t * queue);
|
||||
int sleep_on(list_t * queue);
|
||||
|
||||
typedef struct {
|
||||
uint32_t signum;
|
||||
uintptr_t handler;
|
||||
regs_t registers_before;
|
||||
} signal_t;
|
||||
|
||||
#endif
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <system.h>
|
||||
#include <process.h>
|
||||
#include <logging.h>
|
||||
#include <signal.h>
|
||||
|
||||
#define KERNEL_HEAP_END 0x02000000
|
||||
|
||||
@ -305,6 +306,11 @@ page_fault(
|
||||
uint32_t faulting_address;
|
||||
asm volatile("mov %%cr2, %0" : "=r"(faulting_address));
|
||||
|
||||
if (r->eip == 0xFFFFFFFF) {
|
||||
return_from_signal_handler();
|
||||
}
|
||||
|
||||
#if 1
|
||||
int present = !(r->err_code & 0x1);
|
||||
int rw = r->err_code & 0x2;
|
||||
int user = r->err_code & 0x4;
|
||||
@ -313,8 +319,14 @@ page_fault(
|
||||
|
||||
kprintf("\033[1;37;41m");
|
||||
kprintf("Segmentation fault. (p:%d,rw:%d,user:%d,res:%d,id:%d) at 0x%x eip:0x%x pid=%d\n", present, rw, user, reserved, id, faulting_address, r->eip, getpid());
|
||||
|
||||
HALT_AND_CATCH_FIRE("Segmentation fault", r);
|
||||
#else
|
||||
signal_t * sig = malloc(sizeof(signal_t));
|
||||
sig->handler = current_process->signals.functions[SIGSEGV];
|
||||
sig->signum = SIGSEGV;
|
||||
handle_signal(current_process, sig);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -98,7 +98,7 @@ exec(
|
||||
free(header);
|
||||
close_fs(file);
|
||||
|
||||
for (uintptr_t stack_pointer = 0x10000000; stack_pointer < 0x100F0000; stack_pointer += 0x1000) {
|
||||
for (uintptr_t stack_pointer = 0x10000000; stack_pointer < 0x10100000; stack_pointer += 0x1000) {
|
||||
alloc_frame(get_page(stack_pointer, 1, current_directory), 0, 1);
|
||||
}
|
||||
|
||||
@ -120,6 +120,8 @@ exec(
|
||||
process_append_fd((process_t *)current_process, NULL);
|
||||
}
|
||||
|
||||
current_process->image.start = entry;
|
||||
|
||||
/* Go go go */
|
||||
enter_user_jmp(entry, argc, argv_, 0x100EFFFF);
|
||||
|
||||
@ -150,6 +152,7 @@ system(
|
||||
* not all that much we can do right now. */
|
||||
while (child_task->finished == 0) {
|
||||
if (child_task->finished != 0) break;
|
||||
switch_task(1);
|
||||
}
|
||||
/* Grab the child's return value */
|
||||
int ret = child_task->status;
|
||||
|
@ -176,6 +176,7 @@ process_t * spawn_init() {
|
||||
init->finished = 0;
|
||||
init->wait_queue = list_create();
|
||||
init->shm_mappings = NULL;
|
||||
init->signal_queue = list_create();
|
||||
|
||||
/* What the hey, let's also set the description on this one */
|
||||
init->description = "[init]";
|
||||
@ -261,8 +262,10 @@ process_t * spawn_process(volatile process_t * parent) {
|
||||
/* Zero out the process status */
|
||||
proc->status = 0;
|
||||
proc->finished = 0;
|
||||
memset(proc->signals.functions, 0x00, sizeof(uintptr_t) * NUMSIGNALS);
|
||||
proc->wait_queue = list_create();
|
||||
proc->shm_mappings = list_create();
|
||||
proc->signal_queue = list_create();
|
||||
|
||||
/* Insert the process into the process tree as a child
|
||||
* of the parent process. */
|
||||
@ -402,7 +405,9 @@ int wakeup_queue(list_t * queue) {
|
||||
int awoken_processes = 0;
|
||||
while (queue->length > 0) {
|
||||
node_t * node = list_pop(queue);
|
||||
make_process_ready(node->value);
|
||||
if (!((process_t *)node->value)->finished) {
|
||||
make_process_ready(node->value);
|
||||
}
|
||||
free(node);
|
||||
awoken_processes++;
|
||||
}
|
||||
@ -414,3 +419,12 @@ int sleep_on(list_t * queue) {
|
||||
switch_task(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int XXX_slow_process_is_queued(process_t * proc) {
|
||||
foreach(node, process_queue) {
|
||||
if (node->value == proc)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
84
kernel/sys/signal.c
Normal file
84
kernel/sys/signal.c
Normal file
@ -0,0 +1,84 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
*
|
||||
* Signal Handling
|
||||
*/
|
||||
|
||||
#include <system.h>
|
||||
#include <signal.h>
|
||||
|
||||
void enter_signal_handler(uintptr_t location, int signum, uintptr_t stack) {
|
||||
kprintf("[debug] Jumping to 0x%x with %d pushed and a stack at 0x%x\n", location, signum, stack);
|
||||
asm volatile(
|
||||
"mov %2, %%esp\n"
|
||||
"pushl %1\n" /* argument count */
|
||||
"pushl $0xFFFFFFFF\n"
|
||||
"mov $0x23, %%ax\n" /* Segment selector */
|
||||
"mov %%ax, %%ds\n"
|
||||
"mov %%ax, %%es\n"
|
||||
"mov %%ax, %%fs\n"
|
||||
"mov %%ax, %%gs\n"
|
||||
"mov %%esp, %%eax\n" /* Stack -> EAX */
|
||||
"pushl $0x23\n" /* Segment selector again */
|
||||
"pushl %%eax\n"
|
||||
"pushf\n" /* Push flags */
|
||||
"popl %%eax\n" /* Fix the Interrupt flag */
|
||||
"orl $0x200, %%eax\n"
|
||||
"pushl %%eax\n"
|
||||
"pushl $0x1B\n"
|
||||
"pushl %0\n" /* Push the entry point */
|
||||
"iret\n"
|
||||
: : "m"(location), "m"(signum), "r"(stack) : "%ax", "%esp", "%eax");
|
||||
kprintf("Yep, definitely an iret issue.\n");
|
||||
}
|
||||
|
||||
void handle_signal(process_t * proc, signal_t * sig) {
|
||||
kprintf("[signal] Need to process signal %d for process %d\n", sig->signum, proc->id);
|
||||
|
||||
if (!sig->handler) {
|
||||
kprintf("[debug] Process %d killed by unhandled signal.\n", proc->id);
|
||||
kprintf("Current process = %d\n", current_process->id);
|
||||
kexit(127 + sig);
|
||||
kprintf("Still here.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (sig->handler == 1) /* Ignore */ {
|
||||
return;
|
||||
}
|
||||
|
||||
uintptr_t stack = 0x100EFFFF;
|
||||
|
||||
/* Not marked as ignored, must call signal */
|
||||
enter_signal_handler(sig->handler, sig->signum, stack);
|
||||
|
||||
}
|
||||
|
||||
list_t * rets_from_sig;
|
||||
|
||||
void return_from_signal_handler() {
|
||||
kprintf("[debug] Return From Signal for process %d\n", current_process->id);
|
||||
|
||||
if (__builtin_expect(!rets_from_sig, 0)) {
|
||||
rets_from_sig = list_create();
|
||||
}
|
||||
|
||||
list_insert(rets_from_sig, current_process);
|
||||
|
||||
switch_next();
|
||||
}
|
||||
|
||||
void fix_signal_stacks() {
|
||||
if (rets_from_sig) {
|
||||
while (rets_from_sig->head) {
|
||||
node_t * n = list_dequeue(rets_from_sig);
|
||||
process_t * p = n->value;
|
||||
p->thread.esp = p->signal_state.esp;
|
||||
p->thread.eip = p->signal_state.eip;
|
||||
p->thread.ebp = p->signal_state.ebp;
|
||||
memcpy(p->image.stack - KERNEL_STACK_SIZE, p->signal_kstack, KERNEL_STACK_SIZE);
|
||||
free(p->signal_kstack);
|
||||
make_process_ready(p);
|
||||
free(n);
|
||||
}
|
||||
}
|
||||
}
|
@ -110,7 +110,6 @@ static int wait(int child) {
|
||||
kprintf("Tried to wait for non-existent process\n");
|
||||
}
|
||||
while (child_task->finished == 0) {
|
||||
if (child_task->finished != 0) break;
|
||||
/* Add us to the wait queue for this child */
|
||||
sleep_on(child_task->wait_queue);
|
||||
}
|
||||
@ -313,6 +312,55 @@ static int kernel_name_XXX(char * buffer) {
|
||||
__kernel_arch);
|
||||
}
|
||||
|
||||
static int send_signal(pid_t process, uint32_t signal) {
|
||||
process_t * receiver = process_from_pid(process);
|
||||
|
||||
if (!receiver) {
|
||||
/* Invalid pid */
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (receiver->user != current_process->user && current_process->user != USER_ROOT_UID) {
|
||||
/* No way in hell. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (signal >= NUMSIGNALS) {
|
||||
/* Invalid signal */
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (receiver->finished) {
|
||||
/* Can't send signals to finished processes */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Append signal to list */
|
||||
signal_t * sig = malloc(sizeof(signal_t));
|
||||
sig->handler = (uintptr_t)receiver->signals.functions[signal];
|
||||
sig->signum = signal;
|
||||
memset(&sig->registers_before, 0x00, sizeof(regs_t));
|
||||
|
||||
if (!XXX_slow_process_is_queued(receiver)) {
|
||||
make_process_ready(receiver);
|
||||
}
|
||||
|
||||
kprintf("[signal] Sending signal %d to PID %d from PID %d\n", signal, process, current_process->id);
|
||||
|
||||
list_insert(receiver->signal_queue, sig);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uintptr_t sys_signal(uint32_t signum, uintptr_t handler) {
|
||||
if (signum >= NUMSIGNALS) {
|
||||
return -1;
|
||||
}
|
||||
uintptr_t old = current_process->signals.functions[signum];
|
||||
current_process->signals.functions[signum] = handler;
|
||||
return old;
|
||||
}
|
||||
|
||||
/*
|
||||
static void inspect_memory (uintptr_t vaddr) {
|
||||
// Please use this scary hack of a function as infrequently as possible.
|
||||
@ -322,10 +370,10 @@ static void inspect_memory (uintptr_t vaddr) {
|
||||
|
||||
static int reboot() {
|
||||
kprintf("[kernel] Reboot requested from process %d by user #%d\n", current_process->id, current_process->user);
|
||||
kprintf("[kernel] Good bye!\n");
|
||||
if (current_process->user != 0) {
|
||||
if (current_process->user != USER_ROOT_UID) {
|
||||
return -1;
|
||||
} else {
|
||||
kprintf("[kernel] Good bye!\n");
|
||||
/* Goodbye, cruel world */
|
||||
uint8_t out = 0x02;
|
||||
while ((out & 0x02) != 0) {
|
||||
@ -435,7 +483,9 @@ static uintptr_t syscalls[] = {
|
||||
(uintptr_t)&mousedevice,
|
||||
(uintptr_t)&sys_mkdir,
|
||||
(uintptr_t)&shm_obtain,
|
||||
(uintptr_t)&shm_release, /* 36 */
|
||||
(uintptr_t)&shm_release, /* 36 */
|
||||
(uintptr_t)&send_signal,
|
||||
(uintptr_t)&sys_signal,
|
||||
0
|
||||
};
|
||||
uint32_t num_syscalls;
|
||||
|
@ -76,11 +76,14 @@ void free_directory(page_directory_t * dir) {
|
||||
void reap_process(process_t * proc) {
|
||||
list_free(proc->wait_queue);
|
||||
free(proc->wait_queue);
|
||||
list_free(proc->signal_queue);
|
||||
free(proc->signal_queue);
|
||||
free((void *)(proc->image.stack - KERNEL_STACK_SIZE));
|
||||
free_directory(proc->thread.page_directory);
|
||||
free((void *)(proc->fds.entries));
|
||||
|
||||
shm_release_all(proc);
|
||||
kprintf("reaping %s\n", proc->name);
|
||||
kprintf("[kernel] reaping %s\n", proc->name);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -322,6 +325,17 @@ switch_task(uint8_t reschedule) {
|
||||
reap_process(proc);
|
||||
}
|
||||
}
|
||||
fix_signal_stacks();
|
||||
/* XXX: Signals */
|
||||
if (!current_process->finished) {
|
||||
if (current_process->signal_queue->length > 0) {
|
||||
node_t * node = list_dequeue(current_process->signal_queue);
|
||||
signal_t * sig = node->value;
|
||||
free(node);
|
||||
handle_signal(current_process, sig);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -357,6 +371,16 @@ switch_next() {
|
||||
/* Validate */
|
||||
assert((eip > (uintptr_t)&code) && (eip < (uintptr_t)&end) && "Task switch return point is not within Kernel!");
|
||||
|
||||
if (!current_process->finished) {
|
||||
if (current_process->signal_queue->length > 0) {
|
||||
current_process->signal_kstack = malloc(KERNEL_STACK_SIZE);
|
||||
current_process->signal_state.esp = current_process->thread.esp;
|
||||
current_process->signal_state.eip = current_process->thread.eip;
|
||||
current_process->signal_state.ebp = current_process->thread.ebp;
|
||||
memcpy(current_process->signal_kstack, current_process->image.stack - KERNEL_STACK_SIZE, KERNEL_STACK_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the page directory */
|
||||
current_directory = current_process->thread.page_directory;
|
||||
/* Set the kernel stack in the TSS */
|
||||
|
@ -18,6 +18,9 @@ DEFN_SYSCALL1(chdir, 28, char *);
|
||||
DEFN_SYSCALL0(getuid, 23);
|
||||
DEFN_SYSCALL0(gethostname, 32);
|
||||
|
||||
DEFN_SYSCALL2(signal, 38, uint32_t, void *);
|
||||
DEFN_SYSCALL2(send_signal, 37, uint32_t, uint32_t)
|
||||
|
||||
#define LINE_LEN 4096
|
||||
|
||||
char cwd[1024] = {'/',0};
|
||||
@ -79,12 +82,24 @@ void draw_prompt(int ret) {
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
uint32_t child = 0;
|
||||
|
||||
void sig_int(int sig) {
|
||||
if (child) {
|
||||
syscall_send_signal(child, sig);
|
||||
} else {
|
||||
printf("stop that!\n");
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
int pid = getpid();
|
||||
int nowait = 0;
|
||||
int free_cmd = 0;
|
||||
int last_ret = 0;
|
||||
|
||||
syscall_signal(9, sig_int);
|
||||
|
||||
getusername();
|
||||
gethostname();
|
||||
|
||||
@ -168,6 +183,7 @@ int main(int argc, char ** argv) {
|
||||
return i;
|
||||
} else {
|
||||
if (!nowait) {
|
||||
child = f;
|
||||
last_ret = syscall_wait(f);
|
||||
}
|
||||
free(cmd);
|
||||
|
@ -18,6 +18,25 @@ DEFN_SYSCALL1(setuid, 24, unsigned int);
|
||||
DEFN_SYSCALL1(kernel_string_XXX, 25, char *);
|
||||
DEFN_SYSCALL0(gethostname, 32);
|
||||
|
||||
DEFN_SYSCALL2(signal, 38, uint32_t, void *);
|
||||
DEFN_SYSCALL2(send_signal, 37, uint32_t, uint32_t)
|
||||
|
||||
uint32_t child = 0;
|
||||
|
||||
void sig_int(int sig) {
|
||||
/* Pass onto the shell */
|
||||
if (child) {
|
||||
syscall_send_signal(child, sig);
|
||||
}
|
||||
/* Else, ignore */
|
||||
}
|
||||
|
||||
void sig_segv(int sig) {
|
||||
printf("Segmentation fault.\n");
|
||||
exit(127 + sig);
|
||||
/* no return */
|
||||
}
|
||||
|
||||
int checkUserPass(char * user, char * pass) {
|
||||
|
||||
/* Generate SHA512 */
|
||||
@ -62,6 +81,9 @@ int main(int argc, char ** argv) {
|
||||
|
||||
fprintf(stdout, "\n%s\n\n", _uname);
|
||||
|
||||
syscall_signal(9, sig_int);
|
||||
syscall_signal(11, sig_segv);
|
||||
|
||||
while (1) {
|
||||
char * username = malloc(sizeof(char) * 1024);
|
||||
char * password = malloc(sizeof(char) * 1024);
|
||||
@ -100,8 +122,10 @@ int main(int argc, char ** argv) {
|
||||
syscall_setuid(uid);
|
||||
int i = execve(args[0], args, NULL);
|
||||
} else {
|
||||
child = f;
|
||||
syscall_wait(f);
|
||||
}
|
||||
child = 0;
|
||||
free(username);
|
||||
free(password);
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
/*
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
*
|
||||
* Terminal Emulator
|
||||
*/
|
||||
|
||||
@ -2822,6 +2823,10 @@ void clear_input() {
|
||||
input_collected = 0;
|
||||
}
|
||||
|
||||
uint32_t child_pid = 0;
|
||||
|
||||
DEFN_SYSCALL2(send_signal, 37, uint32_t, uint32_t)
|
||||
|
||||
int buffer_put(char c) {
|
||||
if (c == 8) {
|
||||
/* Backspace */
|
||||
@ -2834,6 +2839,10 @@ int buffer_put(char c) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (c == 3) {
|
||||
syscall_send_signal(child_pid, 9);
|
||||
return 0;
|
||||
}
|
||||
if (c < 10 || (c > 10 && c < 32) || c > 126) {
|
||||
return 0;
|
||||
}
|
||||
@ -2978,6 +2987,10 @@ int main(int argc, char ** argv) {
|
||||
int i = execve(tokens[0], tokens, NULL);
|
||||
return 0;
|
||||
} else {
|
||||
|
||||
child_pid = f;
|
||||
printf("[terminal] child is %d\n", child_pid);
|
||||
|
||||
char buf[1024];
|
||||
while (1) {
|
||||
struct stat _stat;
|
||||
|
Loading…
Reference in New Issue
Block a user