From 0aea73bdc76d6898553cd9561285344bf4a7cc1d Mon Sep 17 00:00:00 2001 From: stefan Date: Mon, 2 Aug 2010 07:43:56 +0000 Subject: [PATCH] - add a simple memory mangement unit - use a bitmask to mark used pages (see lecture notes "BS") git-svn-id: http://svn.lfbs.rwth-aachen.de/svn/scc/trunk/MetalSVM@7 315a16e6-25f9-4109-90ae-ca3045a26c18 --- Makefile.example | 2 +- arch/x86/include/asm/mmu.h | 35 ------ arch/x86/include/asm/processor.h | 4 + include/metalsvm/config.h.example | 6 + include/metalsvm/errno.h | 3 +- include/metalsvm/mmu.h | 10 +- include/metalsvm/stdlib.h | 4 + include/metalsvm/tasks.h | 4 +- include/metalsvm/tasks_types.h | 5 + kernel/main.c | 8 +- kernel/tasks.c | 38 +++++-- link.ld | 3 + mm/Makefile | 2 +- mm/alloc.c | 181 ++++++++++++++++++++++++++++++ mm/init.c | 26 ----- 15 files changed, 251 insertions(+), 80 deletions(-) delete mode 100644 arch/x86/include/asm/mmu.h create mode 100644 mm/alloc.c delete mode 100644 mm/init.c diff --git a/Makefile.example b/Makefile.example index e7a270dd..07014410 100644 --- a/Makefile.example +++ b/Makefile.example @@ -10,7 +10,7 @@ export INCLUDE = -I$(TOPDIR)/include -I$(TOPDIR)/arch/$(ARCH)/include -I$(TOPDIR export CC = gcc export CFLAGS = -m32 -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -fno-builtin $(INCLUDE) export AR = ar -export ARFLAGS = rs +export ARFLAGS = rsv export RM = rm -rf LD = ld LDFLAGS = -T link.ld diff --git a/arch/x86/include/asm/mmu.h b/arch/x86/include/asm/mmu.h deleted file mode 100644 index 361d81e1..00000000 --- a/arch/x86/include/asm/mmu.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2010 Stefan Lankes, Chair for Operating Systems, - * RWTH Aachen University - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * This file is part of MetalSVM. - */ - -#ifndef __ARCH_MMU_H__ -#define __ARCH_MMU_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -extern void gdt_install(void); - -#define mmu_arch_init gdt_install - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index ab582eae..66db266f 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -36,6 +36,10 @@ static inline uint64_t rdtsc() #define NOP4 asm volatile ("nop;nop;nop;nop") #define NOP8 asm volatile ("nop;nop;nop;nop;nop;nop;nop;nop") +void gdt_install(void); + +#define system_init gdt_install + #ifdef __cplusplus } #endif diff --git a/include/metalsvm/config.h.example b/include/metalsvm/config.h.example index cbe4ff0a..343b9cec 100644 --- a/include/metalsvm/config.h.example +++ b/include/metalsvm/config.h.example @@ -33,6 +33,12 @@ extern "C" { #define TIMER_FREQ 100 /* in HZ */ #define CLOCK_TICK_RATE 1193182 /* 8254 chip's internal oscillator frequency */ +/* + * address space / (page_size * sizeof(uint8_t)) + * x86_32 => 4 GB / (4096 * 8) + */ +#define BITMAP_SIZE 1048576 + #define USE_VGA //undef USE_VGA diff --git a/include/metalsvm/errno.h b/include/metalsvm/errno.h index e68a4c70..d8539541 100644 --- a/include/metalsvm/errno.h +++ b/include/metalsvm/errno.h @@ -27,7 +27,8 @@ extern "C" { #endif - +#define EUNKNOWN 1 /* Out of memory */ +#define ENOMEM 2 /* Out of memory */ #ifdef __cplusplus } diff --git a/include/metalsvm/mmu.h b/include/metalsvm/mmu.h index 11d7e362..8e05e08e 100644 --- a/include/metalsvm/mmu.h +++ b/include/metalsvm/mmu.h @@ -20,12 +20,20 @@ #ifndef __MMU_H__ #define __MMU_H__ -#include +#include +#include +//#include #ifdef __cplusplus extern "C" { #endif +extern atomic_size_t total_usage; + +typedef struct { + atomic_size_t usage; +} mm_t; + void mmu_init(void); #ifdef __cplusplus diff --git a/include/metalsvm/stdlib.h b/include/metalsvm/stdlib.h index 8703e98b..174f6f9c 100644 --- a/include/metalsvm/stdlib.h +++ b/include/metalsvm/stdlib.h @@ -21,6 +21,7 @@ #define __STDLIB_H__ #include +#include #include #ifdef __cplusplus @@ -28,6 +29,9 @@ extern "C" { #endif void NORETURN abort(void); +void* kmalloc(size_t); +void kfree(void*, size_t); +void* create_stack(task_t* task, size_t sz); #ifdef __cplusplus } diff --git a/include/metalsvm/tasks.h b/include/metalsvm/tasks.h index f97c6cd8..c88c8228 100644 --- a/include/metalsvm/tasks.h +++ b/include/metalsvm/tasks.h @@ -32,8 +32,8 @@ extern "C" { extern task_t* current_task; int multitasking_init(void); -int create_kernel_task(tid_t*, entry_point_t, void*); -int joint_kernel_task(tid_t); +int create_kernel_task(tid_t*, entry_point_t, void*, size_t); +int join_kernel_task(tid_t); void schedule(void); task_t* get_new_task(void); diff --git a/include/metalsvm/tasks_types.h b/include/metalsvm/tasks_types.h index 8cf2ca79..5a028e33 100644 --- a/include/metalsvm/tasks_types.h +++ b/include/metalsvm/tasks_types.h @@ -22,6 +22,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -31,6 +32,7 @@ extern "C" { #define TASK_READY 1 #define TASK_RUNNING 2 #define TASK_BLOCKED 3 +#define TASK_FINISHED 4 typedef void* (STDCALL *entry_point_t)(void*); typedef unsigned int tid_t; @@ -39,6 +41,9 @@ typedef struct { unsigned char* top; unsigned int ip; tid_t id; + mm_t mm; + unsigned char* stack; + size_t stack_size; unsigned char status; unsigned char idle; } task_t; diff --git a/kernel/main.c b/kernel/main.c index e2d00bb5..886dc648 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -47,11 +47,12 @@ int main(void) { tid_t id1, id2; - mmu_init(); + system_init(); irq_init(); koutput_init(); timer_init(); keyboard_init(); + mmu_init(); multitasking_init(); irq_enable(); @@ -60,11 +61,12 @@ int main(void) detect_cpu_frequency(); kprintf("Processor frequency: %d MHz\n", get_cpu_frequency()/1000000); + kprintf("Kernel size: %u KBytes\n", atomic_size_read(&total_usage)/1024); timer_set_frequency(TIMER_FREQ); - create_kernel_task(&id1, foo, "Hello from foo1\n"); - create_kernel_task(&id2, foo, "Hello from foo2\n"); + create_kernel_task(&id1, foo, "Hello from foo1\n", 8192); + create_kernel_task(&id2, foo, "Hello from foo2\n", 0); current_task->idle = 1; schedule(); diff --git a/kernel/tasks.c b/kernel/tasks.c index 825c2f13..f6e2e282 100644 --- a/kernel/tasks.c +++ b/kernel/tasks.c @@ -27,11 +27,13 @@ task_t* current_task = NULL; static task_t task_table[MAX_TASKS]; -static unsigned char stacks[MAX_TASKS][DEFAULT_STACK_SIZE]; int multitasking_init(void) { memset(task_table, 0, sizeof(task_t)*MAX_TASKS); task_table[0].id = 0; + task_table[0].mm.usage = 0; + task_table[0].stack = NULL; + task_table[0].stack_size = 8192; task_table[0].status = TASK_RUNNING; task_table[0].idle = 0; current_task = task_table; @@ -41,7 +43,7 @@ int multitasking_init(void) { void NORETURN leave_task(void) { kprintf("Terminate task: %u\n", current_task->id); - current_task->status = TASK_INVALID; + current_task->status = TASK_FINISHED; schedule(); kputs("Kernel panic: scheduler found no valid task\n"); @@ -53,7 +55,7 @@ void NORETURN leave_task(void) { void NORETURN abort(void) { kprintf("Abbort task: %u\n", current_task->id); - current_task->status = TASK_INVALID; + current_task->status = TASK_FINISHED; schedule(); kputs("Kernel panic: scheduler found no valid task\n"); @@ -62,7 +64,7 @@ void NORETURN abort(void) { } } -int create_kernel_task(tid_t* id, entry_point_t ep, void* arg) +int create_kernel_task(tid_t* id, entry_point_t ep, void* arg, size_t stack_size) { int ret = -1; unsigned int i; @@ -70,20 +72,32 @@ int create_kernel_task(tid_t* id, entry_point_t ep, void* arg) if (BUILTIN_EXPECT(!ep, 0)) return -1; + if (!stack_size) + stack_size = DEFAULT_STACK_SIZE; + irq_disable(); for(i=0; istatus == TASK_FINISHED) + current_task = TASK_INVALID; + for(i=1; i <= MAX_TASKS; i++) { new_id = (current_task->id + i) % MAX_TASKS; diff --git a/link.ld b/link.ld index d5cc6cec..e8573ddb 100644 --- a/link.ld +++ b/link.ld @@ -1,6 +1,7 @@ OUTPUT_FORMAT("binary") ENTRY(start) phys = 0x00100000; +kernel_start = .; SECTIONS { .text phys : AT(phys) { @@ -24,3 +25,5 @@ SECTIONS } end = .; } +. = ALIGN(4096); +kernel_end = .; diff --git a/mm/Makefile b/mm/Makefile index a0e7814e..39df0f6e 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -1,4 +1,4 @@ -C_source = init.c +C_source = alloc.c OBJS += $(patsubst %.c, %.o, $(filter %.c, $(C_source))) diff --git a/mm/alloc.c b/mm/alloc.c new file mode 100644 index 00000000..516f7b21 --- /dev/null +++ b/mm/alloc.c @@ -0,0 +1,181 @@ +/* + * Copyright 2010 Stefan Lankes, Chair for Operating Systems, + * RWTH Aachen University + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of MetalSVM. + */ + +#include +#include +#include +#include + +/* + * 0 => free + * 1 => occupied + */ +static uint8_t bitmap[BITMAP_SIZE]; +static spinlock_t bitmap_lock = SPINLOCK_INIT; +static size_t alloc_start; +atomic_size_t total_usage; + +extern const void kernel_start; +extern const void kernel_end; + +inline static int page_used(unsigned int i) +{ + unsigned int index = i / 8; + unsigned int mod = i % 8; + + return (bitmap[index] & (1 << mod)); +} + +inline static int page_unused(unsigned int i) +{ + return !page_used(i); +} + +inline static void page_marked(unsigned int i) +{ + unsigned int index = i / 8; + unsigned int mod = i % 8; + + bitmap[index] = bitmap[index] | (1 << mod); +} + +inline static void page_unmarked(unsigned int i) +{ + unsigned int index = i / 8; + unsigned int mod = i % 8; + + if (page_unused(i)) + kprintf("page %u is already unmarked\n", i); + + bitmap[index] = bitmap[index] & ~(1 << mod); +} + +void mmu_init(void) +{ + size_t kernel_size; + unsigned int i; + + memset(bitmap, 0x00, sizeof(uint8_t)*BITMAP_SIZE); + + /* kernel is aligned to page size */ + kernel_size = (size_t) &kernel_end - (size_t) &kernel_start; + atomic_size_set(&total_usage, kernel_size); + + for(i=(size_t) &kernel_start / PAGE_SIZE; i < (size_t) &kernel_end / PAGE_SIZE; i++) + page_marked(i); + + alloc_start = (unsigned int) (&kernel_end) / PAGE_SIZE + 1; +} + +static void* task_malloc(task_t* task, size_t sz) +{ + unsigned int i, j, l; + unsigned int k = 0; + unsigned char* ret = NULL; + unsigned int npages; + + if (BUILTIN_EXPECT(!sz, 0)) + return ret; + + npages = sz / PAGE_SIZE; + if (sz % PAGE_SIZE) + npages++; + + spinlock_lock(&bitmap_lock); + i = alloc_start; +next_try: + while((k < BITMAP_SIZE) && page_used(i)) { + k++; + i = (i+1) % BITMAP_SIZE; + } + + if (k >= BITMAP_SIZE) + goto oom; + + for(j=1; (j= BITMAP_SIZE) { + i = 0; + goto next_try; + } + + if (k >= BITMAP_SIZE) + goto oom; + + ret = (unsigned char*) (i*PAGE_SIZE); + kprintf("alloc: ret %p, i = %d, j = %di, npages = %d\n", ret, i, j, npages); + for(l=i; lmm.usage), npages*PAGE_SIZE); +oom: + spinlock_unlock(&bitmap_lock); + + return ret; +} + +void* kmalloc(size_t sz) +{ + return task_malloc(current_task, sz); +} + +void* create_stack(task_t* task, size_t sz) +{ + unsigned char* addr = (unsigned char*) task_malloc(task, sz); + + memset(addr, 0xCD, sz); + + return addr; +} + +static void task_free(task_t* task, void* addr, size_t sz) +{ + unsigned int index, npages, i; + + if (BUILTIN_EXPECT(!addr && !sz, 0)) + return; + + index = (size_t) addr / PAGE_SIZE; + npages = sz / PAGE_SIZE; + if (sz % PAGE_SIZE) + npages++; + + spinlock_lock(&bitmap_lock); + + for(i=index; imm.usage), npages*PAGE_SIZE); + + spinlock_unlock(&bitmap_lock); +} + +void kfree(void* addr, size_t sz) +{ + task_free(current_task, addr, sz); +} diff --git a/mm/init.c b/mm/init.c deleted file mode 100644 index 2c5b2b11..00000000 --- a/mm/init.c +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2010 Stefan Lankes, Chair for Operating Systems, - * RWTH Aachen University - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * This file is part of MetalSVM. - */ - -#include -#include - -void mmu_init(void) -{ - mmu_arch_init(); -}