From e9683297bf480f9590b0e5796f4520fb430e2e03 Mon Sep 17 00:00:00 2001 From: Alex AUVOLAT Date: Tue, 1 May 2012 17:42:36 +0200 Subject: Now using Doug Lea's malloc for userland too. And improved stability. --- src/kernel/Makefile | 4 +-- src/kernel/core/kmain.c | 7 ++--- src/kernel/core/sys.c | 3 ++- src/kernel/core/test.c | 37 -------------------------- src/kernel/core/test.h | 6 ----- src/kernel/lib/mutex.c | 24 ----------------- src/kernel/lib/mutex.h | 15 ----------- src/kernel/linker/elf.c | 9 ++++++- src/kernel/mem/_dlmalloc.c | 8 ++++++ src/kernel/mem/_dlmalloc.h | 5 ++++ src/kernel/mem/gdt.c | 2 +- src/kernel/mem/mem.h | 1 + src/kernel/mem/paging.c | 5 ++-- src/kernel/task/idt.c | 6 ++--- src/kernel/task/sched.c | 2 +- src/kernel/task/syscall.c | 8 +++--- src/kernel/task/task.c | 66 +++++++++++++++++++++++++++++++++++++++------- src/kernel/task/task.h | 19 +++++++------ 18 files changed, 106 insertions(+), 121 deletions(-) delete mode 100644 src/kernel/core/test.c delete mode 100644 src/kernel/core/test.h delete mode 100644 src/kernel/lib/mutex.c delete mode 100644 src/kernel/lib/mutex.h (limited to 'src/kernel') diff --git a/src/kernel/Makefile b/src/kernel/Makefile index 0950ba7..6060911 100644 --- a/src/kernel/Makefile +++ b/src/kernel/Makefile @@ -1,8 +1,8 @@ Out = kernel.elf -Obj = core/loader_.o core/kmain.o core/sys.o core/test.o \ +Obj = core/loader_.o core/kmain.o core/sys.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/bitset.o lib/mutex.o lib/std.o \ + lib/bitset.o lib/std.o \ mem/mem.o mem/paging.o mem/gdt.o mem/_dlmalloc.o mem/seg.o \ linker/elf.o diff --git a/src/kernel/core/kmain.c b/src/kernel/core/kmain.c index 17c9425..8c36b54 100644 --- a/src/kernel/core/kmain.c +++ b/src/kernel/core/kmain.c @@ -4,7 +4,6 @@ #include "multiboot.h" #include "monitor.h" #include "sys.h" -#include "test.h" #include #include #include @@ -56,8 +55,6 @@ void kmain(struct multiboot_info_t* mbd, int32_t magic) { //kheap_init(); timer_init(30); tasking_init(); - - //test_run(); monitor_write("\n\nLoading modules :\n"); for (i = 0; i < mbd->mods_count; i++) { @@ -66,7 +63,7 @@ void kmain(struct multiboot_info_t* mbd, int32_t magic) { if (elf_check((uint8_t*)mods[i].mod_start)) { monitor_write(" : Invalid ELF file\n"); } else { - struct process *pr = elf_exec((uint8_t*)mods[i].mod_start, PL_DRIVER); + struct process *pr = elf_exec((uint8_t*)mods[i].mod_start, PL_USER); if (pr == 0) { monitor_write(" : Error loading\n"); } else { @@ -77,6 +74,6 @@ void kmain(struct multiboot_info_t* mbd, int32_t magic) { monitor_write("Modules now RULE THE WORLD !\n\n"); sti(); - tasking_switch(); + schedule(); PANIC("Should never happen. Something probably went wrong with multitasking."); } diff --git a/src/kernel/core/sys.c b/src/kernel/core/sys.c index 4a88838..2c2372d 100644 --- a/src/kernel/core/sys.c +++ b/src/kernel/core/sys.c @@ -39,11 +39,12 @@ void stack_trace(size_t bp) { /* For internal use only. Used by panic and panic_assert. */ static void panic_do(char* file, int line) { + asm volatile("cli;"); monitor_write("\n File:\t\t"); monitor_write(file); monitor_put(':'); monitor_writeDec(line); monitor_write("\nTrace:\n"); size_t bp; asm volatile("mov %%ebp,%0" : "=r"(bp)); stack_trace(bp); monitor_write("\n\t\tSystem halted -_-'"); - asm volatile("cli; hlt"); + asm volatile("hlt"); } /* These functions stop the system, reporting an error message, because something bad happenned. */ diff --git a/src/kernel/core/test.c b/src/kernel/core/test.c deleted file mode 100644 index 8f7b32c..0000000 --- a/src/kernel/core/test.c +++ /dev/null @@ -1,37 +0,0 @@ -#include "test.h" -#include "monitor.h" -#include -#include "sys.h" - -static void test_run_kmalloc() { - monitor_write("\tkmalloc:\n"); - int alloc_sizes[8] = { 10, 32, 16, 20, 64, 128, 32, 48 }; - int *ptrs[8] = { 0 }; - int t, i; - for (t = 0; t < 4; t++) { - for (i = 0; i < 8; i++) { - monitor_writeDec(i); monitor_write(" alloc "); monitor_writeDec(alloc_sizes[i]); - monitor_write(" : "); - ptrs[i] = kmalloc(alloc_sizes[i]); - ASSERT(ptrs[i] != 0); - *ptrs[i] = i; - monitor_writeHex((int)ptrs[i]); monitor_write("\n"); - } - monitor_write("free : "); - for (i = 0; i < 8; i++) { - monitor_writeDec(i); - ASSERT(*ptrs[i] == i); - kfree(ptrs[i]); - monitor_write("."); - } - monitor_write("\n"); - } -} - -/* This function is called when the kernel starts up. - It runs some basic unit tests (for the moment, only tests kmalloc/kfree) */ -void test_run() { - monitor_write("Unit tests:\n"); - test_run_kmalloc(); - monitor_write(" >> Tests OK\n"); -} diff --git a/src/kernel/core/test.h b/src/kernel/core/test.h deleted file mode 100644 index ee689c6..0000000 --- a/src/kernel/core/test.h +++ /dev/null @@ -1,6 +0,0 @@ -#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/mutex.c b/src/kernel/lib/mutex.c deleted file mode 100644 index 2664eb0..0000000 --- a/src/kernel/lib/mutex.c +++ /dev/null @@ -1,24 +0,0 @@ -#include "mutex.h" -#include - -/* Internal use only. This function is atomic, meaning it cannot be interrupted by a system task switch. */ -static uint32_t atomic_exchange(uint32_t* ptr, uint32_t newval) { - uint32_t r; - asm volatile("xchg (%%ecx), %%eax" : "=a"(r) : "c"(ptr), "a"(newval)); - return r; -} - -void mutex_lock(uint32_t* mutex) { - while (atomic_exchange(mutex, MUTEX_LOCKED) == MUTEX_LOCKED) { - thread_sleep(1); - } -} - -int mutex_lockE(uint32_t* mutex) { - if (atomic_exchange(mutex, MUTEX_LOCKED) == MUTEX_LOCKED) return 0; - return 1; -} - -void mutex_unlock(uint32_t* mutex) { - *mutex = MUTEX_UNLOCKED; -} diff --git a/src/kernel/lib/mutex.h b/src/kernel/lib/mutex.h deleted file mode 100644 index 2687b30..0000000 --- a/src/kernel/lib/mutex.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef DEF_MUTEX_H -#define DEF_MUTEX_H - -#include - -#define MUTEX_LOCKED 1 -#define MUTEX_UNLOCKED 0 - -//A mutex is just an uint32_t - -void mutex_lock(uint32_t* mutex); //wait for mutex to be free -int mutex_lockE(uint32_t* mutex); //lock mutex only if free, returns !0 if locked, 0 if was busy -void mutex_unlock(uint32_t* mutex); - -#endif diff --git a/src/kernel/linker/elf.c b/src/kernel/linker/elf.c index 7eaae94..af6d057 100644 --- a/src/kernel/linker/elf.c +++ b/src/kernel/linker/elf.c @@ -1,7 +1,7 @@ #include "elf.h" #include #include -#include +#include #include int elf_check(uint8_t *data) { @@ -14,6 +14,7 @@ thread_entry elf_load(uint8_t *data, struct process* process) { struct elf_ehdr *ehdr = (struct elf_ehdr*)data; struct elf_phdr *phdr; int i; + size_t dataseg = 0; if (elf_check(data)) return 0; struct page_directory *r = current_pagedir; @@ -28,9 +29,15 @@ thread_entry elf_load(uint8_t *data, struct process* process) { if (phdr[i].p_memsz > phdr[i].p_filesz) { memset((uint8_t*)phdr[i].p_vaddr + phdr[i].p_memsz, 0, phdr[i].p_memsz - phdr[i].p_filesz); } + if (phdr[i].p_vaddr + phdr[i].p_memsz > dataseg) { + dataseg = phdr[i].p_vaddr + phdr[i].p_memsz; + dataseg = (dataseg & 0xFFFFF000) + 0x1000; + } } } + process->data = dataseg; + pagedir_switch(r); sti(); diff --git a/src/kernel/mem/_dlmalloc.c b/src/kernel/mem/_dlmalloc.c index 18dabab..30c6622 100644 --- a/src/kernel/mem/_dlmalloc.c +++ b/src/kernel/mem/_dlmalloc.c @@ -912,6 +912,14 @@ static FORCEINLINE int win32munmap(void* ptr, size_t size) { /* #define TRY_LOCK(lk) ... */ /* static MLOCK_T malloc_global_mutex = ... */ +#define MLOCK_T uint32_t +#define INITIAL_LOCK(l) (*l = MUTEX_UNLOCKED) +#define DESTROY_LOCK(l) (0) +#define ACQUIRE_LOCK(l) (mutex_lock (l)) +#define RELEASE_LOCK(l) (mutex_unlock (l)) +#define TRY_LOCK(l) (mutex_lockE(l)) +static MLOCK_T malloc_global_mutex = MUTEX_UNLOCKED; + #elif USE_SPIN_LOCKS /* First, define CAS_LOCK and CLEAR_LOCK on ints */ diff --git a/src/kernel/mem/_dlmalloc.h b/src/kernel/mem/_dlmalloc.h index a030da2..7b2e2cc 100644 --- a/src/kernel/mem/_dlmalloc.h +++ b/src/kernel/mem/_dlmalloc.h @@ -2,14 +2,19 @@ #define DEF_DLMALLOC_H #include "lib/std.h" +#include +#include #define NO_MALLOC_STATS 1 #define LACKS_TIME_H #define LACKS_UNISTD_H #define LACKS_SYS_PARAM_H +#define LACKS_STDLIB_H #define USE_DL_PREFIX +#define USE_LOCKS 2 + /* Version identifier to allow people to support multiple versions */ #ifndef DLMALLOC_VERSION diff --git a/src/kernel/mem/gdt.c b/src/kernel/mem/gdt.c index 8ee403a..494aaf2 100644 --- a/src/kernel/mem/gdt.c +++ b/src/kernel/mem/gdt.c @@ -1,5 +1,5 @@ #include "gdt.h" -#include +#include #include extern void gdt_flush(uint32_t); //ASM (imported from idt_.asm) diff --git a/src/kernel/mem/mem.h b/src/kernel/mem/mem.h index b6e9622..cb9c396 100644 --- a/src/kernel/mem/mem.h +++ b/src/kernel/mem/mem.h @@ -5,6 +5,7 @@ kmalloc_page and kfree_page are used mostly for paging. */ #include +#include "_dlmalloc.h" void* kmalloc_page(size_t *phys); void kfree_page(void* page); diff --git a/src/kernel/mem/paging.c b/src/kernel/mem/paging.c index 5953fc6..0527f06 100644 --- a/src/kernel/mem/paging.c +++ b/src/kernel/mem/paging.c @@ -1,6 +1,6 @@ #include "paging.h" #include -#include +#include #include #include "mem.h" #include "seg.h" @@ -17,7 +17,7 @@ struct page_directory *kernel_pagedir, *current_pagedir; uint32_t frame_alloc() { uint32_t free = bitset_firstFree(&frames); if (free == (uint32_t) -1) { - PANIC("Out of memory!"); + PANIC("No more frames to allocate, system is out of memory!"); } bitset_set(&frames, free); return free; @@ -166,7 +166,6 @@ struct page *pagedir_getPage(struct page_directory *pd, uint32_t address, int ma pd->tablesPhysical[table_idx] |= 0x07; if (table_idx >= FIRST_KERNEL_PAGETABLE) { - monitor_write("UKPI "); tasking_updateKernelPagetable(table_idx, pd->tables[table_idx], pd->tablesPhysical[table_idx]); } diff --git a/src/kernel/task/idt.c b/src/kernel/task/idt.c index ff129be..aed5ea8 100644 --- a/src/kernel/task/idt.c +++ b/src/kernel/task/idt.c @@ -6,7 +6,7 @@ #include "task.h" #include "syscall.h" -#include +#include extern void isr0(); extern void isr1(); @@ -102,7 +102,7 @@ void idt_irqHandler(struct registers regs) { if (irq_handlers[regs.err_code] != 0) { irq_handlers[regs.err_code](®s); } - if (doSwitch) tasking_switch(); + if (doSwitch) schedule(); } /* Called in idt_.asm on a system call (interrupt 64). @@ -208,7 +208,7 @@ void idt_handleIrq(int number, int_callback func) { /* Tells the IRQ handler to wake up the current thread when specified IRQ fires. */ void idt_waitIrq(int number) { - if (number < 16 && number >= 0 && proc_priv() <= PL_DRIVER) { + if (number < 16 && number >= 0 && proc_priv() <= PL_KERNEL) { struct irq_waiter *tmp = kmalloc(sizeof(struct irq_waiter)); tmp->thread = current_thread; tmp->next = irq_wakeup[number]; diff --git a/src/kernel/task/sched.c b/src/kernel/task/sched.c index 2b0ef8a..aa41d5b 100644 --- a/src/kernel/task/sched.c +++ b/src/kernel/task/sched.c @@ -3,7 +3,7 @@ #include // Lower priority numbers have high priority. Priorities must start at 0. -#define PRIORITIES 4 // we have 4 priority levels +#define PRIORITIES 3 // we have 4 priority levels #define PRIORITY(t) (t->process->privilege) //get priority for a thread extern struct thread *idle_thread; diff --git a/src/kernel/task/syscall.c b/src/kernel/task/syscall.c index 5d40596..bd27eba 100644 --- a/src/kernel/task/syscall.c +++ b/src/kernel/task/syscall.c @@ -16,13 +16,14 @@ #define CALL4V(name, scname) static void scname(struct registers* r) { name(r->ebx, r->ecx, r->edx, r->esi); } CALL0V(thread_exit, thread_exit_sc); -CALL0V(tasking_switch, schedule_sc); +CALL0V(schedule, schedule_sc); CALL1V(thread_sleep, thread_sleep_sc); CALL1V(process_exit, process_exit_sc); CALL1(monitor_write, printk_sc); CALL1V(idt_waitIrq, irq_wait_sc); CALL0(proc_priv, proc_priv_sc); -CALL2(process_setheapseg, proc_setheap_sc); +CALL1(process_sbrk, proc_sbrk_sc); +CALL1V(process_brk, proc_brk_sc); static void thread_new_sc(struct registers* r) { cli(); @@ -39,5 +40,6 @@ int_callback syscalls[NUMBER_OF_SYSCALLS] = { thread_new_sc, //5 irq_wait_sc, proc_priv_sc, - proc_setheap_sc, + proc_sbrk_sc, + proc_brk_sc, 0 }; diff --git a/src/kernel/task/task.c b/src/kernel/task/task.c index 7071248..9d98165 100644 --- a/src/kernel/task/task.c +++ b/src/kernel/task/task.c @@ -55,7 +55,7 @@ void tasking_updateKernelPagetable(uint32_t idx, struct page_table *table, uint3 } /* Called when a timer IRQ fires. Does a context switch. */ -void tasking_switch() { +void schedule() { if (processes == 0) PANIC("No processes are running !"); asm volatile("cli"); @@ -122,7 +122,7 @@ uint32_t tasking_handleException(struct registers *regs) { /* Puts the current thread in an inactive state. */ void thread_goInactive() { current_thread->state = TS_WAKEWAIT; - tasking_switch(); + schedule(); } /* Wakes up the given thread. */ @@ -157,7 +157,7 @@ void thread_exit2(uint32_t reason) { //See EX_TH_* defines in task.h } retrn: sti(); - tasking_switch(); + schedule(); } /* For internal use only. Called by thread_exit and process_exit. @@ -183,7 +183,7 @@ void thread_exit() { } /* System call. Exit the current process. */ -void process_exit(uint32_t retval) { +void process_exit(size_t retval) { if (retval == EX_TH_NORMAL || retval == EX_TH_EXCEPTION) retval = EX_PR_EXCEPTION; thread_exit_stackJmp(retval); } @@ -193,7 +193,7 @@ void process_exit(uint32_t retval) { It switches to user mode if necessary and calls the entry point. */ 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 ! + if (thread->process->privilege >= PL_USER) { //User mode ! uint32_t *stack = u_esp; stack--; *stack = (uint32_t)data; @@ -283,11 +283,12 @@ struct process *process_new(struct process* parent, uint32_t uid, uint32_t privi p->parent = parent; p->pagedir = pagedir_new(); p->next = processes; - p->heapseg = 0; + p->data = 0; + p->dataseg = 0; p->stack = 0; - if (p->privilege >= PL_SERVICE) { //We are running in user mode - size_t stacksBottom = 0xDF000000; + if (p->privilege >= PL_USER) { //We are running in user mode + size_t stacksBottom = K_HIGHHALF_ADDR - 0x01000000; seg_map(simpleseg_make(stacksBottom, USER_STACK_SIZE, 1), p->pagedir, 0); p->stack = stacksBottom + USER_STACK_SIZE - 4; } @@ -340,7 +341,7 @@ static void process_delete(struct process *pr) { } /* System call. Called by the app to define the place for the heap. */ -int process_setheapseg(size_t start, size_t end) { //syscall +/*int process_setheapseg(size_t start, size_t end) { //syscall struct process *p = current_thread->process; if (start >= K_HIGHHALF_ADDR || end >= K_HIGHHALF_ADDR) return -1; if (p->heapseg == 0) { @@ -359,4 +360,51 @@ int process_setheapseg(size_t start, size_t end) { //syscall } else { return simpleseg_resize(p->heapseg, end - start); } +}*/ + +size_t process_sbrk(size_t size) { + struct process *p = current_thread->process; + if (p->data == 0) return -1; + ASSERT(p->data < K_HIGHHALF_ADDR); + if (p->data + size >= K_HIGHHALF_ADDR) return -1; + + size_t ret; + if (p->dataseg == 0) { + size_t start = p->data; + if (start & 0x0FFF) start = (start & 0xFFFFF000) + 0x1000; + size_t end = start + size; + if (end & 0x0FFF) end = (end & 0xFFFFF000) + 0x1000; + + struct segment *s = simpleseg_make(start, end - start, 1); + if (s == 0) return -5; + p->dataseg = seg_map(s, p->pagedir, 0); + if (p->dataseg == 0) return -1; + + ret = start; + p->data = start + size; + } else { + size_t start = p->dataseg->start; + size_t end = p->data + size; + if (end <= start) return -1; + + if (end & 0x0FFF) end = (end & 0xFFFFF000) + 0x1000; + simpleseg_resize(p->dataseg, end - start); + + ret = p->data; + p->data += size; + } + /* (DBG) monitor_write("(sbrk "); + monitor_writeHex(size); + monitor_write(" "); + monitor_writeHex(ret); + monitor_write(")"); */ + return ret; } + +void process_brk(size_t ptr) { + struct process *p = current_thread->process; + + ASSERT(ptr < K_HIGHHALF_ADDR); + process_sbrk(ptr - p->data); +} + diff --git a/src/kernel/task/task.h b/src/kernel/task/task.h index fdffa11..63cb35a 100644 --- a/src/kernel/task/task.h +++ b/src/kernel/task/task.h @@ -8,17 +8,15 @@ #define TS_RUNNING 0 #define TS_WAKEWAIT 2 //Waiting to be waked up by something precise (thread currently blocked) -#define PL_UNKNOWN 4 -#define PL_USER 3 -#define PL_SERVICE 2 -#define PL_DRIVER 1 +#define PL_UNKNOWN 2 +#define PL_USER 1 #define PL_KERNEL 0 #define EX_TH_NORMAL 0x10000 //ERROR code : just one thread exits, because it has to #define EX_TH_EXCEPTION 0x10001 //ERROR code : just one thread exits, because of an unhandled exception #define EX_PR_EXCEPTION 0x10002 //ERROR code : all process finishes, because of an unhandled exception -#define USER_STACK_SIZE 0x8000 //32k, but pages will be mapped one by one as used +#define USER_STACK_SIZE 0x10000 //64k, but pages will be mapped one by one as they are used typedef void (*thread_entry)(void*); @@ -26,9 +24,9 @@ struct process { uint32_t pid, uid, privilege, thread_count; struct process *parent; struct page_directory *pagedir; - size_t stack; + size_t stack, data; - struct segment_map *heapseg; + struct segment_map *dataseg; struct process *next; //Forms a linked list struct thread *threads; @@ -48,7 +46,7 @@ struct thread { extern struct thread *current_thread; void tasking_init(); -void tasking_switch(); +void schedule(); void tasking_updateKernelPagetable(uint32_t idx, struct page_table *table, uint32_t tablePhysical); uint32_t tasking_handleException(struct registers *regs); @@ -59,7 +57,8 @@ struct thread * thread_new(struct process *proc, thread_entry entry_point, void struct process* process_new(struct process *parent, uint32_t uid, uint32_t privilege); void thread_exit(); //syscall -void process_exit(uint32_t retval); //syscall -int process_setheapseg(size_t start, size_t end); //syscall +void process_exit(size_t retval); //syscall +size_t process_sbrk(size_t size); +void process_brk(size_t ptr); #endif -- cgit v1.2.3