Added usermode interrupt handling

This commit is contained in:
2022-12-21 11:37:13 -06:00
parent 590290f92b
commit 166841da51
5 changed files with 175 additions and 50 deletions

View File

@@ -22,6 +22,8 @@
#define IO_PORT 1 << 1 #define IO_PORT 1 << 1
#define IO_MAILBOX 2 << 1 #define IO_MAILBOX 2 << 1
typedef unsigned long (*signal_handler_t)(void*, void*);
struct process_context_t; struct process_context_t;
struct module_t struct module_t
@@ -73,10 +75,24 @@ struct port_t
unsigned long owner_pid; 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 kernel_t
{ {
struct syscall_t syscall_table[MAX_SYSCALL_ID]; struct syscall_t syscall_table[MAX_SYSCALL_ID];
struct priority_queue_t priority_queue; struct priority_queue_t priority_queue;
struct avltree_t *interrupt_handlers;
struct avltree_t *port_table; struct avltree_t *port_table;
struct avltree_t *process_table; struct avltree_t *process_table;
struct process_t *active_process; 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_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_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); int receive_message(struct message_t *buffer, int flags);
void panic(const char *message) __attribute__ ((noreturn)); void panic(const char *message) __attribute__ ((noreturn));

View File

@@ -33,12 +33,28 @@ struct process_context_t
void load_context(struct process_context_t *context); 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 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_stack(struct process_context_t *context, void *stack);
void set_context_flags(struct process_context_t *context, unsigned long flags); 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 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 #endif

View File

@@ -362,7 +362,7 @@ enum error_t kernel_send_message(unsigned long recipient, struct message_t *mess
{ {
return EDOESNTEXIST; 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); printf("Sending message directly from %i to %i\n", kernel.active_process->pid, dest->pid);
struct message_t kernel_buffer; 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) enum error_t kernel_queue_message(unsigned long recipient, struct message_t *message)
{ {
struct process_t *dest = avl_get(kernel.process_table, recipient); 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) int receive_message(struct message_t *buffer, int flags)
{ {
if(kernel.active_process->sending_queue.count > 0) if(kernel.active_process->message_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)
{ {
struct message_t *queued_msg = queue_get_next(&kernel.active_process->message_queue); struct message_t *queued_msg = queue_get_next(&kernel.active_process->message_queue);
memcpy(buffer, queued_msg, sizeof(struct message_t)); 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) void panic(const char *message)
{ {
printf("panic: %s", message); printf("panic: %s", message);

View File

@@ -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); enum error_t status = kernel_send_message(recipient.unsigned_int, message.ptr);
if(status == EBUSY && op_type == IO_SYNC) if(status == EBUSY && op_type == IO_ASYNC)
{
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)
{ {
return kernel_queue_message(recipient.unsigned_int, message.ptr); return kernel_queue_message(recipient.unsigned_int, message.ptr);
} }

View File

@@ -4,16 +4,27 @@
#include "heap.h" #include "heap.h"
#include "string.h" #include "string.h"
#include "system.h" #include "system.h"
#include <stdarg.h>
void *get_context_pc(struct process_context_t *context)
{
return (void*) context->eip;
}
void set_context_pc(struct process_context_t *context, void *pc) void set_context_pc(struct process_context_t *context, void *pc)
{ {
context->eip = pc; context->eip = (unsigned long) pc;
context->cs = 0x1B; 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) 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; context->ss = 0x23;
} }
@@ -26,3 +37,50 @@ void set_context_return(struct process_context_t *context, unsigned long value)
{ {
context->gp_registers[0] = 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;
}