summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick Williams <iawillia@us.ibm.com>2010-05-20 19:16:30 -0500
committerPatrick Williams <iawillia@us.ibm.com>2010-05-20 19:16:30 -0500
commitd9d7e6c7247aaf5d2721d08a365e9c51ec18c870 (patch)
tree16f882f7d77eb293ac0417b43bb5680ee149efbd
parentd5a43e2fa43f8178aaa7ca67a9615d3ab4e68dbb (diff)
downloadtalos-hostboot-d9d7e6c7247aaf5d2721d08a365e9c51ec18c870.tar.gz
talos-hostboot-d9d7e6c7247aaf5d2721d08a365e9c51ec18c870.zip
Create page manager.
-rw-r--r--src/include/kernel/pagemgr.H42
-rw-r--r--src/include/stddef.h12
-rw-r--r--src/include/stdint.h2
-rw-r--r--src/kernel.ld6
-rw-r--r--src/kernel/kernel.C18
-rw-r--r--src/kernel/makefile2
-rw-r--r--src/kernel/pagemgr.C124
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);
+}
OpenPOWER on IntegriCloud