- 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
This commit is contained in:
stefan 2010-08-02 07:43:56 +00:00
parent d2293f130d
commit 0aea73bdc7
15 changed files with 251 additions and 80 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -27,7 +27,8 @@
extern "C" {
#endif
#define EUNKNOWN 1 /* Out of memory */
#define ENOMEM 2 /* Out of memory */
#ifdef __cplusplus
}

View file

@ -20,12 +20,20 @@
#ifndef __MMU_H__
#define __MMU_H__
#include <asm/mmu.h>
#include <metalsvm/stddef.h>
#include <asm/atomic.h>
//#include <asm/mmu.h>
#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

View file

@ -21,6 +21,7 @@
#define __STDLIB_H__
#include <metalsvm/config.h>
#include <metalsvm/tasks_types.h>
#include <asm/stddef.h>
#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
}

View file

@ -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);

View file

@ -22,6 +22,7 @@
#include <metalsvm/config.h>
#include <metalsvm/stddef.h>
#include <metalsvm/mmu.h>
#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;

View file

@ -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();

View file

@ -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; i<MAX_TASKS; i++) {
if (task_table[i].status == TASK_INVALID) {
if (id)
*id = i;
task_table[i].top = stacks[i] + DEFAULT_STACK_SIZE - sizeof(size_t);
if (task_table[i].stack)
kfree(task_table[i].stack, task_table[i].stack_size);
if (task_table[i].mm.usage) {
kprintf("Task %d has a memory leax (%d byte)\n", task_table[i].id, task_table[i].mm.usage);
task_table[i].mm.usage = 0;
}
task_table[i].stack = create_stack(task_table+i, stack_size);
if (!task_table[i].stack)
break;
task_table[i].stack_size = stack_size;
task_table[i].top = task_table[i].stack + stack_size - sizeof(size_t);
task_table[i].ip = 0;
task_table[i].id = i;
task_table[i].status = TASK_READY;
task_table[i].idle = 0;
memset(stacks[i], 0xCD, DEFAULT_STACK_SIZE);
if (id)
*id = i;
ret = create_default_frame(task_table+i, ep, arg);
break;
}
@ -103,6 +117,10 @@ task_t* get_new_task(void)
{
unsigned int i, new_id;
/* signalize that this task could be reuse */
if (current_task->status == TASK_FINISHED)
current_task = TASK_INVALID;
for(i=1; i <= MAX_TASKS; i++) {
new_id = (current_task->id + i) % MAX_TASKS;

View file

@ -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 = .;

View file

@ -1,4 +1,4 @@
C_source = init.c
C_source = alloc.c
OBJS += $(patsubst %.c, %.o, $(filter %.c, $(C_source)))

181
mm/alloc.c Normal file
View file

@ -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 <metalsvm/stdio.h>
#include <metalsvm/string.h>
#include <metalsvm/mmu.h>
#include <metalsvm/spinlocks.h>
/*
* 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<npages) && (i+j < BITMAP_SIZE) && (k < BITMAP_SIZE); j++, k++) {
if (page_used(i+j)) {
i = (i+j) % BITMAP_SIZE;
goto next_try;
}
}
if (i+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; l<i+j; l++)
page_marked(l);
alloc_start = i+j-1;
atomic_size_add(&total_usage, npages*PAGE_SIZE);
if (task)
atomic_size_add(&(task->mm.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; i<index+npages; i++)
page_unmarked(i);
atomic_size_sub(&total_usage, npages*PAGE_SIZE);
if (task)
atomic_size_sub(&(task->mm.usage), npages*PAGE_SIZE);
spinlock_unlock(&bitmap_lock);
}
void kfree(void* addr, size_t sz)
{
task_free(current_task, addr, sz);
}

View file

@ -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 <metalsvm/stdio.h>
#include <metalsvm/mmu.h>
void mmu_init(void)
{
mmu_arch_init();
}