From 166841da515a62d1bc4a0c2b64366928fb8ee9fc Mon Sep 17 00:00:00 2001 From: Nathan Giddings Date: Wed, 21 Dec 2022 11:37:13 -0600 Subject: [PATCH] Added usermode interrupt handling --- include/kernel.h | 26 ++++++++- include/platform/context.h | 16 ++++++ src/kernel.c | 107 +++++++++++++++++++++++++------------ src/syscalls.c | 14 +---- src/x86/context.c | 62 ++++++++++++++++++++- 5 files changed, 175 insertions(+), 50 deletions(-) diff --git a/include/kernel.h b/include/kernel.h index 6908394..64b607e 100644 --- a/include/kernel.h +++ b/include/kernel.h @@ -22,6 +22,8 @@ #define IO_PORT 1 << 1 #define IO_MAILBOX 2 << 1 +typedef unsigned long (*signal_handler_t)(void*, void*); + struct process_context_t; struct module_t @@ -73,10 +75,24 @@ struct port_t unsigned long owner_pid; }; +struct signal_action_t +{ + unsigned long pid; + signal_handler_t func_ptr; + void (*trampoline_ptr)(); + void *userdata; +}; + +struct signal_context_t +{ + unsigned long signal_id; +}; + struct kernel_t { struct syscall_t syscall_table[MAX_SYSCALL_ID]; struct priority_queue_t priority_queue; + struct avltree_t *interrupt_handlers; struct avltree_t *port_table; struct avltree_t *process_table; struct process_t *active_process; @@ -111,10 +127,16 @@ unsigned long kernel_get_port_owner(unsigned long id); enum error_t kernel_send_message(unsigned long recipient, struct message_t *message); -enum error_t kernel_queue_sender(unsigned long recipient); - enum error_t kernel_queue_message(unsigned long recipient, struct message_t *message); +enum error_t kernel_register_interrupt_handler(unsigned long interrupt, signal_handler_t handler, void *userdata); + +enum error_t kernel_remove_interrupt_handler(unsigned long interrupt); + +enum error_t kernel_execute_interrupt_handler(unsigned long interrupt); + +enum error_t kernel_signal_return(); + int receive_message(struct message_t *buffer, int flags); void panic(const char *message) __attribute__ ((noreturn)); diff --git a/include/platform/context.h b/include/platform/context.h index 2152655..92b7a03 100644 --- a/include/platform/context.h +++ b/include/platform/context.h @@ -33,12 +33,28 @@ struct process_context_t void load_context(struct process_context_t *context); +void *get_context_pc(struct process_context_t *context); + void set_context_pc(struct process_context_t *context, void *pc); +void *get_context_stack(struct process_context_t *context); + void set_context_stack(struct process_context_t *context, void *stack); void set_context_flags(struct process_context_t *context, unsigned long flags); void set_context_return(struct process_context_t *context, unsigned long value); +void *context_stack_push(struct process_context_t *context, unsigned long value); + +void *context_stack_push_struct(struct process_context_t *context, void *data, unsigned long size); + +void *context_stack_pop(struct process_context_t *context, void *value); + +void *context_stack_pop_struct(struct process_context_t *context, void *value, unsigned long size); + +void context_call_func(struct process_context_t *context, void *func_ptr, void *ret_ptr, int argc, ...); + +void context_cleanup_func(struct process_context_t *context, int argc); + #endif diff --git a/src/kernel.c b/src/kernel.c index dad6537..8803de4 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -362,7 +362,7 @@ enum error_t kernel_send_message(unsigned long recipient, struct message_t *mess { return EDOESNTEXIST; } - else if(dest->message_buffer != NULL) + else if(dest->message_buffer != NULL && dest->state == PROCESS_REQUESTING) { printf("Sending message directly from %i to %i\n", kernel.active_process->pid, dest->pid); struct message_t kernel_buffer; @@ -383,23 +383,6 @@ enum error_t kernel_send_message(unsigned long recipient, struct message_t *mess } } -enum error_t kernel_queue_sender(unsigned long recipient) -{ - struct process_t *dest = avl_get(kernel.process_table, recipient); - if(dest != NULL) - { - printf("Queueing process %i to %i\n", kernel.active_process->pid, dest->pid); - queue_insert(&dest->sending_queue, kernel.active_process); - kernel.active_process->state = PROCESS_SENDING; - kernel.active_process = NULL; - return ENONE; - } - else - { - return EDOESNTEXIST; - } -} - enum error_t kernel_queue_message(unsigned long recipient, struct message_t *message) { struct process_t *dest = avl_get(kernel.process_table, recipient); @@ -423,21 +406,7 @@ enum error_t kernel_queue_message(unsigned long recipient, struct message_t *mes int receive_message(struct message_t *buffer, int flags) { - if(kernel.active_process->sending_queue.count > 0) - { - struct message_t kernel_buffer; - struct process_t *sender = queue_get_next(&kernel.active_process->sending_queue); - paging_load_address_space(sender->page_table); - memcpy(&kernel_buffer, &sender->message_buffer, sizeof(struct message_t)); - kernel_buffer.sender = sender->pid; - paging_load_address_space(kernel.active_process->page_table); - memcpy(buffer, &kernel_buffer, sizeof(struct message_t)); - sender->state = PROCESS_ACTIVE; - set_context_return(sender->ctx, ENONE); - priorityqueue_insert(&kernel.priority_queue, sender, sender->priority); - return ENONE; - } - else if(kernel.active_process->message_queue.count > 0) + if(kernel.active_process->message_queue.count > 0) { struct message_t *queued_msg = queue_get_next(&kernel.active_process->message_queue); memcpy(buffer, queued_msg, sizeof(struct message_t)); @@ -457,6 +426,78 @@ int receive_message(struct message_t *buffer, int flags) } } +enum error_t kernel_register_interrupt_handler(unsigned long interrupt, signal_handler_t handler, void *userdata) +{ + if(avl_get(kernel.interrupt_handlers, interrupt) != NULL) + { + return EEXISTS; + } + struct signal_action_t *action = kmalloc(sizeof(struct signal_action_t)); + action->pid = kernel.active_process->pid; + action->func_ptr = handler; + action->userdata = userdata; + kernel.interrupt_handlers = avl_insert(kernel.interrupt_handlers, interrupt, action); + return ENONE; +} + +enum error_t kernel_remove_interrupt_handler(unsigned long interrupt) +{ + if(avl_get(kernel.interrupt_handlers, interrupt) == NULL) + { + return EDOESNTEXIST; + } + kernel.interrupt_handlers = avl_remove(kernel.interrupt_handlers, interrupt); + return ENONE; +} + +enum error_t kernel_execute_interrupt_handler(unsigned long interrupt) +{ + struct signal_action_t *action = avl_get(kernel.interrupt_handlers, interrupt); + if(action == NULL) + { + return EDOESNTEXIST; + } + + struct process_t *process = avl_get(kernel.process_table, action->pid); + if(process == NULL) + { + kernel.interrupt_handlers = avl_remove(kernel.interrupt_handlers, interrupt); + return EDOESNTEXIST; + } + + paging_load_address_space(process->page_table); + + struct signal_context_t siginfo = { + .signal_id = interrupt + }; + void *siginfo_ptr = context_stack_push_struct(process->ctx, &siginfo, sizeof(siginfo)); + context_stack_push_struct(process->ctx, process->ctx, sizeof(*process->ctx)); + context_stack_push(process->ctx, process->state); + context_call_func(process->ctx, action->func_ptr, action->trampoline_ptr, 2, action->userdata, siginfo_ptr); + if(process->state != PROCESS_ACTIVE) + { + process->state = PROCESS_ACTIVE; + priorityqueue_insert(&kernel.priority_queue, process, process->priority); + } + + paging_load_address_space(kernel.active_process->page_table); + + return ENONE; +} + +enum error_t kernel_signal_return() +{ + context_cleanup_func(kernel.active_process->ctx, 2); + context_stack_pop(kernel.active_process->ctx, &kernel.active_process->state); + context_stack_pop_struct(kernel.active_process->ctx, kernel.active_process->ctx, sizeof(*kernel.active_process->ctx)); + if(kernel.active_process->state == PROCESS_REQUESTING) + { + receive_message(kernel.active_process->message_buffer, 0); + load_context(kernel.active_process->ctx); + } + return ENONE; +} + void panic(const char *message) { printf("panic: %s", message); diff --git a/src/syscalls.c b/src/syscalls.c index c36954c..475fbde 100644 --- a/src/syscalls.c +++ b/src/syscalls.c @@ -111,19 +111,7 @@ size_t send(syscall_arg_t recipient, syscall_arg_t message, syscall_arg_t flags) } } enum error_t status = kernel_send_message(recipient.unsigned_int, message.ptr); - if(status == EBUSY && op_type == IO_SYNC) - { - status = kernel_queue_sender(recipient.unsigned_int); - if(status) - { - return status; - } - else - { - load_context(kernel_advance_scheduler()); - } - } - else if(status == EBUSY && op_type == IO_ASYNC) + if(status == EBUSY && op_type == IO_ASYNC) { return kernel_queue_message(recipient.unsigned_int, message.ptr); } diff --git a/src/x86/context.c b/src/x86/context.c index 9e6b04c..bbc3107 100644 --- a/src/x86/context.c +++ b/src/x86/context.c @@ -4,16 +4,27 @@ #include "heap.h" #include "string.h" #include "system.h" +#include + +void *get_context_pc(struct process_context_t *context) +{ + return (void*) context->eip; +} void set_context_pc(struct process_context_t *context, void *pc) { - context->eip = pc; + context->eip = (unsigned long) pc; context->cs = 0x1B; } +void *get_context_stack(struct process_context_t *context) +{ + return (void*) context->gp_registers[7]; +} + void set_context_stack(struct process_context_t *context, void *stack) { - context->gp_registers[7] = stack; + context->gp_registers[7] = (unsigned long)stack; context->ss = 0x23; } @@ -25,4 +36,51 @@ void set_context_flags(struct process_context_t *context, unsigned long flags) void set_context_return(struct process_context_t *context, unsigned long value) { context->gp_registers[0] = value; +} + +void *context_stack_push(struct process_context_t *context, unsigned long value) +{ + context->gp_registers[7] -= sizeof(long); + *((unsigned long*) context->gp_registers[7]) = value; + return (void*) context->gp_registers[7]; +} + +void *context_stack_push_struct(struct process_context_t *context, void *data, unsigned long size) +{ + context->gp_registers[7] -= size; + memcpy((void*) context->gp_registers[7], data, size); + return (void*) context->gp_registers[7]; +} + +void *context_stack_pop(struct process_context_t *context, void *value) +{ + unsigned long *prev_stack = ((unsigned long*) context->gp_registers[7]); + context->gp_registers[7] += sizeof(unsigned long); + *((unsigned long*) value) = *prev_stack; + return (void*) context->gp_registers[7]; +} + +void *context_stack_pop_struct(struct process_context_t *context, void *value, unsigned long size) +{ + void *prev_stack = ((void*) context->gp_registers[7]); + context->gp_registers[7] += size; + memcpy(value, prev_stack, size); + return (void*) context->gp_registers[7]; +} + +void context_call_func(struct process_context_t *context, void *func_ptr, void *ret_ptr, int argc, ...) +{ + context->eip = (uint32_t) func_ptr; + va_list valist; + va_start(valist, argc); + for(int i = 0; i < argc; i++) + { + context_stack_push(context, va_arg(valist, unsigned long)); + } + context_stack_push(context, (unsigned long) ret_ptr); +} + +void context_cleanup_func(struct process_context_t *context, int argc) +{ + context->gp_registers[7] -= sizeof(unsigned long) * argc; } \ No newline at end of file