diff --git a/include/elf.h b/include/elf.h index 14766da..6084c28 100644 --- a/include/elf.h +++ b/include/elf.h @@ -1,6 +1,5 @@ #pragma once -#include "mmgr.h" #include "types/physaddr.h" #include diff --git a/include/heap.h b/include/heap.h index 43d35b2..cb0cdde 100644 --- a/include/heap.h +++ b/include/heap.h @@ -1,6 +1,5 @@ #pragma once -#include "mmgr.h" #include /** @@ -15,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 0d1054e..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; @@ -36,23 +40,41 @@ struct boot_info_t struct message_t { - uint16_t sender, type; - uint32_t param1, param2, param3; + unsigned long sender; + unsigned long code; + unsigned long args[6]; +}; + +enum process_state_t +{ + 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; @@ -62,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); @@ -70,14 +92,20 @@ int active_process(); int add_process(void *program_entry, int priority, physaddr_t address_space); -struct process_context_t *next_process(struct process_context_t *prev_state); +struct process_context_t *next_process(); int terminate_process(size_t process_id); -/* -int accept_message(size_t process_id, struct message_t *message); +int store_active_context(struct process_context_t *context, size_t size); -int send_message(size_t process_id, const struct message_t *message); -*/ +struct process_context_t *get_active_context(); + +int open_port(unsigned long id); + +int close_port(unsigned long id); + +int send_message(int recipient, struct message_t *message, int flags); + +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 f3fd65d..dc6b27f 100644 --- a/include/platform/context.h +++ b/include/platform/context.h @@ -1,9 +1,26 @@ #pragma once -void *initialize_context(void *task_entry); +struct process_context_t; + +/** + * @brief Allocates a new process context and initializes it with the given + * program counter. + * + * @param task_entry + * @return void* + */ +void *initialize_context(void *pc); void destroy_context(void *ctx); -void save_context(struct process_context_t *context, void *ptr); +void save_context(struct process_context_t *context); void load_context(struct process_context_t *context); + +void set_context_pc(struct process_context_t *context, void *pc); + +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); diff --git a/include/platform/paging.h b/include/platform/paging.h index 9a67c26..9c3b2ee 100644 --- a/include/platform/paging.h +++ b/include/platform/paging.h @@ -13,7 +13,7 @@ enum page_flag_t PAGE_COPY_ON_WRITE = 1 << 18 }; -const size_t page_table_levels; +extern const size_t page_table_levels; /** * @brief diff --git a/include/priorityqueue.h b/include/priorityqueue.h index cb49fcb..15f34dc 100644 --- a/include/priorityqueue.h +++ b/include/priorityqueue.h @@ -70,7 +70,7 @@ int construct_priority_queue(struct priority_queue_t *queue, int capacity); * @param queue * @return void* */ -void *extract_min(struct priority_queue_t *queue); +void *priorityqueue_extract_min(struct priority_queue_t *queue); /** * @brief Inserts a new object onto the queue. @@ -80,7 +80,7 @@ void *extract_min(struct priority_queue_t *queue); * @param priority * @return int */ -int queue_insert(struct priority_queue_t *queue, void *value, int priority); +int priorityqueue_insert(struct priority_queue_t *queue, void *value, int priority); /** * @brief Removes the object with a matching value from the queue. @@ -89,4 +89,4 @@ int queue_insert(struct priority_queue_t *queue, void *value, int priority); * @param value * @return int */ -int queue_remove(struct priority_queue_t *queue, void *value); +int priorityqueue_remove(struct priority_queue_t *queue, void *value); diff --git a/include/queue.h b/include/queue.h new file mode 100644 index 0000000..97ac60a --- /dev/null +++ b/include/queue.h @@ -0,0 +1,60 @@ +#pragma once + +struct queue_node_t; + +/** + * @brief A last-in-first-out queue. + * + */ +struct queue_t +{ + /** + * @brief The number of objects stored in this queue. + * + */ + unsigned int count; + + /** + * @brief A link to the first node stored in this queue. + * + */ + struct queue_node_t *first; + + /** + * @brief A link to the last node stored in this queue. + * + */ + struct queue_node_t *last; +}; + +/** + * @brief Initializes a queue structure. + * + * @param queue + */ +void queue_construct(struct queue_t *queue); + +/** + * @brief Inserts a new item at the end of the queue. + * + * @param queue + * @param ptr + */ +void queue_insert(struct queue_t *queue, void *ptr); + +/** + * @brief Removes the next item from the queue and returns it. + * + * @param queue + * @return void* + */ +void *queue_get_next(struct queue_t *queue); + +/** + * @brief Returns the next item on the queue without removing it. + * + * @param queue + * @return void* + */ +void *queue_peek(struct queue_t *queue); + diff --git a/include/syscalls.h b/include/syscalls.h index 0a09101..3efd400 100644 --- a/include/syscalls.h +++ b/include/syscalls.h @@ -9,7 +9,11 @@ enum syscall_id_t SYSCALL_YIELD, SYSCALL_MMAP, SYSCALL_MUNMAP, - SYSCALL_TERMINATE_SELF + SYSCALL_TERMINATE_SELF, + SYSCALL_SEND, + SYSCALL_RECEIVE, + SYSCALL_OPEN_PORT, + SYSCALL_CLOSE_PORT }; typedef union @@ -48,3 +52,11 @@ size_t mmap(syscall_arg_t location, syscall_arg_t length, syscall_arg_t flags); size_t munmap(syscall_arg_t location, syscall_arg_t length); size_t terminate_self(); + +size_t send(syscall_arg_t recipient, syscall_arg_t message, syscall_arg_t flags); + +size_t receive(syscall_arg_t buffer, syscall_arg_t flags); + +size_t openport(syscall_arg_t id); + +size_t closeport(syscall_arg_t id); diff --git a/rootfs/boot/grub/grub.cfg b/rootfs/boot/grub/grub.cfg index e499f92..954a0e0 100644 --- a/rootfs/boot/grub/grub.cfg +++ b/rootfs/boot/grub/grub.cfg @@ -1,6 +1,6 @@ menuentry "Quark OS" { multiboot2 /apps/quark-kernel - module2 /apps/quark-testmod + module2 /apps/quark-testserver module2 /apps/quark-testmod module2 /apps/quark-testmod module2 /apps/quark-testmod diff --git a/src/Makefile.am b/src/Makefile.am index bdbd1e8..db5a2ae 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,5 +1,5 @@ noinst_PROGRAMS = quark-kernel -quark_kernel_SOURCES = kernel.c mmgr.c priorityqueue.c stdio.c string.c elf.c syscalls.c heap.c memmap.c avltree.c +quark_kernel_SOURCES = kernel.c mmgr.c priorityqueue.c stdio.c string.c elf.c syscalls.c heap.c memmap.c avltree.c queue.c quark_kernel_LDADD = -lgcc quark_kernel_CFLAGS = -I$(top_srcdir)/include -ffreestanding -mgeneral-regs-only -O0 -Wall -ggdb quark_kernel_LDFLAGS = -nostdlib @@ -14,7 +14,7 @@ quark_kernel_SOURCES += x86/paging.c \ x86/isr.c \ x86/msr.c \ x86/context.c \ - x86/contextswitch.S \ + x86/load_context.S \ x86/preempt.S \ x86/quark_x86.c \ x86/entry.S 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 9c510c2..f9ebb83 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."); @@ -38,6 +39,10 @@ void kernel_initialize(struct boot_info_t *boot_info) set_syscall(SYSCALL_TEST, 1, 0, test_syscall); set_syscall(SYSCALL_MMAP, 3, 0, mmap); set_syscall(SYSCALL_MUNMAP, 2, 0, munmap); + set_syscall(SYSCALL_SEND, 3, 0, send); + set_syscall(SYSCALL_RECEIVE, 2, 0, receive); + set_syscall(SYSCALL_OPEN_PORT, 1, 0, openport); + set_syscall(SYSCALL_CLOSE_PORT, 1, 0, closeport); for(int i = 0; i < boot_info->module_count; i++) { if(load_module(&boot_info->modules[i]) != S_OK) @@ -51,13 +56,8 @@ 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(NULL)); + load_context(next_process()); } int set_syscall(int id, int arg_count, int pid, void *func_ptr) @@ -89,7 +89,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 +111,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 +200,7 @@ int active_process() } else { - return kernel.active_process->resource_id; + return kernel.active_process->pid; } } @@ -210,28 +213,31 @@ 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); - queue_insert(&kernel.priority_queue, new_process, new_process->priority); + 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(struct process_context_t *prev_state) +struct process_context_t *next_process() { - if(prev_state != NULL) + if(kernel.active_process != NULL) { - kernel.active_process->state = prev_state; - queue_insert(&kernel.priority_queue, kernel.active_process, kernel.active_process->priority); + priorityqueue_insert(&kernel.priority_queue, kernel.active_process, kernel.active_process->priority); } - kernel.active_process = extract_min(&kernel.priority_queue); + kernel.active_process = priorityqueue_extract_min(&kernel.priority_queue); 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->pid, kernel.active_process->page_table, kernel.active_process->ctx); + return kernel.active_process->ctx; } panic("no processes available to enter!"); } @@ -248,62 +254,155 @@ int terminate_process(size_t process_id) kernel.active_process = NULL; } kernel.process_table = avl_remove(kernel.process_table, process_id); - queue_remove(&kernel.priority_queue, process); - destroy_context(process->state); + priorityqueue_remove(&kernel.priority_queue, process); + destroy_context(process->ctx); kfree(process); return S_OK; } -/* -int accept_message(size_t process_id, struct message_t *message) +int store_active_context(struct process_context_t *context, size_t size) { - if(message == NULL) + if(kernel.active_process != NULL && kernel.active_process->ctx != NULL) { - return S_NULL_POINTER; + memcpy(kernel.active_process->ctx, context, size); + return S_OK; } - else if(kernel->resource_table->limit >= process_id) + else { - return S_OUT_OF_BOUNDS; + return S_DOESNT_EXIST; } - else if(kernel->resource_table->array[process_id].type != RESOURCE_PROCESS) +} + +int open_port(unsigned long id) +{ + if(avl_get(kernel.port_table, id) != NULL) { - return S_INVALID_ARGUMENT; + return S_EXISTS; } - struct process_t *process = &kernel->resource_table->array[process_id].process; - process->state = PROCESS_WAITING; - process->message = message; - if(kernel->active_process == process) - { - kernel->active_process = NULL; - } - queue_remove(kernel->priority_queue, process); + printf("opening port %i -> %i\n", id, kernel.active_process->pid); + struct port_t *port = kmalloc(sizeof(struct port_t)); + port->id = id; + port->owner_pid = kernel.active_process->pid; + kernel.port_table = avl_insert(kernel.port_table, id, port); return S_OK; } -int send_message(size_t process_id, const struct message_t *message) +int close_port(unsigned long id) { - if(kernel == NULL || message == NULL) + struct port_t *port = avl_get(kernel.port_table, id); + if(port == NULL) { - return S_NULL_POINTER; + return S_DOESNT_EXIST; } - else if(kernel->resource_table->limit >= process_id) - { - return S_OUT_OF_BOUNDS; - } - else if(kernel->resource_table->array[process_id].type != RESOURCE_PROCESS) + else if(port->owner_pid != kernel.active_process->pid) { return S_INVALID_ARGUMENT; } - struct process_t *process = &kernel->resource_table->array[process_id].process; - if(process->state != PROCESS_WAITING || process->message == NULL) - { - return S_BUSY; - } - queue_insert(kernel->priority_queue, kernel->active_process); - struct message_t buffer = *message; - + printf("closing port %i attached to %i\n", id, kernel.active_process->pid); + kernel.port_table = 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) + { + printf("Invalid flags on send_message\n"); + 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 + { + printf("Port %i does not exist\n", recipient); + 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) + { + printf("Sending message directly from %i to %i\n", kernel.active_process->pid, dest->pid); + 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) + { + printf("Queueing message from %i to %i\n", kernel.active_process->pid, dest->pid); + 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 + { + 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; + 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) { diff --git a/src/priorityqueue.c b/src/priorityqueue.c index 5f62875..1396d0b 100644 --- a/src/priorityqueue.c +++ b/src/priorityqueue.c @@ -38,7 +38,7 @@ int construct_priority_queue(struct priority_queue_t *queue, int capacity) return S_OK; } -void *extract_min(struct priority_queue_t *queue) +void *priorityqueue_extract_min(struct priority_queue_t *queue) { if(queue->size == 0) return NULL; @@ -49,7 +49,7 @@ void *extract_min(struct priority_queue_t *queue) return value; } -int queue_insert(struct priority_queue_t *queue, void *value, int priority) +int priorityqueue_insert(struct priority_queue_t *queue, void *value, int priority) { if(queue->size == queue->capacity) return S_OUT_OF_MEMORY; @@ -65,7 +65,7 @@ int queue_insert(struct priority_queue_t *queue, void *value, int priority) return S_OK; } -int queue_remove(struct priority_queue_t *queue, void *value) +int priorityqueue_remove(struct priority_queue_t *queue, void *value) { for(size_t i = 0; i < queue->size; i++) { diff --git a/src/queue.c b/src/queue.c new file mode 100644 index 0000000..dc51873 --- /dev/null +++ b/src/queue.c @@ -0,0 +1,60 @@ +#include "queue.h" +#include "heap.h" + +struct queue_node_t +{ + /** + * @brief Pointer to the user-defined object this node refers to. + * + */ + void *ptr; + + /** + * @brief Link to the next node in the queue. + * + */ + struct queue_node_t *next; +}; + +void queue_construct(struct queue_t *queue) +{ + queue->first = NULL; + queue->last = NULL; + queue->count = 0; +} + +void queue_insert(struct queue_t *queue, void *ptr) +{ + struct queue_node_t *node = kmalloc(sizeof(struct queue_node_t)); + node->ptr = ptr; + node->next = NULL; + if(queue->last == NULL) + { + queue->first = queue->last = node; + } + else + { + queue->last->next = node; + queue->last = node; + } + queue->count++; +} + +void *queue_get_next(struct queue_t *queue) +{ + struct queue_node_t *node = queue->first; + queue->first = node->next; + if(queue->first == NULL) + { + queue->last = NULL; + } + queue->count--; + void *ptr = node->ptr; + kfree(node); + return ptr; +} + +void *queue_peek(struct queue_t *queue) +{ + return queue->first->ptr; +} \ No newline at end of file diff --git a/src/syscalls.c b/src/syscalls.c index 2ae8a10..eae5696 100644 --- a/src/syscalls.c +++ b/src/syscalls.c @@ -91,3 +91,23 @@ size_t terminate_self() { return terminate_process(active_process()); } + +size_t send(syscall_arg_t recipient, syscall_arg_t message, syscall_arg_t flags) +{ + return send_message(recipient.unsigned_int, message.ptr, flags.unsigned_int); +} + +size_t receive(syscall_arg_t buffer, syscall_arg_t flags) +{ + return receive_message(buffer.ptr, flags.unsigned_int); +} + +size_t openport(syscall_arg_t id) +{ + return open_port(id.unsigned_int); +} + +size_t closeport(syscall_arg_t id) +{ + return close_port(id.unsigned_int); +} diff --git a/src/x86/context.c b/src/x86/context.c index 2387392..0f37597 100644 --- a/src/x86/context.c +++ b/src/x86/context.c @@ -1,35 +1,65 @@ #include "platform/context.h" +#include "kernel.h" #include "mmgr.h" +#include "heap.h" #include "string.h" +#include "system.h" #include "x86/processstate.h" void *initialize_context(void *task_entry) { - /* - * TODO: this implementation is a goddamn mess. - * Stack pointer is hardcoded, and the stack isn't resizable. - * PCB pointer is just a constant. - */ - map_page(NULL, reserve_page(), PAGE_RW); - map_page((void*)0xFF3FF000, reserve_page(), PAGE_RW | PAGE_USERMODE); - unmap_page((void*)0xFF3FE000); - uint32_t flags; - asm("pushf; " - "mov (%%esp), %0; " - "popf; " - : "=r"(flags)); - struct process_context_t *state = (struct process_context_t*)PCB_LOCATION; - memset(NULL, 0, page_size); - state->cs = 0x1B; - state->eip = (uint32_t)task_entry; - state->flags = (flags & ~0xFD) | 0x200; - state->ss = 0x23; - state->esp = 0xFF400000; - state->ebp = 0xFF400000; - return (void*)state; + physaddr_t stack_frame = reserve_page(); + if(stack_frame % page_size != 0) + { + return NULL; + } + map_page((void*)&_kernel_start - page_size, stack_frame, PAGE_RW | PAGE_USERMODE); + unmap_page((void*)&_kernel_start - (2 * page_size)); + struct process_context_t *context = kmalloc(sizeof(struct process_context_t)); + if(context != NULL) + { + memset(context, 0, sizeof(struct process_context_t)); + uint32_t flags; + asm("pushf; " + "mov (%%esp), %0; " + "popf; " + : "=r"(flags)); + context->cs = 0x1B; + context->eip = (uint32_t)task_entry; + context->flags = (flags & ~0xFD) | 0x200; + context->ss = 0x23; + context->esp = &_kernel_start; + context->ebp = &_kernel_start; + } + return (void*)context; } void destroy_context(void *ctx) { - // Nothing to do... + kfree(ctx); +} + +void save_context(struct process_context_t *context) +{ + store_active_context(context, sizeof(*context)); +} + +void set_context_pc(struct process_context_t *context, void *pc) +{ + context->eip = pc; +} + +void set_context_stack(struct process_context_t *context, void *stack) +{ + context->esp = stack; +} + +void set_context_flags(struct process_context_t *context, unsigned long flags) +{ + context->flags = flags; +} + +void set_context_return(struct process_context_t *context, unsigned long value) +{ + context->eax = value; } \ No newline at end of file diff --git a/src/x86/contextswitch.S b/src/x86/contextswitch.S deleted file mode 100644 index 79c48ba..0000000 --- a/src/x86/contextswitch.S +++ /dev/null @@ -1,67 +0,0 @@ -.section .text - -/* - * save_context(struct process_state_t *context, struct interrupt_frame_t *frame) - */ - .global save_context - .type save_context, @function -save_context: - push %edi - push %esi - push %eax - mov $0x10, %ax - mov %ax, %ds - mov %ax, %es - mov %ax, %fs - mov %ax, %gs - mov 16(%esp), %eax - mov %ebx, 0x04(%eax) - mov %ecx, 0x08(%eax) - mov %edx, 0x0C(%eax) - mov %edi, 0x10(%eax) - mov %esi, 0x14(%eax) - mov %ebp, 0x18(%eax) - mov %eax, %edi - pop %eax - mov %eax, 0x00(%edi) - mov 16(%esp), %esi - mov 0x10(%esi), %eax - mov %eax, 0x1C(%edi) - mov 0x0C(%esi), %eax - mov %eax, 0x20(%edi) - mov 0x08(%esi), %eax - mov %eax, 0x2C(%edi) - mov 0x04(%esi), %eax - mov %eax, 0x24(%edi) - mov 0x00(%esi), %eax - mov %eax, 0x28(%edi) - pop %esi - pop %edi - ret - -/* - * load_context(struct process_state_t *context) - */ -.global load_context -.type load_context, @function -load_context: - mov 4(%esp), %eax - push 0x1C(%eax) - push 0x20(%eax) - push 0x2C(%eax) - push 0x24(%eax) - push 0x28(%eax) - push 0x00(%eax) - mov 0x04(%eax), %ebx - mov 0x08(%eax), %ecx - mov 0x0C(%eax), %edx - mov 0x10(%eax), %edi - mov 0x14(%eax), %esi - mov 0x18(%eax), %ebp - mov 0x1C(%eax), %ax - mov %ax, %ds - mov %ax, %es - mov %ax, %fs - mov %ax, %gs - pop %eax - iret \ No newline at end of file diff --git a/src/x86/load_context.S b/src/x86/load_context.S new file mode 100644 index 0000000..4550674 --- /dev/null +++ b/src/x86/load_context.S @@ -0,0 +1,28 @@ +.section .text + +/* + * load_context(struct process_state_t *context) + */ +.global load_context +.type load_context, @function +load_context: + mov 4(%esp), %eax + push 0x1C(%eax) + push 0x20(%eax) + push 0x2C(%eax) + push 0x24(%eax) + push 0x28(%eax) + push 0x00(%eax) + mov 0x04(%eax), %ebx + mov 0x08(%eax), %ecx + mov 0x0C(%eax), %edx + mov 0x10(%eax), %edi + mov 0x14(%eax), %esi + mov 0x18(%eax), %ebp + mov 0x1C(%eax), %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + pop %eax + iret \ No newline at end of file diff --git a/src/x86/preempt.S b/src/x86/preempt.S index ededc1c..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 @@ -25,14 +32,63 @@ isr_syscall: .global isr_preempt .type isr_preempt, @function isr_preempt: + + // Disable interrupts for now cli + + // Save process's base pointer + push %ebp + + // Save base pointer; it points to the interrupt stack frame + mov %esp, %ebp + add $4, %ebp + + // Save EAX on stack so it can be used as a buffer + push %eax + + // Load EFLAGS, then push it onto stack + mov 8(%ebp), %eax + push %eax + + // Load EIP, then push it onto stack + mov (%ebp), %eax + push %eax + + // Load CS, then push it onto stack + mov 4(%ebp), %eax + push %eax + + // Load ESP, then push it onto stack + mov 12(%ebp), %eax + push %eax + + // Load SS, then push it onto stack + mov 16(%ebp), %eax + push %eax + + // Load EBP, then push it onto stack + mov -4(%ebp), %eax + push %eax + + // Push GP registers onto stack + push %esi + push %edi + push %edx + push %ecx + push %ebx + + // Restore saved value of EAX, then push it onto stack + mov -8(%ebp), %eax + push %eax + + // Push pointer to the process context saved on the stack push %esp - push $0x800 + call save_context - add $8, %esp - push $0x800 + mov %ebp, %esp + call next_process - add $8, %esp + push %eax call load_context \ No newline at end of file