- 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:
parent
d2293f130d
commit
0aea73bdc7
15 changed files with 251 additions and 80 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -27,7 +27,8 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#define EUNKNOWN 1 /* Out of memory */
|
||||
#define ENOMEM 2 /* Out of memory */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
3
link.ld
3
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 = .;
|
||||
|
|
|
@ -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
181
mm/alloc.c
Normal 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);
|
||||
}
|
26
mm/init.c
26
mm/init.c
|
@ -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();
|
||||
}
|
Loading…
Add table
Reference in a new issue