diff --git a/Makefile.am b/Makefile.am index ba92d35..0fcdcae 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = src +SUBDIRS = src include quark.iso: src/quark-kernel rootfs/boot/grub/grub.cfg mkdir -p rootfs/apps diff --git a/README.md b/README.md index 8ccfaed..e8288a2 100755 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ You will need: To build the kernel for the x86 platform, run: - `autoreconf -i` -- `./configure --host=i686-elf CFLAGS=-ffreestanding LDFLAGS=-nostdlib` +- `./configure --host=i686-elf --prefix= --bindir=$(prefix)/apps CFLAGS=-ffreestanding LDFLAGS=-nostdlib` - `make` To generate a bootable disk image, run: diff --git a/configure.ac b/configure.ac index 4cd90c7..92890ab 100644 --- a/configure.ac +++ b/configure.ac @@ -27,5 +27,5 @@ AC_TYPE_UINT8_T AM_CONDITIONAL([x86], [test $host = i686-elf]) -AC_CONFIG_FILES([Makefile src/Makefile]) +AC_CONFIG_FILES([Makefile src/Makefile include/Makefile]) AC_OUTPUT diff --git a/include/Makefile.am b/include/Makefile.am new file mode 100644 index 0000000..eb82e4f --- /dev/null +++ b/include/Makefile.am @@ -0,0 +1 @@ +nobase_include_HEADERS = types/status.h types/syscallid.h types/physaddr.h types/syscallarg.h \ No newline at end of file diff --git a/include/kernel.h b/include/kernel.h index 6908394..e2922ec 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; @@ -85,35 +101,41 @@ struct kernel_t void kernel_initialize(struct boot_info_t *boot_info); -enum error_t set_syscall(int id, int arg_count, int pid, void *func_ptr); +error_t 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, void *pc, void *stack, unsigned long flags); +size_t do_syscall(syscall_id_t id, syscall_arg_t arg1, syscall_arg_t arg2, syscall_arg_t arg3, void *pc, void *stack, unsigned long flags); -enum error_t kernel_load_module(struct module_t *module); +error_t kernel_load_module(struct module_t *module); unsigned long kernel_current_pid(); struct process_context_t *kernel_current_context(); -enum error_t kernel_store_active_context(struct process_context_t *context); +error_t kernel_store_active_context(struct process_context_t *context); unsigned long kernel_spawn_process(void *program_entry, int priority, physaddr_t address_space); struct process_context_t *kernel_advance_scheduler(); -enum error_t kernel_terminate_process(size_t process_id); +error_t kernel_terminate_process(size_t process_id); -enum error_t kernel_create_port(unsigned long id); +error_t kernel_create_port(unsigned long id); -enum error_t kernel_remove_port(unsigned long id); +error_t kernel_remove_port(unsigned long id); unsigned long kernel_get_port_owner(unsigned long id); -enum error_t kernel_send_message(unsigned long recipient, struct message_t *message); +error_t kernel_send_message(unsigned long recipient, struct message_t *message); -enum error_t kernel_queue_sender(unsigned long recipient); +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); +error_t kernel_register_interrupt_handler(unsigned long interrupt, signal_handler_t handler, void *userdata); + +error_t kernel_remove_interrupt_handler(unsigned long interrupt); + +error_t kernel_execute_interrupt_handler(unsigned long interrupt); + +error_t kernel_signal_return(); int receive_message(struct message_t *buffer, int flags); diff --git a/include/mmgr.h b/include/mmgr.h index 731afb9..8af38d8 100644 --- a/include/mmgr.h +++ b/include/mmgr.h @@ -3,6 +3,7 @@ #include "memmap.h" #include "platform/paging.h" #include "types/physaddr.h" +#include "types/status.h" #include extern const size_t page_size; @@ -71,7 +72,7 @@ void *page_map_end(); * @param block_size * @return enum error_t */ -enum error_t initialize_page_map(struct memory_map_t *map, void *base, size_t memory_size, unsigned long block_size); +error_t initialize_page_map(struct memory_map_t *map, void *base, size_t memory_size, unsigned long block_size); /** * @brief Create a new top-level page table and map the kernel in it. 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/include/queue.h b/include/queue.h index 6b8368a..7e77e15 100644 --- a/include/queue.h +++ b/include/queue.h @@ -43,7 +43,7 @@ void queue_construct(struct queue_t *queue); * @param ptr A pointer to some user-defined data to store on the queue. * @return enum error_t */ -enum error_t queue_insert(struct queue_t *queue, void *ptr); +error_t queue_insert(struct queue_t *queue, void *ptr); /** * @brief Removes the next item from the queue and returns it. diff --git a/include/syscalls.h b/include/syscalls.h index 7787fce..efd1e8b 100644 --- a/include/syscalls.h +++ b/include/syscalls.h @@ -1,15 +1,9 @@ #pragma once +#include "types/syscallarg.h" #include #include -typedef union -{ - long signed_int; - unsigned long unsigned_int; - void *ptr; -} syscall_arg_t; - typedef size_t (*syscall_ptr_0_t)(); typedef size_t (*syscall_ptr_1_t)(syscall_arg_t); diff --git a/include/types/physaddr.h b/include/types/physaddr.h index 6631873..3e12471 100644 --- a/include/types/physaddr.h +++ b/include/types/physaddr.h @@ -1,14 +1,6 @@ #ifndef _QUARK_PHYSADDR_H #define _QUARK_PHYSADDR_H -#include - -#if defined __i386__ || __arm__ -typedef uint32_t physaddr_t; -#elif defined __x86_64__ || __aarch64__ -typedef uint64_t physaddr_t; -#else -typedef uint64_t physaddr_t; -#endif +typedef unsigned long int physaddr_t; #endif \ No newline at end of file diff --git a/include/types/status.h b/include/types/status.h index 60eec73..ed04ac2 100644 --- a/include/types/status.h +++ b/include/types/status.h @@ -1,7 +1,7 @@ #ifndef _QUARK_ERROR_H #define _QUARK_ERROR_H -enum error_t +typedef enum { ENONE = 0, ENULLPTR, @@ -15,6 +15,6 @@ enum error_t EPERM, EBUSY, EEXITED -}; +} error_t; #endif \ No newline at end of file diff --git a/include/types/syscallarg.h b/include/types/syscallarg.h new file mode 100644 index 0000000..b1a49c8 --- /dev/null +++ b/include/types/syscallarg.h @@ -0,0 +1,11 @@ +#ifndef _QUARK_SYSCALLARG_H +#define _QUARK_SYSCALLARG_H + +typedef union +{ + long int signed_int; + unsigned long int unsigned_int; + void *ptr; +} syscall_arg_t; + +#endif \ No newline at end of file diff --git a/include/types/syscallid.h b/include/types/syscallid.h index fe95a5b..b04b0e3 100644 --- a/include/types/syscallid.h +++ b/include/types/syscallid.h @@ -1,7 +1,7 @@ #ifndef QUARK_SYSCALLID_H #define QUARK_SYSCALLID_H -enum syscall_id_t +typedef enum { SYSCALL_TEST = 1, SYSCALL_MMAP, @@ -12,6 +12,6 @@ enum syscall_id_t SYSCALL_RECEIVE, SYSCALL_OPEN_PORT, SYSCALL_CLOSE_PORT -}; +} syscall_id_t; #endif \ No newline at end of file diff --git a/include/x86/idt.h b/include/x86/idt.h index 3b78343..0e018dc 100644 --- a/include/x86/idt.h +++ b/include/x86/idt.h @@ -32,11 +32,11 @@ enum interrupt_code_t enum isr_type_t { - INTERRPUT_TASK32 = 5, - INTERRPUT_TRAP32 = 15, - INTERRPUT_INT32 = 14, - INTERRPUT_TRAP16 = 7, - INTERRPUT_INT16 = 6 + INTERRUPT_TASK32 = 5, + INTERRUPT_TRAP32 = 15, + INTERRUPT_INT32 = 14, + INTERRUPT_TRAP16 = 7, + INTERRUPT_INT16 = 6 }; void initialize_gdt(); diff --git a/src/Makefile.am b/src/Makefile.am index 9bd5478..5954e6f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -noinst_PROGRAMS = quark-kernel +bin_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 queue.c math.c quark_kernel_LDADD = -lgcc quark_kernel_CFLAGS = -I$(top_srcdir)/include -ffreestanding -mgeneral-regs-only -O0 -Wall -ggdb diff --git a/src/avltree.c b/src/avltree.c index 41ae7c9..8902d54 100644 --- a/src/avltree.c +++ b/src/avltree.c @@ -179,20 +179,20 @@ struct avltree_t *avl_remove(struct avltree_t *tree, int key) void *avl_get(struct avltree_t *tree, int key) { - if(tree == NULL) + while(tree != NULL) { - return NULL; - } - else if(key < tree->key) - { - return avl_get(tree->left, key); - } - else if(key > tree->key) - { - return avl_get(tree->right, key); - } - else - { - return tree->value; + if(key < tree->key) + { + tree = tree->left; + } + else if(key > tree->key) + { + tree = tree->right; + } + else + { + return tree->value; + } } + return NULL; } \ No newline at end of file diff --git a/src/heap.c b/src/heap.c index 488fa5a..e194a60 100644 --- a/src/heap.c +++ b/src/heap.c @@ -19,9 +19,9 @@ struct heap_t struct heap_node_t { - size_t height : 5; size_t mapped : 1; size_t state : 2; + size_t height : 5; } __attribute__ ((packed)); size_t find_free_block(struct heap_t *heap, size_t height) diff --git a/src/kernel.c b/src/kernel.c index dad6537..f778a08 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -17,18 +17,19 @@ struct kernel_t kernel; 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_map(&boot_info->map, (physaddr_t*)&_kernel_end, boot_info->memory_size, page_size); - kminit(&_kernel_start, page_map_end(), 0xFFC00000 - (size_t)&_kernel_start, 64); initialize_screen(); printf("***%s***\n", PACKAGE_STRING); printf("Total memory: %08x\n", boot_info->memory_size); + printf("kernel: %08x ... %08x\n", &_kernel_pstart, &_kernel_pend); printf("Type\t\tLocation\t\tSize\n"); for (size_t i = 0; i < boot_info->map.size && boot_info->map.array[i].size > 0; i++) { printf("%i\t\t\t%08x\t\t%u\n", boot_info->map.array[i].type, boot_info->map.array[i].location, boot_info->map.array[i].size); } + insert_region(&boot_info->map, (physaddr_t)&_kernel_pstart, (physaddr_t)&_kernel_pend - (physaddr_t)&_kernel_pstart, M_UNAVAILABLE); + initialize_page_map(&boot_info->map, (physaddr_t*)&_kernel_end, boot_info->memory_size, page_size); + kminit(&_kernel_start, page_map_end(), 0xFFC00000 - (size_t)&_kernel_start, 64); kernel.active_process = NULL; kernel.next_pid = 1; kernel.process_table = NULL; @@ -62,7 +63,7 @@ void kernel_initialize(struct boot_info_t *boot_info) load_context(kernel_advance_scheduler()); } -enum error_t set_syscall(int id, int arg_count, int pid, void *func_ptr) +error_t set_syscall(int id, int arg_count, int pid, void *func_ptr) { if(id < 0 || id > MAX_SYSCALL_ID) { @@ -91,7 +92,7 @@ enum error_t set_syscall(int id, int arg_count, int pid, void *func_ptr) return ENONE; } -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) +size_t do_syscall(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) { @@ -139,7 +140,7 @@ size_t do_syscall(enum syscall_id_t id, syscall_arg_t arg1, syscall_arg_t arg2, return result; } -enum error_t kernel_load_module(struct module_t *module) +error_t kernel_load_module(struct module_t *module) { physaddr_t module_address_space = create_address_space(); if(module_address_space == ENOMEM) { @@ -264,13 +265,13 @@ struct process_context_t *kernel_advance_scheduler() if(kernel.active_process != NULL) { paging_load_address_space(kernel.active_process->page_table); - printf("entering process %08x cr3=%08x ctx=%08x.\n", kernel.active_process->pid, kernel.active_process->page_table, kernel.active_process->ctx); + printf("entering process %08x cr3=%08x ctx=%08x sched=%i.\n", kernel.active_process->pid, kernel.active_process->page_table, kernel.active_process->ctx, kernel.priority_queue.size); return kernel.active_process->ctx; } panic("no processes available to enter!"); } -enum error_t kernel_terminate_process(size_t process_id) +error_t kernel_terminate_process(size_t process_id) { struct process_t *process = avl_get(kernel.process_table, process_id); if(process == NULL) @@ -298,7 +299,7 @@ enum error_t kernel_terminate_process(size_t process_id) return ENONE; } -enum error_t kernel_store_active_context(struct process_context_t *context) +error_t kernel_store_active_context(struct process_context_t *context) { if(kernel.active_process != NULL && kernel.active_process->ctx != NULL) { @@ -311,7 +312,7 @@ enum error_t kernel_store_active_context(struct process_context_t *context) } } -enum error_t kernel_create_port(unsigned long id) +error_t kernel_create_port(unsigned long id) { if(avl_get(kernel.port_table, id) != NULL) { @@ -325,7 +326,7 @@ enum error_t kernel_create_port(unsigned long id) return ENONE; } -enum error_t kernel_remove_port(unsigned long id) +error_t kernel_remove_port(unsigned long id) { struct port_t *port = avl_get(kernel.port_table, id); if(port == NULL) @@ -355,14 +356,14 @@ unsigned long kernel_get_port_owner(unsigned long id) } } -enum error_t kernel_send_message(unsigned long recipient, struct message_t *message) +error_t kernel_send_message(unsigned long recipient, struct message_t *message) { struct process_t *dest = avl_get(kernel.process_table, recipient); if(dest == NULL) { 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,24 +384,7 @@ 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) +error_t kernel_queue_message(unsigned long recipient, struct message_t *message) { struct process_t *dest = avl_get(kernel.process_table, recipient); if(dest != NULL) @@ -423,21 +407,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 +427,80 @@ int receive_message(struct message_t *buffer, int flags) } } +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; +} + +error_t kernel_remove_interrupt_handler(unsigned long interrupt) +{ + struct signal_action_t *action = avl_get(kernel.interrupt_handlers, interrupt); + if(action == NULL) + { + return EDOESNTEXIST; + } + kfree(action); + kernel.interrupt_handlers = avl_remove(kernel.interrupt_handlers, interrupt); + return ENONE; +} + +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; +} + +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/mmgr.c b/src/mmgr.c index 0caede0..c23c2e5 100644 --- a/src/mmgr.c +++ b/src/mmgr.c @@ -3,142 +3,152 @@ #include "math.h" #include "platform/paging.h" #include "types/status.h" +#include "stdio.h" #include #include -/** - * @brief Describes a stack containing the physical addresses of available page - * frames. - * - */ -struct page_stack_t -{ - - /** - * @brief The total number of physical pages managed by the system. - * - */ - unsigned long total_pages; - - /** - * @brief Points to the topmost physical address on the stack. - * - */ - physaddr_t *stack_pointer; - - /** - * @brief Points to the bottom of the stack. - * - */ - physaddr_t *base_pointer; - - /** - * @brief Points to the limit of the stack. The stack cannot grow beyond - * this point. - * - */ - physaddr_t *limit_pointer; - -} page_stack; +#define MAX_CACHE_SIZE 32 struct page_map_t { /** * @brief The underlying bitmap representing the availability of chunks of * physical memory. - * + * */ unsigned long *bitmap; /** - * @brief The size of the bitmap in bytes. + * @brief Stores a list of available blocks of memory to speed up allocation. * */ + unsigned long *cache; + + /** + * @brief The size of the bitmap in bytes. + * + */ unsigned long bitmap_size; /** * @brief The size in bytes of the smallest unit of allocation. - * + * * This value should either be the size of a page on the host system, or * possibly some number of pages. - * + * */ unsigned long block_size; /** - * @brief - * + * @brief + * */ unsigned long height; /** - * @brief The number of available blocks of memory. - * - * Due to memory fragmentation, it may not be possible to allocate all + * @brief The number of available blocks of memory. + * + * Due to memory fragmentation, it may not be possible to allocate all * available memory at once. - * + * */ unsigned long free_block_count; } page_map; -const int bitmap_word_size = 8 * sizeof(*page_map.bitmap); +static const int bitmap_word_size = 8 * sizeof(*page_map.bitmap); + +static void clear_cache() +{ + for(int i = 0; i < MAX_CACHE_SIZE; i++) + { + page_map.cache[i] = 0; + } +} + +static void clear_bitmap() +{ + for(int i = 0; i < page_map.bitmap_size / sizeof(*page_map.bitmap); i++) + { + page_map.bitmap[i] = 0; + } +} int split_block(int index) { - if(index) + if (index) { - int bitmap_index = index / bitmap_word_size; - int bitmap_offset = index % bitmap_word_size; - page_map.bitmap[bitmap_index] &= ~(1 << bitmap_offset); + unsigned long bitmap_index = index / bitmap_word_size; + unsigned long bitmap_offset = index % bitmap_word_size; + page_map.bitmap[bitmap_index] &= ~((unsigned long)1 << bitmap_offset); index *= 2; bitmap_index = index / bitmap_word_size; - bitmap_offset = index / bitmap_word_size; - page_map.bitmap[bitmap_index] |= 1 << bitmap_offset; - page_map.bitmap[bitmap_index] |= 1 << (bitmap_offset ^ 1); + bitmap_offset = index % bitmap_word_size; + page_map.bitmap[bitmap_index] |= (unsigned long)1 << bitmap_offset; + page_map.bitmap[bitmap_index] |= (unsigned long)1 << (bitmap_offset ^ 1); + unsigned long depth = llog2(index + 1) - 1; + unsigned long cache_start = llog2(bitmap_word_size); + if(depth >= cache_start && page_map.cache[depth - cache_start] == 0) + { + page_map.cache[depth - cache_start] = index + 1; + } } return index; } int find_free_region(int height) { - if(height > page_map.height || height < 0) + if (height > page_map.height || height < 0) { return 0; } - else if(height <= page_map.height - ilog2(bitmap_word_size)) + else if (height <= page_map.height - ilog2(bitmap_word_size)) { - for(int index = (1 << (page_map.height - height)) / bitmap_word_size; - index < (1 << (page_map.height - height + 1)) / bitmap_word_size; - index++) + if(page_map.cache[page_map.height - height - llog2(bitmap_word_size)]) { - if(page_map.bitmap[index] != 0) + unsigned long index = page_map.cache[page_map.height - height - llog2(bitmap_word_size)]; + page_map.cache[page_map.height - height - llog2(bitmap_word_size)] = 0; + return index; + } + unsigned long start = (1 << (page_map.height - height)) / bitmap_word_size; + unsigned long end = ((1 << (page_map.height - height + 1)) / bitmap_word_size); + for (int index = start; index < end; index++) + { + if (page_map.bitmap[index] != 0) { - return bitmap_word_size * index + __builtin_ctz(page_map.bitmap[index]); + return bitmap_word_size * index + __builtin_ctzl(page_map.bitmap[index]); } } } else { - static const int bitmasks[] = {0x00000002, 0x0000000C, 0x000000F0, 0x0000FF00, 0xFFFF0000}; +#if __SIZEOF_LONG__ == 8 + static const unsigned long bitmasks[] = {0x00000002, 0x0000000C, 0x000000F0, 0x0000FF00, 0xFFFF0000, 0xFFFFFFFF00000000}; +#else + static const unsigned long bitmasks[] = {0x00000002, 0x0000000C, 0x000000F0, 0x0000FF00, 0xFFFF0000}; +#endif int depth = page_map.height - height; - if(page_map.bitmap[0] & bitmasks[depth]) + if (page_map.bitmap[0] & bitmasks[depth]) { - return __builtin_ctz(page_map.bitmap[0] & bitmasks[depth]); + return __builtin_ctzl(page_map.bitmap[0] & bitmasks[depth]); } } return split_block(find_free_region(height + 1)); } + physaddr_t reserve_region(size_t size) { int height = llog2(size / page_map.block_size); int index = find_free_region(height); - if(index) + if (index) { int bitmap_index = index / bitmap_word_size; int bitmap_offset = index % bitmap_word_size; - page_map.bitmap[bitmap_index] &= ~(1 << bitmap_offset); - return (page_map.block_size << height) * (index - (1 << (page_map.height - height))); + page_map.bitmap[bitmap_index] &= ~((unsigned long)1 << bitmap_offset); + physaddr_t page = (page_map.block_size << height) * (index - ((unsigned long)1 << (page_map.height - height))); + if(page < 0x10000) + ;//printf("Reserved %08x\n", page); + return page; } else { @@ -149,18 +159,29 @@ physaddr_t reserve_region(size_t size) int free_region(physaddr_t location, size_t size) { int height = llog2(size / page_map.block_size); - int index = (location / (page_map.block_size * (1 << height))) + (1 << (page_map.height - height)); + int index = (location / (page_map.block_size * ((unsigned long)1 << height))) + (1 << (page_map.height - height)); int bitmap_index = index / bitmap_word_size; int bitmap_offset = index % bitmap_word_size; - page_map.bitmap[bitmap_index] |= 1 << bitmap_offset; - while(page_map.bitmap[bitmap_index] & (1 << (bitmap_offset ^ 1))) + page_map.bitmap[bitmap_index] |= (unsigned long)1 << bitmap_offset; + unsigned long cache_start = llog2(bitmap_word_size); + while (page_map.bitmap[bitmap_index] & ((unsigned long)1 << (bitmap_offset ^ 1))) { - page_map.bitmap[bitmap_index] &= ~(1 << bitmap_offset); - page_map.bitmap[bitmap_index] &= ~(1 << (bitmap_offset ^ 1)); + unsigned long depth = llog2(index + 1) - 1; + if(page_map.cache[depth - cache_start] == (index ^ 1)) + { + page_map.cache[depth - cache_start] = 0; + } + page_map.bitmap[bitmap_index] &= ~((unsigned long)1 << bitmap_offset); + page_map.bitmap[bitmap_index] &= ~((unsigned long)1 << (bitmap_offset ^ 1)); index /= 2; bitmap_index = index / bitmap_word_size; bitmap_offset = index % bitmap_word_size; - page_map.bitmap[bitmap_index] |= 1 << bitmap_offset; + page_map.bitmap[bitmap_index] |= (unsigned long)1 << bitmap_offset; + } + unsigned long depth = llog2(index + 1) - 1; + if (depth >= cache_start && page_map.cache[depth - cache_start] == 0) + { + page_map.cache[depth - cache_start] = index; } return ENONE; } @@ -190,17 +211,21 @@ void *page_map_end() return (void*)page_map.bitmap + page_map.bitmap_size; } -enum error_t initialize_page_map(struct memory_map_t *map, void *base, size_t memory_size, unsigned long block_size) +error_t initialize_page_map(struct memory_map_t *map, void *base, size_t memory_size, unsigned long block_size) { + static unsigned long page_map_cache[MAX_CACHE_SIZE]; // Round memory_size up to nearest power of 2 memory_size = 1 << llog2(memory_size); page_map.bitmap = (unsigned long*) base; + page_map.cache = page_map_cache; page_map.bitmap_size = (memory_size / page_size) / 4; page_map.block_size = block_size; page_map.height = llog2(memory_size / block_size); page_map.free_block_count = 0; int block_log = llog2(block_size); int pages_mapped = 0; + bool initialized = false; + printf("bmpsz: %08x bmploc: %08x\n", page_map.bitmap_size, page_map.bitmap); for(int i = 0; i < map->size; i++) { if(map->array[i].type != M_AVAILABLE) @@ -209,61 +234,84 @@ enum error_t initialize_page_map(struct memory_map_t *map, void *base, size_t me } physaddr_t location = (map->array[i].location + page_size - 1) & ~(page_size - 1); physaddr_t region_end = map->array[i].location + map->array[i].size; - while(location + block_size <= region_end) + while(location + block_size <= region_end && pages_mapped < (page_map.bitmap_size + page_size - 1) / page_size) { - if(pages_mapped < page_map.bitmap_size / page_size) + void *page = (void*)page_map.bitmap + pages_mapped * page_size; + for(int level = 0; level < page_table_levels; level++) { - void *page = (void*)page_map.bitmap + pages_mapped * page_size; - for(int level = 0; level < page_table_levels; level++) + if(!(get_pte_type(page, level) & PAGE_PRESENT)) { - if(!(get_pte_type(page, level) & PAGE_PRESENT)) + if(set_pte(page, level, PAGE_PRESENT | PAGE_RW, location)) { - if(set_pte(page, level, PAGE_PRESENT | PAGE_RW, location)) - { - return ENOMEM; - } - else if(level == page_table_levels - 1) - { - pages_mapped++; - } - break; + return ENOMEM; } else if(level == page_table_levels - 1) { pages_mapped++; } + break; + } + else if(level == page_table_levels - 1) + { + pages_mapped++; } - location += page_size; - continue; } + location += page_size; + continue; + } + + if(!initialized) + { + clear_bitmap(); + initialized = true; + } + + while(location + block_size <= region_end) + { int bit_offset = (location / block_size) % bitmap_word_size; - int bitmap_index = (location / block_size) / bitmap_word_size; + int bitmap_index = ((1 << (page_map.height - 0)) / bitmap_word_size) + (location / block_size) / bitmap_word_size; size_t chunk_size = (bitmap_word_size - bit_offset) * block_size; + // BUG: bitmap entries are uninitialized at first, never zeroed out + if(location < 0x180000) + printf("%08x ", page_map.bitmap[bitmap_index]); if(bit_offset == 0 && (region_end - location) >= chunk_size) { + if(location < 0x180000) + printf("a "); // Set all bits in the word page_map.bitmap[bitmap_index] = ~0; } else if(bit_offset == 0) { + if(location < 0x180000) + printf("b "); // Set the first 'count' bits int count = (region_end - location) >> block_log; page_map.bitmap[bitmap_index] |= (1 << count) - 1; } else if((region_end - location) >= chunk_size) { + if(location < 0x180000) + printf("c "); // Set all bits starting at 'bit_offset' page_map.bitmap[bitmap_index] |= ~((1 << bit_offset) - 1); } else { + if(location < 0x180000) + printf("d "); // Set all bits starting at 'bit_offset' up to 'count' int count = (region_end - location) >> block_log; page_map.bitmap[bitmap_index] |= ((1 << count) - 1) & ~((1 << bit_offset) - 1); } + if(location < 0x180000) { + printf("bmp: %08x loc: %08x end: %08x off: %i idx: %i cnt: %i\n", page_map.bitmap[bitmap_index], location, region_end, bit_offset, bitmap_index, (region_end - location) >> block_log); + } + location += chunk_size; } } + clear_cache(); return ENONE; } diff --git a/src/queue.c b/src/queue.c index 492f257..6cbefb7 100644 --- a/src/queue.c +++ b/src/queue.c @@ -23,7 +23,7 @@ void queue_construct(struct queue_t *queue) queue->count = 0; } -enum error_t queue_insert(struct queue_t *queue, void *ptr) +error_t queue_insert(struct queue_t *queue, void *ptr) { struct queue_node_t *node = kmalloc(sizeof(struct queue_node_t)); if(node == NULL) diff --git a/src/stdio.c b/src/stdio.c index a487e3a..54a9f8c 100644 --- a/src/stdio.c +++ b/src/stdio.c @@ -27,6 +27,7 @@ char *itoa(unsigned int n, unsigned int base, unsigned int width) static const char *digits = "0123456789abcdef"; static char buffer[65]; char *s = &buffer[64]; + *s = 0; unsigned int count = 0; do { diff --git a/src/syscalls.c b/src/syscalls.c index c36954c..297e871 100644 --- a/src/syscalls.c +++ b/src/syscalls.c @@ -110,20 +110,8 @@ size_t send(syscall_arg_t recipient, syscall_arg_t message, syscall_arg_t flags) return EDOESNTEXIST; } } - 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) + error_t status = kernel_send_message(recipient.unsigned_int, message.ptr); + 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 diff --git a/src/x86/idt.c b/src/x86/idt.c index 6b9d1be..1bf0c51 100644 --- a/src/x86/idt.c +++ b/src/x86/idt.c @@ -125,7 +125,7 @@ void load_tr(uint16_t gdt_offset) void create_interrupt_descriptor(struct interrupt_descriptor_t *descriptor, void *isr, enum isr_type_t type, uint32_t privilage, uint32_t selector) { - if(type != INTERRPUT_TASK32) + if(type != INTERRUPT_TASK32) { descriptor->offset_1 = (uint32_t) isr & 0xFFFF; descriptor->offset_2 = (uint32_t) isr >> 16; @@ -245,15 +245,15 @@ void initialize_idt() memset(idt, 0, sizeof(struct interrupt_descriptor_t) * idt_size); for(int i = 0; i < idt_size; i++) { - create_interrupt_descriptor(&idt[i], (void*)isr_generic, INTERRPUT_INT32, 0, 8); + create_interrupt_descriptor(&idt[i], (void*)isr_generic, INTERRUPT_INT32, 0, 8); } - create_interrupt_descriptor(&idt[EXCEPTION_DIV_BY_0], (void*)isr_division_by_zero, INTERRPUT_INT32, 0, 8); - create_interrupt_descriptor(&idt[EXCEPTION_SEGMENT_NOT_PRESENT], (void*)isr_segment_not_present, INTERRPUT_TRAP32, 0, 8); - create_interrupt_descriptor(&idt[EXCEPTION_GPF], (void*)isr_gp_fault, INTERRPUT_TRAP32, 0, 8); - create_interrupt_descriptor(&idt[EXCEPTION_PAGE_FAULT], (void*)isr_page_fault, INTERRPUT_TRAP32, 0, 8); - create_interrupt_descriptor(&idt[EXCEPTION_DOUBLE_FAULT], /*(void*)isr_double_fault*/NULL, INTERRPUT_TASK32, 0, 8 * 6); - create_interrupt_descriptor(&idt[ISR_PREEMPT], (void*)isr_preempt, INTERRPUT_INT32, 3, 8); - create_interrupt_descriptor(&idt[ISR_APIC_TIMER], (void*)isr_timer, INTERRPUT_INT32, 0, 8); - create_interrupt_descriptor(&idt[ISR_SYSCALL], (void*)isr_syscall, INTERRPUT_INT32, 3, 8); + create_interrupt_descriptor(&idt[EXCEPTION_DIV_BY_0], (void*)isr_division_by_zero, INTERRUPT_INT32, 0, 8); + create_interrupt_descriptor(&idt[EXCEPTION_SEGMENT_NOT_PRESENT], (void*)isr_segment_not_present, INTERRUPT_TRAP32, 0, 8); + create_interrupt_descriptor(&idt[EXCEPTION_GPF], (void*)isr_gp_fault, INTERRUPT_TRAP32, 0, 8); + create_interrupt_descriptor(&idt[EXCEPTION_PAGE_FAULT], (void*)isr_page_fault, INTERRUPT_TRAP32, 0, 8); + create_interrupt_descriptor(&idt[EXCEPTION_DOUBLE_FAULT], /*(void*)isr_double_fault*/NULL, INTERRUPT_TASK32, 0, 8 * 6); + create_interrupt_descriptor(&idt[ISR_PREEMPT], (void*)isr_preempt, INTERRUPT_INT32, 3, 8); + create_interrupt_descriptor(&idt[ISR_APIC_TIMER], (void*)isr_timer, INTERRUPT_INT32, 0, 8); + create_interrupt_descriptor(&idt[ISR_SYSCALL], (void*)isr_syscall, INTERRUPT_INT32, 3, 8); load_idt(idt); } diff --git a/src/x86/multiboot2.c b/src/x86/multiboot2.c index ed13e55..44aba57 100644 --- a/src/x86/multiboot2.c +++ b/src/x86/multiboot2.c @@ -107,9 +107,12 @@ void *read_multiboot_table_entry(struct boot_info_t *boot_info, void *table) boot_info->modules[boot_info->module_count].start = ((struct multiboot2_module_t*) table)->start; boot_info->modules[boot_info->module_count].end = ((struct multiboot2_module_t*) table)->end; strcpy(boot_info->modules[boot_info->module_count].str, &((struct multiboot2_module_t*) table)->str); + unsigned long size = ((struct multiboot2_module_t*) table)->end - ((struct multiboot2_module_t*) table)->start; + size += 4095; + size &= ~4095; insert_region(&boot_info->map, ((struct multiboot2_module_t*) table)->start, - ((struct multiboot2_module_t*) table)->end - ((struct multiboot2_module_t*) table)->start, + size, M_UNAVAILABLE); boot_info->module_count++; } diff --git a/src/x86/paging.c b/src/x86/paging.c index 4d4cdb5..630d89e 100644 --- a/src/x86/paging.c +++ b/src/x86/paging.c @@ -2,6 +2,7 @@ #include "string.h" #include +#include struct page_table_entry_t {