From 0ae4f7995da3910d5e7f08210755080260ee3ae1 Mon Sep 17 00:00:00 2001 From: ngiddings Date: Wed, 17 Aug 2022 02:47:41 -0500 Subject: [PATCH] Added basic IPC syscalls --- include/heap.h | 2 +- include/kernel.h | 51 +++++++++------ src/heap.c | 62 +++++++++--------- src/kernel.c | 161 +++++++++++++++++++++++++++++++++++++++++----- src/x86/preempt.S | 9 ++- 5 files changed, 217 insertions(+), 68 deletions(-) diff --git a/include/heap.h b/include/heap.h index b03c5f9..cb0cdde 100644 --- a/include/heap.h +++ b/include/heap.h @@ -14,7 +14,7 @@ * @param block_size Size in bytes of a single unit of allocation * @return a status code */ -int kminit(void *base, size_t heap_size, size_t block_size); +int kminit(void *base, void* start, size_t heap_size, size_t block_size); /** * @brief Allocates a block of memory containing at least `size` bytes. diff --git a/include/kernel.h b/include/kernel.h index 8b1b47f..0efc5f5 100644 --- a/include/kernel.h +++ b/include/kernel.h @@ -3,6 +3,7 @@ #include "avltree.h" #include "memmap.h" #include "priorityqueue.h" +#include "queue.h" #include "mmgr.h" #include "syscalls.h" #include @@ -10,11 +11,14 @@ #define MAX_SYSCALL_ID 256 #define module_limit 8 -enum process_state_t -{ - PROCESS_ACTIVE, - PROCESS_WAITING -}; +#define IO_OP 1 << 0 +#define IO_SYNC 0 << 0 +#define IO_ASYNC 1 << 0 + +#define IO_RECIPIENT_TYPE 3 << 1 +#define IO_PID 0 << 1 +#define IO_PORT 1 << 1 +#define IO_MAILBOX 2 << 1 struct process_context_t; @@ -41,25 +45,36 @@ struct message_t unsigned long args[6]; }; -struct address_space_t +enum process_state_t { - physaddr_t top_table; - int counter; + PROCESS_ACTIVE, + PROCESS_REQUESTING, + PROCESS_SENDING }; struct process_t { - size_t priority; - size_t resource_id; + unsigned long pid; + int priority; physaddr_t page_table; - struct process_context_t *state; - struct message_t *message; + enum process_state_t state; + struct queue_t sending_queue; + struct queue_t message_queue; + struct message_t *message_buffer; + struct process_context_t *ctx; +}; + +struct port_t +{ + unsigned long id; + unsigned long owner_pid; }; struct kernel_t { struct syscall_t syscall_table[MAX_SYSCALL_ID]; struct priority_queue_t priority_queue; + struct avltree_t *port_table; struct avltree_t *process_table; struct process_t *active_process; int next_pid; @@ -69,7 +84,7 @@ void kernel_initialize(struct boot_info_t *boot_info); int set_syscall(int id, int arg_count, int pid, void *func_ptr); -size_t do_syscall(enum syscall_id_t id, syscall_arg_t arg1, syscall_arg_t arg2, syscall_arg_t arg3); +size_t do_syscall(enum syscall_id_t id, syscall_arg_t arg1, syscall_arg_t arg2, syscall_arg_t arg3, void *pc, void *stack, unsigned long flags); int load_module(struct module_t *module); @@ -85,14 +100,12 @@ int store_active_context(struct process_context_t *context, size_t size); struct process_context_t *get_active_context(); -int open_port(int id); +int open_port(unsigned long id); -int close_port(int id); +int close_port(unsigned long id); -int send_message(int recipient, struct message_t *message); +int send_message(int recipient, struct message_t *message, int flags); -int receive_message(struct message_t *buffer); - -int request_message(struct message_t *buffer, void *temp); +int receive_message(struct message_t *buffer, int flags); void panic(const char *message) __attribute__ ((noreturn)); diff --git a/src/heap.c b/src/heap.c index 79fde3a..96de07e 100644 --- a/src/heap.c +++ b/src/heap.c @@ -9,7 +9,8 @@ struct heap_t { - struct heap_node_t *base; + void *base; + struct heap_node_t *header; size_t heap_size; size_t block_size; size_t tree_height; @@ -47,7 +48,7 @@ size_t find_free_block(struct heap_t *heap, size_t height) } for(size_t index = 1 << (heap->tree_height - height); index < 1 << (heap->tree_height - height + 1); index++) { - if(heap->base[index].state == AVAIL) + if(heap->header[index].state == AVAIL) { return index; } @@ -55,9 +56,9 @@ size_t find_free_block(struct heap_t *heap, size_t height) size_t index = find_free_block(heap, height + 1); if(index) { - heap->base[index].state = UNAVAIL; - heap->base[index << 1].state = AVAIL; - heap->base[(index << 1) ^ 1].state = AVAIL; + heap->header[index].state = UNAVAIL; + heap->header[index << 1].state = AVAIL; + heap->header[(index << 1) ^ 1].state = AVAIL; } return index << 1; } @@ -65,7 +66,7 @@ size_t find_free_block(struct heap_t *heap, size_t height) int map_region(struct heap_t *heap, size_t height, size_t index) { int status = 0; - if(heap->base[index].mapped == 0) + if(heap->header[index].mapped == 0) { if(height > 0) { @@ -83,48 +84,49 @@ int map_region(struct heap_t *heap, size_t height, size_t index) status = map_page(ptr, reserve_page(), PAGE_RW); } } - heap->base[index].mapped = 1; + heap->header[index].mapped = 1; } return status; } -int heap_contruct(struct heap_t *heap, void *base, size_t heap_size, size_t block_size) +int heap_contruct(struct heap_t *heap, void *base, void *start, size_t heap_size, size_t block_size) { - heap->base = (struct heap_node_t*) base; + heap->base = base; + heap->header = (struct heap_node_t*) start; heap->heap_size = heap_size; heap->block_size = block_size; heap->tree_height = ilog2(heap_size / block_size); size_t header_size = (heap_size / block_size) << 1; - for(size_t i = 1; i < (heap_size / block_size) * 2; i++) + for(size_t i = 1; i <= (heap_size / block_size) * 2; i++) { - int flags = page_type((void*) heap->base + i); + int flags = page_type((void*) heap->header + i); if((flags & PAGE_PRESENT) == 0) { - int status = map_page((void*)heap->base + i, reserve_page(), PAGE_RW); + int status = map_page((void*)heap->header + i, reserve_page(), PAGE_RW); if(status != S_OK) { return status; } } - heap->base[i].state = UNAVAIL; - heap->base[i].mapped = 0; + heap->header[i].state = UNAVAIL; + heap->header[i].mapped = 0; } for(size_t i = 0; i < heap_size / block_size; i++) { - if(block_size * i >= header_size) + if(block_size * i >= header_size + (start - base)) { size_t index = i + (1 << heap->tree_height); - heap->base[index].state = AVAIL; - for(; index > 1 && heap->base[index ^ 1].state == 0; index >>= 1) + heap->header[index].state = AVAIL; + for(; index > 1 && heap->header[index ^ 1].state == 0; index >>= 1) { - heap->base[index].state = UNAVAIL; - heap->base[index ^ 1].state = UNAVAIL; - heap->base[index >> 1].state = AVAIL; + heap->header[index].state = UNAVAIL; + heap->header[index ^ 1].state = UNAVAIL; + heap->header[index >> 1].state = AVAIL; } } else { - heap->base[i + (1 << heap->tree_height)].state = UNAVAIL; + heap->header[i + (1 << heap->tree_height)].state = UNAVAIL; } } return S_OK; @@ -138,7 +140,7 @@ void *heap_allocate(struct heap_t *heap, size_t size) size_t index = find_free_block(heap, height); if(index) { - heap->base[index].state = ALLOCATED; + heap->header[index].state = ALLOCATED; void *ptr = (void*) ((size_t) heap->base + (heap->block_size << height) * (index - (1 << (heap->tree_height - height)))); map_region(heap, height, index); return ptr; @@ -150,19 +152,19 @@ void heap_free(struct heap_t *heap, void *ptr) { size_t offset = (size_t) ptr - (size_t) heap->base; size_t index = (offset / heap->block_size) + (1 << heap->tree_height); - for(; index > 0 && heap->base[index].state == UNAVAIL; index >>= 1); - heap->base[index].state = AVAIL; - for(; index > 1 && heap->base[index ^ 1].state == AVAIL; index >>= 1) + for(; index > 0 && heap->header[index].state == UNAVAIL; index >>= 1); + heap->header[index].state = AVAIL; + for(; index > 1 && heap->header[index ^ 1].state == AVAIL; index >>= 1) { - heap->base[index].state = UNAVAIL; - heap->base[index ^ 1].state = UNAVAIL; - heap->base[index >> 1].state = AVAIL; + heap->header[index].state = UNAVAIL; + heap->header[index ^ 1].state = UNAVAIL; + heap->header[index >> 1].state = AVAIL; } } -int kminit(void *base, size_t heap_size, size_t block_size) +int kminit(void *base, void* start, size_t heap_size, size_t block_size) { - return heap_contruct(&system_heap, base, heap_size, block_size); + return heap_contruct(&system_heap, base, start, heap_size, block_size); } void *kmalloc(size_t size) diff --git a/src/kernel.c b/src/kernel.c index 2a8a6f4..9f46058 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -18,7 +18,7 @@ void kernel_initialize(struct boot_info_t *boot_info) { insert_region(&boot_info->map, (physaddr_t)&_kernel_pstart, (physaddr_t)&_kernel_pend - (physaddr_t)&_kernel_pstart, M_UNAVAILABLE); initialize_page_stack(&boot_info->map, (physaddr_t*)&_kernel_end); - kminit(page_stack_top(), 0xFFC00000 - (size_t)page_stack_top(), page_size); + kminit(&_kernel_start, page_stack_top(), 0xFFC00000 - (size_t)&_kernel_start, 64); initialize_screen(); printf("***%s***\n", PACKAGE_STRING); printf("Type\t\tLocation\t\tSize\n"); @@ -30,6 +30,7 @@ void kernel_initialize(struct boot_info_t *boot_info) kernel.active_process = NULL; kernel.next_pid = 1; kernel.process_table = NULL; + kernel.port_table = NULL; if(construct_priority_queue(&kernel.priority_queue, 512) != S_OK) { panic("Failed to construct priority queue."); @@ -51,11 +52,6 @@ void kernel_initialize(struct boot_info_t *boot_info) panic("Failed to initialize interrupts."); } - /*asm("mov $281, %ax;" - "mov %ax, %ds"); - - asm("hlt");*/ - irq_enable(); load_context(next_process()); } @@ -89,7 +85,7 @@ int set_syscall(int id, int arg_count, int pid, void *func_ptr) return S_OK; } -size_t do_syscall(enum syscall_id_t id, syscall_arg_t arg1, syscall_arg_t arg2, syscall_arg_t arg3) +size_t do_syscall(enum syscall_id_t id, syscall_arg_t arg1, syscall_arg_t arg2, syscall_arg_t arg3, void *pc, void *stack, unsigned long flags) { if(id < 0 || id > MAX_SYSCALL_ID) { @@ -111,6 +107,9 @@ size_t do_syscall(enum syscall_id_t id, syscall_arg_t arg1, syscall_arg_t arg2, paging_load_address_space(callee->page_table); switched_address_space = true; } + set_context_pc(kernel.active_process->ctx, pc); + set_context_stack(kernel.active_process->ctx, stack); + set_context_flags(kernel.active_process->ctx, flags); size_t result; switch(kernel.syscall_table[id].arg_count) { @@ -197,7 +196,7 @@ int active_process() } else { - return kernel.active_process->resource_id; + return kernel.active_process->pid; } } @@ -210,13 +209,17 @@ int add_process(void *program_entry, int priority, physaddr_t address_space) } struct process_context_t *initial_context = initialize_context(program_entry); new_process->priority = priority; - new_process->resource_id = kernel.next_pid; + new_process->pid = kernel.next_pid; new_process->page_table = address_space; - new_process->state = initial_context; - kernel.process_table = avl_insert(kernel.process_table, new_process->resource_id, new_process); + new_process->state = PROCESS_ACTIVE; + new_process->message_buffer = NULL; + new_process->ctx = initial_context; + queue_construct(&new_process->sending_queue); + queue_construct(&new_process->message_queue); + kernel.process_table = avl_insert(kernel.process_table, new_process->pid, new_process); priorityqueue_insert(&kernel.priority_queue, new_process, new_process->priority); kernel.next_pid++; - return new_process->resource_id; + return new_process->pid; } struct process_context_t *next_process() @@ -229,8 +232,8 @@ struct process_context_t *next_process() if(kernel.active_process != NULL) { paging_load_address_space(kernel.active_process->page_table); - printf("entering process %08x cr3=%08x state=%08x.\n", kernel.active_process, kernel.active_process->page_table, kernel.active_process->state); - return kernel.active_process->state; + printf("entering process %08x cr3=%08x ctx=%08x.\n", kernel.active_process, kernel.active_process->page_table, kernel.active_process->ctx); + return kernel.active_process->ctx; } panic("no processes available to enter!"); } @@ -248,16 +251,16 @@ int terminate_process(size_t process_id) } kernel.process_table = avl_remove(kernel.process_table, process_id); priorityqueue_remove(&kernel.priority_queue, process); - destroy_context(process->state); + destroy_context(process->ctx); kfree(process); return S_OK; } int store_active_context(struct process_context_t *context, size_t size) { - if(kernel.active_process != NULL && kernel.active_process->state != NULL) + if(kernel.active_process != NULL && kernel.active_process->ctx != NULL) { - memcpy(kernel.active_process->state, context, size); + memcpy(kernel.active_process->ctx, context, size); return S_OK; } else @@ -266,6 +269,130 @@ int store_active_context(struct process_context_t *context, size_t size) } } +int open_port(unsigned long id) +{ + if(avl_get(kernel.port_table, id) != NULL) + { + return S_EXISTS; + } + struct port_t *port = kmalloc(sizeof(struct port_t)); + port->id = id; + port->owner_pid = kernel.active_process->pid; + avl_insert(kernel.port_table, id, port); + return S_OK; +} + +int close_port(unsigned long id) +{ + struct port_t *port = avl_get(kernel.port_table, id); + if(port == NULL) + { + return S_DOESNT_EXIST; + } + else if(port->owner_pid != kernel.active_process->pid) + { + return S_INVALID_ARGUMENT; + } + avl_remove(kernel.port_table, id); + kfree(port); + return S_OK; +} + +int send_message(int recipient, struct message_t *message, int flags) +{ + int op_type = flags & IO_OP; + int dest_type = flags & IO_RECIPIENT_TYPE; + if((flags & ~(IO_OP | IO_RECIPIENT_TYPE)) != 0 || dest_type >= IO_MAILBOX) + { + return S_INVALID_ARGUMENT; + } + if(dest_type == IO_PORT) + { + struct port_t *port = avl_get(kernel.port_table, recipient); + if(port != NULL) + { + recipient = port->owner_pid; + } + else + { + return S_DOESNT_EXIST; + } + } + struct process_t *dest = avl_get(kernel.process_table, recipient); + if(dest == NULL) + { + return S_DOESNT_EXIST; + } + else if(dest->message_buffer != NULL) + { + struct message_t kernel_buffer; + memcpy(&kernel_buffer, message, sizeof(struct message_t)); + kernel_buffer.sender = kernel.active_process->pid; + paging_load_address_space(dest->page_table); + memcpy(dest->message_buffer, &kernel_buffer, sizeof(struct message_t)); + paging_load_address_space(kernel.active_process->page_table); + dest->message_buffer = NULL; + dest->state = PROCESS_ACTIVE; + set_context_return(dest->ctx, S_OK); + priorityqueue_insert(&kernel.priority_queue, dest, dest->priority); + return S_OK; + } + else if(op_type == IO_ASYNC) + { + struct message_t *queued_msg = kmalloc(sizeof(struct message_t)); + if(queued_msg == NULL) + { + return S_OUT_OF_MEMORY; + } + memcpy(queued_msg, message, sizeof(struct message_t)); + queue_insert(&dest->message_queue, queued_msg); + return S_OK; + } + else + { + queue_insert(&dest->sending_queue, kernel.active_process); + kernel.active_process->state = PROCESS_SENDING; + kernel.active_process = NULL; + load_context(next_process()); + } +} + +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, S_OK); + priorityqueue_insert(&kernel.priority_queue, sender, sender->priority); + return S_OK; + } + else 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)); + kfree(queued_msg); + return S_OK; + } + else if((flags & IO_OP) == IO_ASYNC) + { + return S_DOESNT_EXIST; + } + else + { + kernel.active_process->message_buffer = buffer; + kernel.active_process->state = PROCESS_REQUESTING; + kernel.active_process = NULL; + load_context(next_process()); + } +} + void panic(const char *message) { printf("panic: %s", message); diff --git a/src/x86/preempt.S b/src/x86/preempt.S index 6b4cfea..5814fe7 100644 --- a/src/x86/preempt.S +++ b/src/x86/preempt.S @@ -4,6 +4,13 @@ .type isr_syscall, @function isr_syscall: cli + mov %esp, %ebp + mov 8(%ebp), %esi + push %esi + mov 12(%ebp), %esi + push %esi + mov (%ebp), %esi + push %esi push %edx push %ecx push %ebx @@ -14,7 +21,7 @@ isr_syscall: mov %ax, %fs mov %ax, %gs call do_syscall - add $0x10, %esp + mov %ebp, %esp mov $0x23, %cx mov %cx, %ds mov %cx, %es