From aba6ed4b91aff5d914be11704e34de75bfd4d003 Mon Sep 17 00:00:00 2001 From: Alexis211 Date: Fri, 10 Sep 2010 18:46:00 +0200 Subject: Each thread has its own stack. Added simple unit tests for kmalloc,kfree Found a bug in heap_contract (not sure) but didn't fix it. --- Makefile | 6 +++++- doc/syscalls.txt | 1 + gdb-cmd | 2 ++ menu_fdd.cfg | 2 ++ src/include/gc/syscall.h | 2 ++ src/kernel/Makefile | 2 +- src/kernel/core/kmain.c | 3 +++ src/kernel/core/monitor.h | 3 ++- src/kernel/core/sys.c | 2 +- src/kernel/core/test.c | 31 +++++++++++++++++++++++++++++++ src/kernel/core/test.h | 6 ++++++ src/kernel/lib/stdlib.h | 3 +++ src/kernel/linker/elf.c | 2 +- src/kernel/mem/heap.c | 26 ++++++++++++++++++-------- src/kernel/mem/mem.c | 2 +- src/kernel/mem/paging.c | 15 ++++++++------- src/kernel/task/idt.c | 8 +++----- src/kernel/task/syscall.c | 2 +- src/kernel/task/task.c | 29 ++++++++++++++++------------- src/kernel/task/task.h | 5 ++--- src/library/gc/syscall.c | 19 ++++++++++++++++++- src/modules/test/main.c | 9 +++++++++ 22 files changed, 136 insertions(+), 44 deletions(-) create mode 100644 gdb-cmd create mode 100644 src/kernel/core/test.c create mode 100644 src/kernel/core/test.h diff --git a/Makefile b/Makefile index 6a014ec..192c867 100644 --- a/Makefile +++ b/Makefile @@ -44,4 +44,8 @@ bochs: all floppy bochs -f bochs.cfg qemu: all floppy - qemu -fda $(Floppy) -m 8 + qemu -fda $(Floppy) -m 16 + +qemu-gdb: all floppy + qemu -fda $(Floppy) -m 16 -s -S & gdb src/kernel/kernel.elf -x gdb-cmd + diff --git a/doc/syscalls.txt b/doc/syscalls.txt index 67b4b3c..8053b38 100644 --- a/doc/syscalls.txt +++ b/doc/syscalls.txt @@ -11,6 +11,7 @@ id=eax Name Parameters Description 4 printk ebx: addr of a string Print a message to screen 5 thread_new ebx: entry point Creates a new thread ecx: data pointer + edx: stack pointer 6 irq_wait ebx: irq number Waits for an IRQ (requires privilege PL_DRIVER) 7 proc_priv none Returns current process privilege level 8 shm_create ebx: offset Create a shared memory segment at offset (ret = errcode) diff --git a/gdb-cmd b/gdb-cmd new file mode 100644 index 0000000..4c32a6e --- /dev/null +++ b/gdb-cmd @@ -0,0 +1,2 @@ +target remote localhost:1234 +break core/sys.c:panic_do diff --git a/menu_fdd.cfg b/menu_fdd.cfg index 1d3504c..551c1e8 100644 --- a/menu_fdd.cfg +++ b/menu_fdd.cfg @@ -1,3 +1,5 @@ +timeout 1 + title Grapes kernel /kernel.elf module /manager.elf diff --git a/src/include/gc/syscall.h b/src/include/gc/syscall.h index 9ac6748..e6005c1 100644 --- a/src/include/gc/syscall.h +++ b/src/include/gc/syscall.h @@ -25,6 +25,8 @@ struct user_sendrequest { int errcode; }; +#define NEW_STACK_SIZE 0x8000 + void thread_exit(); void schedule(); void thread_sleep(int time); diff --git a/src/kernel/Makefile b/src/kernel/Makefile index e807fc0..757349f 100644 --- a/src/kernel/Makefile +++ b/src/kernel/Makefile @@ -1,5 +1,5 @@ Out = kernel.elf -Obj = core/loader_.o core/kmain.o core/sys.o \ +Obj = core/loader_.o core/kmain.o core/sys.o core/test.o \ core/monitor.o task/timer.o \ task/idt.o task/idt_.o task/task.o task/task_.o task/syscall.o task/sched.o \ lib/stdlib.o lib/bitset.o lib/mutex.o \ diff --git a/src/kernel/core/kmain.c b/src/kernel/core/kmain.c index 65a39e6..6c9700e 100644 --- a/src/kernel/core/kmain.c +++ b/src/kernel/core/kmain.c @@ -2,6 +2,7 @@ #include "multiboot.h" #include "monitor.h" #include "sys.h" +#include "test.h" #include #include #include @@ -63,6 +64,8 @@ void kmain(struct multiboot_info_t* mbd, int32_t magic) { } } + test_run(); + monitor_write("Modules now RULE THE WORLD !\n"); sti(); tasking_switch(); diff --git a/src/kernel/core/monitor.h b/src/kernel/core/monitor.h index c04632e..bb8e16e 100644 --- a/src/kernel/core/monitor.h +++ b/src/kernel/core/monitor.h @@ -10,11 +10,12 @@ void monitor_writeHex(uint32_t v); void monitor_writeDec(uint32_t v); #define NL monitor_put('\n'); +#define TAB monitor_put('\t'); #define WHERE { monitor_write("(kernel:"); \ monitor_write(__FILE__); \ monitor_write(":"); \ monitor_writeDec(__LINE__); \ - monitor_write(") "); } + monitor_write(")\t"); } #endif diff --git a/src/kernel/core/sys.c b/src/kernel/core/sys.c index 56de038..05a7bc5 100644 --- a/src/kernel/core/sys.c +++ b/src/kernel/core/sys.c @@ -28,7 +28,7 @@ uint16_t inw(uint16_t port) { void stack_trace(size_t bp) { uint32_t *stack = (uint32_t*)bp, i; for (i = 0; i < 5 && stack > 0xE0000000 && stack < (bp + 0x8000); i++) { - monitor_write(" "); monitor_writeHex(stack); + monitor_write("| "); monitor_writeHex(stack); monitor_write("\tnext:"); monitor_writeHex(stack[0]); monitor_write("\t\tret:"); monitor_writeHex(stack[1]); monitor_write("\n"); stack = (uint32_t*)stack[0]; diff --git a/src/kernel/core/test.c b/src/kernel/core/test.c new file mode 100644 index 0000000..77c7029 --- /dev/null +++ b/src/kernel/core/test.c @@ -0,0 +1,31 @@ +#include "test.h" +#include "monitor.h" +#include +#include "sys.h" + +#define TEST_KMALLOC(var, sz) monitor_write("kmalloc:"); monitor_writeHex(sz); void *var = kmalloc(sz); \ + if (var < 0xE0000000) { monitor_write(":FAIL\t"); PANIC("A test failed."); } \ + else monitor_write(":OK:"); monitor_writeHex(var); monitor_write("\t"); +#define TEST_KFREE(var) if (var != 0) { monitor_write("kfree:"); monitor_writeHex(var); kfree(var); monitor_write(":OK\t"); } + +void test_run() { + monitor_write("Run kmalloc() and kfree() unit tests:\n"); + int i; + for (i = 1; i <= 5; i++) { + monitor_write("\nMALLOC TEST SERIES #"); monitor_writeDec(i); monitor_write(":\n"); + TEST_KMALLOC(a, 32); + TEST_KMALLOC(b, 64); + TEST_KMALLOC(c, 256); + TEST_KMALLOC(d, 512); + TEST_KMALLOC(e, 1024); + TEST_KMALLOC(f, 4096); + TEST_KMALLOC(g, 16384); + TEST_KFREE(b); + TEST_KFREE(c); + TEST_KFREE(d); + TEST_KFREE(e); + TEST_KFREE(f); + TEST_KFREE(g); + } + monitor_write("\nUnit tests finished.\n"); +} diff --git a/src/kernel/core/test.h b/src/kernel/core/test.h new file mode 100644 index 0000000..ee689c6 --- /dev/null +++ b/src/kernel/core/test.h @@ -0,0 +1,6 @@ +#ifndef DEF_TEST_H +#define DEF_TEST_H + +void test_run(); //run basic unit tests on kmalloc() and kfree() + +#endif diff --git a/src/kernel/lib/stdlib.h b/src/kernel/lib/stdlib.h index 704c410..319cf26 100644 --- a/src/kernel/lib/stdlib.h +++ b/src/kernel/lib/stdlib.h @@ -8,5 +8,8 @@ uint8_t *memset(uint8_t *dest, uint8_t val, int count); uint16_t *memsetw(uint16_t *dest, uint16_t val, int count); int strlen(const char *str); +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + #endif diff --git a/src/kernel/linker/elf.c b/src/kernel/linker/elf.c index 6ad5d34..7eaae94 100644 --- a/src/kernel/linker/elf.c +++ b/src/kernel/linker/elf.c @@ -44,7 +44,7 @@ struct process* elf_exec(uint8_t *data, int privilege) { thread_entry e = elf_load(data, p); - thread_new(p, e, 0); + thread_new(p, e, 0, 0); return p; } diff --git a/src/kernel/mem/heap.c b/src/kernel/mem/heap.c index b7f6c97..79ef81e 100644 --- a/src/kernel/mem/heap.c +++ b/src/kernel/mem/heap.c @@ -1,5 +1,8 @@ #include "heap.h" #include "paging.h" +#include + +#include #define HEAP_MAGIC 0xBAD0BEEF #define HEAP_MIN_SIZE 0x4000 @@ -11,7 +14,7 @@ static void heapIdx_insert(struct heap *heap, struct heap_header *e) { if ((heap->idxused + sizeof(struct heap_header*) + (size_t)heap->idx) >= heap->start_addr) return; uint32_t iterator = 0, pos; - while (iterator < heap->idxused && heap->idx[iterator]->size < e->size) { + while (iterator < heap->idxused && heap->idx[iterator]->size <= e->size) { if (heap->idx[iterator] == e) return; iterator++; } @@ -122,15 +125,19 @@ static uint32_t heap_expand(struct heap *heap, size_t quantity) { /* For internal use only. Called by heap_free when necessary. Reduces the heap's size. */ static void heap_contract(struct heap *heap) { + return; //TODO: this function bugs everything + + struct heap_footer *last_footer = (struct heap_footer*)(heap->end_addr - sizeof(struct heap_footer)); struct heap_header *last_header = last_footer->header; if (last_header->is_hole == 0) return; + if (last_header->size <= 0x1000) return; - size_t quantity = 0; - while ((heap->end_addr - heap->start_addr) - quantity > HEAP_MIN_SIZE && - (last_header->size - quantity) > 0x1000) - quantity += 0x1000; + size_t quantity = ((heap->end_addr - heap->start_addr) & 0xFFFFF000) - 0x1000; + while ((heap->end_addr - heap->start_addr) - quantity < HEAP_MIN_SIZE || + last_header->size - 0x4000 < quantity) + quantity -= 0x1000; if (quantity == 0) return; size_t newEnd = heap->end_addr - quantity; @@ -149,6 +156,7 @@ static void heap_contract(struct heap *heap) { /* Alocate some bytes on the heap. */ void* heap_alloc(struct heap *heap, size_t sz) { + ASSERT(heap > 0xE0000000); size_t newsize = sz + sizeof(struct heap_header) + sizeof(struct heap_footer); uint32_t iterator = 0; @@ -158,17 +166,19 @@ void* heap_alloc(struct heap *heap, size_t sz) { } if (iterator == heap->idxused) { //No hole is big enough - if (heap_expand(heap, (sz & 0xFFFFF000) + 0x1000) == 0) return 0; //FAILED + if (heap_expand(heap, + MAX((heap->end_addr - heap->start_addr) & 0xFFFFF000, (newsize & 0xFFFFF000) + 0x1000) + ) == 0) return 0; //FAILED return heap_alloc(heap, sz); } struct heap_header *loc = heap->idx[iterator]; + heapIdx_remove(heap, loc); struct heap_footer *footer = (struct heap_footer*)((size_t)loc + loc->size - sizeof(struct heap_footer)); loc->is_hole = 0; - heapIdx_remove(heap, loc); //If we have enough space to create a USEFUL new hole next to the allocated block, do it. - //If we do not, we might return a block that is a few bytes bigger than neede. + //If we do not, we might return a block that is a few bytes bigger than needed. if (loc->size > (newsize + sizeof(struct heap_header) + sizeof(struct heap_footer))) { loc->size = newsize; diff --git a/src/kernel/mem/mem.c b/src/kernel/mem/mem.c index 47a03dc..2061aff 100644 --- a/src/kernel/mem/mem.c +++ b/src/kernel/mem/mem.c @@ -7,7 +7,7 @@ #define FREEPAGESTOKEEP 5 #define KHEAP_IDXSIZE 0x1000 -#define KHEAP_INITSIZE 0x8000 +#define KHEAP_INITSIZE 0x80000 #define KHEAP_MAXSIZE 0x08000000 size_t mem_placementAddr; diff --git a/src/kernel/mem/paging.c b/src/kernel/mem/paging.c index f8f69f1..4e5f33a 100644 --- a/src/kernel/mem/paging.c +++ b/src/kernel/mem/paging.c @@ -134,13 +134,14 @@ uint32_t paging_fault(struct registers *regs) { } if (seg == 0) { - WHERE; monitor_write("Unhandled Page Fault "); - if (regs->err_code & 0x1) monitor_write("present "); - if (regs->err_code & 0x2) monitor_write("write "); - if (regs->err_code & 0x4) monitor_write("user "); - if (regs->err_code & 0x8) monitor_write("rsvd "); - if (regs->err_code & 0x10) monitor_write("instructionfetch "); - monitor_write("cr2:"); monitor_writeHex(addr); monitor_write("\n"); + NL; WHERE; monitor_write("Unhandled Page Fault\t"); + monitor_write("cr2:"); monitor_writeHex(addr); + NL; TAB; + if (regs->err_code & 0x1) monitor_write("present"); TAB; + if (regs->err_code & 0x2) monitor_write("write"); TAB; + if (regs->err_code & 0x4) monitor_write("user"); TAB; + if (regs->err_code & 0x8) monitor_write("rsvd"); TAB; + if (regs->err_code & 0x10) monitor_write("opfetch"); return 1; } return 0; diff --git a/src/kernel/task/idt.c b/src/kernel/task/idt.c index 6aa16e0..be5d152 100644 --- a/src/kernel/task/idt.c +++ b/src/kernel/task/idt.c @@ -75,11 +75,9 @@ static struct irq_waiter { void idt_isrHandler(struct registers regs) { if ((regs.int_no == 14 && paging_fault(®s) != 0) || regs.int_no != 14) { if (tasking_handleException(®s) == 0) { - monitor_write("\n >> >> SOMETHING BAD HAPPENNED << <<\n"); - monitor_write("Unhandled exception "); - monitor_writeHex(regs.int_no); - monitor_write(" @"); monitor_writeHex(regs.eip); - monitor_put('\n'); + monitor_write("\nREALLY BAD THIS TIME\t\tUnhandled exception\t#"); + monitor_writeDec(regs.int_no); + monitor_write("\t@"); monitor_writeHex(regs.eip); PANIC("Unhandled Exception"); } } diff --git a/src/kernel/task/syscall.c b/src/kernel/task/syscall.c index 41cd0ea..b490987 100644 --- a/src/kernel/task/syscall.c +++ b/src/kernel/task/syscall.c @@ -35,7 +35,7 @@ CALL2(send_msg, send_msg_sc); CALL2(process_setheapseg, proc_setheap_sc); static void thread_new_sc(struct registers* r) { - thread_new(current_thread->process, (thread_entry)r->ebx, (void*)r->ecx); + thread_new(current_thread->process, (thread_entry)r->ebx, (void*)r->ecx, (void*)r->edx); } int_callback syscalls[NUMBER_OF_SYSCALLS] = { diff --git a/src/kernel/task/task.c b/src/kernel/task/task.c index 7153d85..b8a72ce 100644 --- a/src/kernel/task/task.c +++ b/src/kernel/task/task.c @@ -39,7 +39,7 @@ void tasking_init() { kernel_process->pagedir = kernel_pagedir; kernel_process->next = 0; current_thread = 0; - idle_thread = thread_new(kernel_process, task_idle, 0); + idle_thread = thread_new(kernel_process, task_idle, 0, 0); kernel_process->threads = idle_thread; sti(); monitor_write("[Tasking] "); @@ -99,15 +99,15 @@ void tasking_switch() { Ends the thread for most exceptions, ends the whole process for page faults. */ uint32_t tasking_handleException(struct registers *regs) { if (current_thread == 0) return 0; //No tasking yet - NL; WHERE; monitor_write("Unhandled exception : "); + NL; WHERE; monitor_write("exception:`"); char *exception_messages[] = {"Division By Zero","Debug","Non Maskable Interrupt","Breakpoint", "Into Detected Overflow","Out of Bounds","Invalid Opcode","No Coprocessor", "Double Fault", "Coprocessor Segment Overrun","Bad TSS","Segment Not Present","Stack Fault","General Protection Fault", "Page Fault","Unknown Interrupt","Coprocessor Fault","Alignment Check","Machine Check"}; monitor_write(exception_messages[regs->int_no]); - monitor_write(" eip:"); monitor_writeHex(regs->eip); + monitor_write("'\teip:"); monitor_writeHex(regs->eip); if (regs->eip >= 0xE0000000) { - monitor_write("\n Exception stack trace :"); + monitor_write("\n Exception stack trace :\n"); stack_trace(regs->ebp); PANIC("Kernel error'd."); } @@ -194,10 +194,10 @@ void process_exit(uint32_t retval) { /* For internal use only. This is called when a newly created thread first runs (its address is the value given for EIP). It switches to user mode if necessary and calls the entry point. */ -static void thread_run(struct thread *thread, thread_entry entry_point, void *data) { +static void thread_run(void* u_esp, struct thread *thread, thread_entry entry_point, void *data) { pagedir_switch(thread->process->pagedir); if (thread->process->privilege >= PL_SERVICE) { //User mode ! - uint32_t *stack = (uint32_t*)(thread->userStack_seg->start + thread->userStack_seg->len); + uint32_t *stack = u_esp; stack--; *stack = (uint32_t)data; stack--; *stack = 0; @@ -239,16 +239,13 @@ static void thread_run(struct thread *thread, thread_entry entry_point, void *da /* Creates a new thread for given process. Allocates a kernel stack and a user stack if necessary. Sets up the kernel stack for values to be passed to thread_run. */ -struct thread *thread_new(struct process *proc, thread_entry entry_point, void *data) { +struct thread *thread_new(struct process *proc, thread_entry entry_point, void *data, void *u_esp) { struct thread *t = kmalloc(sizeof(struct thread)); t->process = proc; t->next = 0; proc->thread_count++; - if (proc->privilege >= PL_SERVICE) { //We are running in user mode - proc->stacksBottom -= USER_STACK_SIZE; - t->userStack_seg = seg_map(simpleseg_make(proc->stacksBottom, USER_STACK_SIZE, 1), proc->pagedir, 0); - } + if (u_esp == 0) u_esp = (void*)proc->stack; t->kernelStack_addr = kmalloc(KSTACKSIZE); t->kernelStack_size = KSTACKSIZE; @@ -259,6 +256,7 @@ struct thread *thread_new(struct process *proc, thread_entry entry_point, void * stack--; *stack = (uint32_t)data; stack--; *stack = (uint32_t)entry_point; stack--; *stack = (uint32_t)t; + stack--; *stack = (uint32_t)u_esp; stack--; *stack = 0; t->esp = (uint32_t)stack; t->ebp = t->esp + 8; @@ -287,9 +285,15 @@ struct process *process_new(struct process* parent, uint32_t uid, uint32_t privi p->parent = parent; p->pagedir = pagedir_new(); p->next = processes; - p->stacksBottom = 0xDF000000; p->heapseg = 0; + p->stack = 0; + if (p->privilege >= PL_SERVICE) { //We are running in user mode + size_t stacksBottom = 0xDF000000; + seg_map(simpleseg_make(stacksBottom, USER_STACK_SIZE, 1), p->pagedir, 0); + p->stack = stacksBottom + USER_STACK_SIZE - 4; + } + p->next_objdesc = 0; p->objects = 0; struct object* o = obj_new(p); @@ -318,7 +322,6 @@ static void thread_delete(struct thread *th) { if (current_thread == th) current_thread = 0; th->process->thread_count--; kfree(th->kernelStack_addr); - if (th->userStack_seg != 0) seg_unmap(th->userStack_seg); kfree(th); } diff --git a/src/kernel/task/task.h b/src/kernel/task/task.h index 0a95e57..171a9fd 100644 --- a/src/kernel/task/task.h +++ b/src/kernel/task/task.h @@ -26,7 +26,7 @@ struct process { uint32_t pid, uid, privilege, thread_count; struct process *parent; struct page_directory *pagedir; - size_t stacksBottom; + size_t stack; struct obj_descriptor *objects; uint32_t next_objdesc; @@ -44,7 +44,6 @@ struct thread { uint32_t timeWait; void* kernelStack_addr; uint32_t kernelStack_size; - struct segment_map *userStack_seg; struct thread *next, *queue_next; //queue_next is used in sched.c }; @@ -59,7 +58,7 @@ uint32_t tasking_handleException(struct registers *regs); void thread_goInactive(); //Blocks the current thread. it is then waked up by another thread or a system event. void thread_wakeUp(struct thread *t); int proc_priv(); //Returns current privilege level -struct thread * thread_new(struct process *proc, thread_entry entry_point, void *data); +struct thread * thread_new(struct process *proc, thread_entry entry_point, void *data, void *u_esp); struct process* process_new(struct process *parent, uint32_t uid, uint32_t privilege); void thread_exit(); //syscall diff --git a/src/library/gc/syscall.c b/src/library/gc/syscall.c index e7d77a0..b16881e 100644 --- a/src/library/gc/syscall.c +++ b/src/library/gc/syscall.c @@ -1,4 +1,5 @@ #include +#include static int call(unsigned a, unsigned b, unsigned c, unsigned d, unsigned e, unsigned f) { unsigned ret; @@ -26,8 +27,24 @@ void printk(char* str) { call(4, (unsigned)str, 0, 0, 0, 0); } +//THREAD CREATION +struct thread_start_data { + void (*entry)(void*); + void *data; + void *stack; +}; +void thread_start(void *data) { + struct thread_start_data *tsd = data; + tsd->entry(tsd->data); + free(tsd->stack); + thread_exit(); +} void thread_new(void (*entry)(void*), void *data) { - call(5, (unsigned)entry, (unsigned)data, 0, 0, 0); + struct thread_start_data *tsd = malloc(sizeof(struct thread_start_data)); + tsd->entry = entry; + tsd->data = data; + tsd->stack = malloc(NEW_STACK_SIZE); + call(5, (unsigned)thread_start, (unsigned)tsd, (unsigned)(tsd->stack + NEW_STACK_SIZE), 0, 0); } void irq_wait(int number) { diff --git a/src/modules/test/main.c b/src/modules/test/main.c index 507567f..493867e 100644 --- a/src/modules/test/main.c +++ b/src/modules/test/main.c @@ -30,6 +30,12 @@ void thread2(void* d) { } } +void thread_cascade(void* d) { + c_logSvc("{#} Thread cascade element started. Continuing.", LL_STATUS); + thread_new(thread_cascade, (void*)((int)d - 1)); + c_logSvc("{#} Thread cascade element finished.", LL_STATUS); +} + int main() { c_logSvc("Hi world from unregistered test module !", LL_NOTICE); c_registerSvc("test"); @@ -38,6 +44,9 @@ int main() { c_logSvc("{1} Sending a test message to manager", LL_STATUS); c_nothing(1, 0); + c_logSvc("{1} Creating thread cascade len:3", LL_STATUS); + thread_new(thread_cascade, (void*)3); + c_logSvc("{1} Thread now sleeping...", LL_WARNING); while (1) thread_sleep(1000); return 0; -- cgit v1.2.3