/* * 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 #include #include #ifdef CONFIG_MULTIBOOT #include #endif #ifdef CONFIG_ROCKCREEK #include #endif /* * 0 => free * 1 => occupied * * Set whole address space as occupied */ static uint8_t bitmap[BITMAP_SIZE] = {[0 ... BITMAP_SIZE-1] = 0xFF}; static spinlock_t bitmap_lock = SPINLOCK_INIT; static size_t alloc_start; atomic_int32_t total_pages = ATOMIC_INIT(0); atomic_int32_t total_allocated_pages = ATOMIC_INIT(0); atomic_int32_t total_available_pages = ATOMIC_INIT(0); extern const void kernel_start; extern const void kernel_end; inline static int page_marked(unsigned int i) { unsigned int index = i / 8; unsigned int mod = i % 8; return (bitmap[index] & (1 << mod)); } inline static int page_unmarked(unsigned int i) { return !page_marked(i); } inline static void page_set_mark(unsigned int i) { unsigned int index = i / 8; unsigned int mod = i % 8; //if (page_marked(i)) // kprintf("page %u is alread marked\n", i); bitmap[index] = bitmap[index] | (1 << mod); } inline static void page_clear_mark(unsigned int i) { unsigned int index = i / 8; unsigned int mod = i % 8; if (page_unmarked(i)) kprintf("page %u is already unmarked\n", i); bitmap[index] = bitmap[index] & ~(1 << mod); } int mmu_init(void) { size_t kernel_size; unsigned int i; size_t addr, end_addr; #ifdef CONFIG_MULTIBOOT if (mb_info && (mb_info->flags & (1 << 6))) { multiboot_memory_map_t* mmap = (multiboot_memory_map_t*) mb_info->mmap_addr; multiboot_memory_map_t* mmap_end = (void*) ((size_t) mb_info->mmap_addr + mb_info->mmap_length); while (mmap < mmap_end) { if (mmap->type == MULTIBOOT_MEMORY_AVAILABLE) { /* set the available memory as "unused" */ addr = mmap->addr; end_addr = addr + mmap->len; while (addr < end_addr) { page_clear_mark(addr / PAGE_SIZE); addr += PAGE_SIZE; atomic_int32_inc(&total_pages); atomic_int32_inc(&total_available_pages); } } mmap++; } } else { kputs("Unable to initialize the memory management subsystem\n"); while(1) ; } /* * Modules like the init ram disk are already loaded. * Therefore, we set these pages as used. */ if (mb_info && (mb_info->flags & (1 << 3))) { multiboot_module_t* mmodule = (multiboot_module_t*) mb_info->mods_addr; for(i=0; imods_count; i++, mmodule++) { for(addr=mmodule->mod_start; addrmod_end; addr+=PAGE_SIZE) { page_set_mark(addr / PAGE_SIZE); atomic_int32_inc(&total_allocated_pages); atomic_int32_dec(&total_available_pages); } } } #elif defined(CONFIG_ROCKCREEK) for(i=0; i= 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 = %d, npages = %d\n", ret, i, j, npages); for(l=i; lmem_usage), npages); oom: spinlock_unlock(&bitmap_lock); return ret; } void* kmalloc(size_t sz) { return task_malloc(per_core(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; imem_usage), npages); spinlock_unlock(&bitmap_lock); } void kfree(void* addr, size_t sz) { task_free(per_core(current_task), addr, sz); }