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 | |
parent | d5a43e2fa43f8178aaa7ca67a9615d3ab4e68dbb (diff) | |
download | talos-hostboot-d9d7e6c7247aaf5d2721d08a365e9c51ec18c870.tar.gz talos-hostboot-d9d7e6c7247aaf5d2721d08a365e9c51ec18c870.zip |
Create page manager.
Diffstat (limited to 'src')
-rw-r--r-- | src/include/kernel/pagemgr.H | 42 | ||||
-rw-r--r-- | src/include/stddef.h | 12 | ||||
-rw-r--r-- | src/include/stdint.h | 2 | ||||
-rw-r--r-- | src/kernel.ld | 6 | ||||
-rw-r--r-- | src/kernel/kernel.C | 18 | ||||
-rw-r--r-- | src/kernel/makefile | 2 | ||||
-rw-r--r-- | src/kernel/pagemgr.C | 124 |
7 files changed, 198 insertions, 8 deletions
diff --git a/src/include/kernel/pagemgr.H b/src/include/kernel/pagemgr.H new file mode 100644 index 000000000..1d7193b22 --- /dev/null +++ b/src/include/kernel/pagemgr.H @@ -0,0 +1,42 @@ +#ifndef __KERNEL_PAGEMGR_H +#define __KERNEL_PAGEMGR_H + +#include <stdint.h> + +/** @class PageManager + * @brief Manages the allocation of memory pages. + */ + +class PageManager +{ + public: + static void* allocatePage(size_t n = 1); + static void freePage(void*, size_t n = 1); + + enum + { + PAGESIZE = 4096, + MEMLEN = 8 * 1024 * 1024, + + BUCKETS = 16, + }; + + protected: + PageManager(); + ~PageManager() {}; + + private: + void* _allocatePage(size_t); + void _freePage(void*, size_t); + + struct page_t + { + page_t* next_page; + }; + page_t* first_page[BUCKETS]; + + page_t* pop_bucket(size_t); + void push_bucket(page_t*, size_t); +}; + +#endif diff --git a/src/include/stddef.h b/src/include/stddef.h new file mode 100644 index 000000000..10c28e361 --- /dev/null +++ b/src/include/stddef.h @@ -0,0 +1,12 @@ +#ifndef __STDDEF_H +#define __STDDEF_H + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void*)0) +#endif +#endif + +#endif diff --git a/src/include/stdint.h b/src/include/stdint.h index f5a30a9f5..1b7328d80 100644 --- a/src/include/stdint.h +++ b/src/include/stdint.h @@ -1,6 +1,8 @@ #ifndef __STDINT_H #define __STDINT_H +#include <stddef.h> + typedef char int8_t; typedef short int int16_t; typedef int int32_t; diff --git a/src/kernel.ld b/src/kernel.ld index 01fad2522..b3749aefb 100644 --- a/src/kernel.ld +++ b/src/kernel.ld @@ -18,9 +18,9 @@ SECTIONS *(.rodata) *(.rodata.*) . = ALIGN(0x8); - ctor_start = .; + ctor_start_address = .; *(.ctors) - ctor_end = .; + ctor_end_address = .; } @@ -41,6 +41,8 @@ SECTIONS } + end_load_address = .; + . = hreset_load_address; .text.hreset : { *(.text.hreset) 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); +} |