Added usermode interrupt handling
This commit is contained in:
@@ -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));
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
107
src/kernel.c
107
src/kernel.c
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user