/* * Copyright (c) 2010, Stefan Lankes, RWTH Aachen University * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include /* * Note that linker symbols are not variables, they have no memory allocated for * maintaining a value, rather their address is their value. */ extern const void kernel_start; extern const void kernel_end; static char stack[MAX_TASKS-1][KERNEL_STACK_SIZE]; static char bitmap[BITMAP_SIZE]; static spinlock_t bitmap_lock = SPINLOCK_INIT; 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); void* create_stack(tid_t id) { // idle task uses stack, which is defined in entry.asm if (BUILTIN_EXPECT(!id, 0)) return NULL; // do we have a valid task id? if (BUILTIN_EXPECT(id >= MAX_TASKS, 0)) return NULL; return (void*) stack[id-1]; } inline static int page_marked(size_t i) { size_t index = i >> 3; size_t mod = i & 0x7; return (bitmap[index] & (1 << mod)); } inline static void page_set_mark(size_t i) { size_t index = i >> 3; size_t mod = i & 0x7; bitmap[index] = bitmap[index] | (1 << mod); } inline static void page_clear_mark(size_t i) { size_t index = i / 8; size_t mod = i % 8; bitmap[index] = bitmap[index] & ~(1 << mod); } size_t get_pages(size_t npages) { size_t cnt, off; if (BUILTIN_EXPECT(!npages, 0)) return 0; if (BUILTIN_EXPECT(npages > atomic_int32_read(&total_available_pages), 0)) return 0; spinlock_lock(&bitmap_lock); off = 1; while (off <= BITMAP_SIZE*8 - npages) { for (cnt=0; cnt> PAGE_BITS; if (BUILTIN_EXPECT(!phyaddr, 0)) return -EINVAL; if (BUILTIN_EXPECT(!npages, 0)) return -EINVAL; spinlock_lock(&bitmap_lock); for (i=0; iflags & MULTIBOOT_INFO_MEM_MAP) { multiboot_memory_map_t* mmap = (multiboot_memory_map_t*) ((size_t) mb_info->mmap_addr); multiboot_memory_map_t* mmap_end = (void*) ((size_t) mb_info->mmap_addr + mb_info->mmap_length); // mark available memory as free while (mmap < mmap_end) { if (mmap->type == MULTIBOOT_MEMORY_AVAILABLE) { for (addr=mmap->addr; addr < mmap->addr + mmap->len; addr += PAGE_SIZE) { page_clear_mark(addr >> PAGE_BITS); atomic_int32_inc(&total_pages); atomic_int32_inc(&total_available_pages); } } mmap++; } } else if (mb_info->flags & MULTIBOOT_INFO_MEM) { size_t page; size_t pages_lower = mb_info->mem_lower >> 2; /* KiB to page number */ size_t pages_upper = mb_info->mem_upper >> 2; for (page=0; page> PAGE_BITS); atomic_int32_inc(&total_allocated_pages); atomic_int32_dec(&total_available_pages); if (mb_info->flags & MULTIBOOT_INFO_MODS) { // mark modules list as used for(addr=mb_info->mods_addr; addrmods_addr+mb_info->mods_count*sizeof(multiboot_module_t); addr+=PAGE_SIZE) { page_set_mark(addr >> PAGE_BITS); atomic_int32_inc(&total_allocated_pages); atomic_int32_dec(&total_available_pages); } // mark modules as used multiboot_module_t* mmodule = (multiboot_module_t*) ((size_t) mb_info->mods_addr); for(i=0; imods_count; i++) { for(addr=mmodule[i].mod_start; addr> PAGE_BITS); atomic_int32_inc(&total_allocated_pages); atomic_int32_dec(&total_available_pages); } } } } // mark kernel as used for(addr=(size_t) &kernel_start; addr<(size_t) &kernel_end; addr+=PAGE_SIZE) { page_set_mark(addr >> PAGE_BITS); atomic_int32_inc(&total_allocated_pages); atomic_int32_dec(&total_available_pages); } // enable paging and map SMP, VGA, Multiboot modules etc. ret = page_init(); if (BUILTIN_EXPECT(ret, 0)) { kputs("Failed to initialize paging!\n"); return ret; } return ret; }