diff options
author | Patrick Williams <iawillia@us.ibm.com> | 2010-05-20 19:16:30 -0500 |
---|---|---|
committer | Patrick Williams <iawillia@us.ibm.com> | 2010-05-20 19:16:30 -0500 |
commit | d9d7e6c7247aaf5d2721d08a365e9c51ec18c870 (patch) | |
tree | 16f882f7d77eb293ac0417b43bb5680ee149efbd /src/kernel | |
parent | d5a43e2fa43f8178aaa7ca67a9615d3ab4e68dbb (diff) | |
download | talos-hostboot-d9d7e6c7247aaf5d2721d08a365e9c51ec18c870.tar.gz talos-hostboot-d9d7e6c7247aaf5d2721d08a365e9c51ec18c870.zip |
Create page manager.
Diffstat (limited to 'src/kernel')
-rw-r--r-- | src/kernel/kernel.C | 18 | ||||
-rw-r--r-- | src/kernel/makefile | 2 | ||||
-rw-r--r-- | src/kernel/pagemgr.C | 124 |
3 files changed, 138 insertions, 6 deletions
diff --git a/src/kernel/kernel.C b/src/kernel/kernel.C index d44095719..2ce5f3e43 100644 --- a/src/kernel/kernel.C +++ b/src/kernel/kernel.C @@ -1,11 +1,13 @@ #include <stdint.h> #include <kernel/console.H> +#include <kernel/pagemgr.H> #include <util/singleton.H> class Kernel { public: void cppBootstrap(); + void memBootstrap(); protected: Kernel() {}; @@ -13,10 +15,11 @@ class Kernel int main() { - printk("Booting Chenoo kernel...\n"); + printk("Booting %s kernel...\n\n", "Chenoo"); Kernel& kernel = Singleton<Kernel>::instance(); kernel.cppBootstrap(); + kernel.memBootstrap(); while(1); return 0; @@ -25,13 +28,18 @@ int main() void Kernel::cppBootstrap() { // Call default constructors for any static objects. - extern void (*ctor_start)(); - extern void (*ctor_end)(); - void(**ctors)() = &ctor_start; - while(ctors != &ctor_end) + extern void (*ctor_start_address)(); + extern void (*ctor_end_address)(); + void(**ctors)() = &ctor_start_address; + while(ctors != &ctor_end_address) { (*ctors)(); ctors++; } } +void Kernel::memBootstrap() +{ + PageManager::freePage(PageManager::allocatePage()); +} + diff --git a/src/kernel/makefile b/src/kernel/makefile index 1047de456..c4cf3c421 100644 --- a/src/kernel/makefile +++ b/src/kernel/makefile @@ -1,7 +1,7 @@ OBJDIR = ../../obj include ../../config.mk -OBJS = start.o kernel.o console.o +OBJS = start.o kernel.o console.o pagemgr.o OBJECTS = $(addprefix ${OBJDIR}/, ${OBJS}) all: ${OBJECTS} diff --git a/src/kernel/pagemgr.C b/src/kernel/pagemgr.C new file mode 100644 index 000000000..e5d9ec321 --- /dev/null +++ b/src/kernel/pagemgr.C @@ -0,0 +1,124 @@ +#include <kernel/pagemgr.H> +#include <util/singleton.H> +#include <kernel/console.H> + +void* PageManager::allocatePage(size_t n) +{ + PageManager& pmgr = Singleton<PageManager>::instance(); + return pmgr._allocatePage(n); +} + +void PageManager::freePage(void* p, size_t n) +{ + PageManager& pmgr = Singleton<PageManager>::instance(); + return pmgr._freePage(p, n); +} + +PageManager::PageManager() +{ + // NOTE: This will need to change once we support loading modules. + + // Determine first page of un-allocated memory. + extern void* end_load_address; + uint64_t addr = (uint64_t)&end_load_address; + if (0 != (addr % PAGESIZE)) + addr = (addr - (addr % PAGESIZE)) + PAGESIZE; + + // Determine number of pages available. + page_t* page = (page_t*)((void*) addr); + size_t length = (MEMLEN - addr) / PAGESIZE; + + // Display. + printk("Initializing PageManager with %zd pages starting at %llx...", + length, + (uint64_t)page); + + // Clear page buckets. + for(int i = 0; i < BUCKETS; i++) + first_page[i] = NULL; + + // Allocate pages to buckets. + size_t page_length = BUCKETS-1; + while(length > 0) + { + while (length < (1 << page_length)) + page_length--; + + page->next_page = first_page[page_length]; + first_page[page_length] = page; + page = (page_t*)((uint64_t)page + (1 << page_length)*PAGESIZE); + length -= (1 << page_length); + } + + printk("done\n"); +} + +void* PageManager::_allocatePage(size_t n) +{ + int which_bucket = 0; + while (n > (1 << which_bucket)) which_bucket++; + + int retries = 0; + page_t* page = (page_t*)NULL; + while ((page == NULL) && (retries < 3)) + { + page = pop_bucket(which_bucket); + retries++; + } + + if (NULL == page) + { + // TODO: Add abort instead. + printk("Insufficient memory for allocation of size %zd!\n", n); + while(1); + } + + return page; +} + +void PageManager::_freePage(void* p, size_t n) +{ + if ((NULL == p) || (0 == n)) return; + + int which_bucket = 0; + while (n > (1 << which_bucket)) which_bucket++; + + push_bucket((page_t*)p, which_bucket); + return; +} + +PageManager::page_t* PageManager::pop_bucket(size_t n) +{ + if (n >= BUCKETS) return NULL; + + page_t* p = first_page[n]; + + if (NULL == p) + { + // Couldn't allocate from the correct size bucket, so split up an + // item from the next sized bucket. + p = pop_bucket(n+1); + push_bucket((page_t*) (((uint64_t)p) + (PAGESIZE * (1 << n))), + n); + } + else + { + // This bucket appears to have items in it, allocate one. + if (!__sync_bool_compare_and_swap(&first_page[n], + p, + p->next_page)) + return pop_bucket(n); + } + return p; +} + +void PageManager::push_bucket(page_t* p, size_t n) +{ + if (n >= BUCKETS) return; + + p->next_page = first_page[n]; + if (!__sync_bool_compare_and_swap(&first_page[n], + p->next_page, + p)) + push_bucket(p, n); +} |