summaryrefslogtreecommitdiff
path: root/kernel/memory.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/memory.c')
-rw-r--r--kernel/memory.c129
1 files changed, 129 insertions, 0 deletions
diff --git a/kernel/memory.c b/kernel/memory.c
new file mode 100644
index 0000000..465b44f
--- /dev/null
+++ b/kernel/memory.c
@@ -0,0 +1,129 @@
+#include <kernel/memory.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+static char __attribute__((aligned (4096))) mapped_page[4096];
+
+static pdir_t kpdir;
+
+ptab_t ktab;
+
+static ptab_t flow;
+static ptab_t fupp;
+
+void *alloc_physical_page(void) {
+ int i;
+ void *ret;
+
+ for(i = 0; i < PGENT; i++) {
+ if(flow[i] & 1) {
+ ret = (void*) (flow[i] & ~1);
+ flow[i] = 0;
+ return ret;
+ }
+
+ if(fupp[i] & 1) {
+ ret = (void*) (fupp[i] & ~1);
+ fupp[i] = 0;
+ return ret;
+ }
+ }
+
+ return NULL;
+}
+
+int free_physical_page(void *page) {
+ int i;
+ page = (void*) ((uint32_t) page & ~0xFFF);
+
+ for(int i = 0; i < PGENT; i++) {
+ if(!(flow[i] & 1)) {
+ flow[i] = (uint32_t) page | 1;
+ return 0;
+ }
+
+ if(!(fupp[i] & 1)) {
+ fupp[i] = (uint32_t) page | 1;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+void *alloc_physical_pages(unsigned int n) {
+ void *p = NULL;
+ void *last = NULL;
+ void **page;
+
+ while(n--) {
+ p = alloc_physical_page();
+ if(p == NULL) {
+ page = &last;
+ while(*page) {
+ free_physical_page(*page);
+ page = *page;
+ }
+ return NULL;
+ }
+
+ map_page(p);
+ *((void**) mapped_page) = last;
+ last = p;
+ }
+
+ return p;
+}
+
+void *map_page(void *page) {
+ uint32_t p = (uint32_t) mapped_page;
+
+ /* enforce 4KB page alignment */
+ page = (void*) ((uint32_t) page & ~0xFFF);
+
+ ktab[(p >> 12) & 0x3FF] = (uint32_t) page | 0x003;
+ /*
+ * invalidate any cached entries for
+ * the mapped page window.
+ */
+ __asm__ ("invlpg %0" :: "m" (mapped_page));
+
+ return mapped_page;
+}
+
+void paging_init(void) {
+ int i;
+
+ /* empty the page directory */
+ for(i = 0; i < PGENT; i++)
+ kpdir[i] = 0;
+
+ /* populate the free page tables */
+ for(i = 0; i < PGENT; i++) {
+ /* populate the lower table */
+ flow[i] = (i << 12);
+ /* only pages >1MB can be allocated */
+ if(i >= 0x100)
+ flow[i] |= 0x001;
+ /* populate the upper table */
+ fupp[i] = ((i << 12) + 0x400000) | 0x001;
+ }
+
+ /* populate the kernel's page table */
+ for(i = 0; i < PGENT; i++) {
+ ktab[i] = 0;
+ if(i < 256)
+ ktab[i] = (i << 12) | 0x003;
+ }
+
+ /* populate the kernel's page directory */
+ kpdir[0] = ((pde_t) ktab) | 0x007;
+
+ __asm__ (
+ "mov %%eax, %%cr3\n"
+ "mov %%cr0, %%eax\n"
+ "or $0x80000000, %%eax\n"
+ "mov %%eax, %%cr0\n"
+ :: "a" (&kpdir)
+ :);
+}