This commit is contained in:
Kevin Lange 2012-02-08 02:40:44 -06:00
parent a09be369ea
commit 65fa12f482
11 changed files with 263 additions and 10 deletions

View File

@ -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;

View File

@ -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

View File

@ -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
}
/*

View File

@ -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;

View File

@ -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
View 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);
}
}
}

View File

@ -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;

View File

@ -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 */

View File

@ -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);

View File

@ -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);
}

View File

@ -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;