aboutsummaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/CMakeLists.txt1
-rw-r--r--kernel/include/common.h11
-rw-r--r--kernel/include/mm/virtual_mm.h45
-rw-r--r--kernel/kernel/kernel.c4
-rw-r--r--kernel/mm/virtual_mm/virtual_mm.c104
5 files changed, 146 insertions, 19 deletions
diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt
index 204295d..72365fb 100644
--- a/kernel/CMakeLists.txt
+++ b/kernel/CMakeLists.txt
@@ -38,6 +38,7 @@ set(C_COMPILE_OPTIONS
-Wall
-Wextra
-pedantic
+ -Werror
-g
)
diff --git a/kernel/include/common.h b/kernel/include/common.h
index 9fa2011..2e1faa3 100644
--- a/kernel/include/common.h
+++ b/kernel/include/common.h
@@ -26,7 +26,14 @@
#define MiB (KiB * KiB)
#define ASSERT_NOT_REACHED() \
- printk("ASSERTION FAILED", "[%s] SHOULD NOT BE REACHED.", __func__); \
- halt();
+ { \
+ printk("ASSERTION FAILED", \
+ "[%s]:%lu SHOULD NOT BE REACHED.", \
+ __func__, \
+ __LINE__); \
+ /* TODO: We should probably remove this exit() eventually */ \
+ exit(); \
+ halt(); \
+ }
#endif
diff --git a/kernel/include/mm/virtual_mm.h b/kernel/include/mm/virtual_mm.h
index 3f938d2..ad2b961 100644
--- a/kernel/include/mm/virtual_mm.h
+++ b/kernel/include/mm/virtual_mm.h
@@ -29,20 +29,22 @@
#define PAGE_DIRECTORY_INDEX(virtual_address) ((virtual_address >> 22) & 0x3ff)
#define PAGE_TABLE_INDEX(virtual_address) ((virtual_address >> 12) & 0x3ff)
-#define PDE_PRESENT 1
-#define PDE_WRITABLE (1 << 1)
-#define PDE_USER (1 << 2)
-#define PDE_WRITETHROUGH (1 << 3)
-#define PDE_CACHE_DISABLE (1 << 4)
-#define PDE_ACCESSED (1 << 5)
+#define SET_PDE_PRESENT(x) x
+#define SET_PDE_WRITABLE(x) (x << 1)
+#define SET_PDE_USER(x) (x << 2)
+#define SET_PDE_WRITETHROUGH(x) (x << 3)
+#define SET_PDE_CACHE_DISABLE(x) (x << 4)
+#define SET_PDE_ACCESSED(x) (x << 5)
/* Never set (reserved by Intel) */
-#define PDE_RESERVED (0 << 6)
-#define PDE_PAGE_SIZE (1 << 7)
-#define PDE_GLOBAL (1 << 8)
+#define SET_PDE_RESERVED(x) (x << 6)
+#define SET_PDE_PAGE_SIZE(x) (x << 7)
+#define SET_PDE_GLOBAL(x) (x << 8)
/* NOTE: Unused by the CPU, free to be used by us! */
-#define PDE_UNUSED(x) (x << 9)
+#define SET_PDE_UNUSED(x) (x << 9)
/* Page table address */
-#define PDE_FRAME(x) (x << 11)
+#define SET_PDE_FRAME(x) (x << 11)
+
+#define GET_PDE_FRAME(x) (*x >> 11)
#define SET_PTE_PRESENT(x) x
#define SET_PTE_WRITABLE(x) (x << 1)
@@ -58,6 +60,7 @@
/* MAX: 0xFFFFF000 */
#define SET_PTE_FRAME(x) (x << 11)
+#define PTE_IS_PRESENT(x) (x & 1)
#define GET_PTE_FRAME(x) (*x >> 11)
#define ADD_ATTRIB(entry, attribute) (*entry |= (attribute))
@@ -92,4 +95,24 @@ uint32_t *virtual_mm_lookup_directory(uint32_t *page_directory,
*/
void virtual_mm_load_page_directory(uint32_t *page_directory);
+/*
+ * Switches the current page directory to a given page directory
+ */
+bool virtual_mm_switch_page_directory(uint32_t *page_directory);
+
+/*
+ * Flushes the given TLB entry
+ */
+void virtual_mm_flush_tlb_entry(uint32_t *virtual_addr);
+
+/*
+ * Map a given physical address to a virtual address
+ */
+bool virtual_mm_map_page(uint32_t *physical_addr, uint32_t *virtual_addr);
+
+/*
+ * Initialize the virtual memory manager
+ */
+void virtual_mm_initialize(void);
+
#endif
diff --git a/kernel/kernel/kernel.c b/kernel/kernel/kernel.c
index fe75d7d..0ebaf64 100644
--- a/kernel/kernel/kernel.c
+++ b/kernel/kernel/kernel.c
@@ -44,12 +44,10 @@ kernel_main(uint32_t magic, multiboot_info_t *multiboot_info)
GDT_load();
memory_map_load(multiboot_info);
physical_mm_init();
+ virtual_mm_initialize();
printk("\nKernel", "Started.");
- uint32_t x = 0;
- virtual_mm_allocate_page(&x);
-
exit();
halt(); /* If exit() fails (on real hardware) */
}
diff --git a/kernel/mm/virtual_mm/virtual_mm.c b/kernel/mm/virtual_mm/virtual_mm.c
index 6350c11..0f55950 100644
--- a/kernel/mm/virtual_mm/virtual_mm.c
+++ b/kernel/mm/virtual_mm/virtual_mm.c
@@ -18,6 +18,8 @@
#include <stdint.h>
+#include <kernel/halt.h>
+
#include <libk/stdio.h>
#include <mm/physical_mm.h>
@@ -26,8 +28,7 @@
extern uint32_t kernel_start;
extern uint32_t kernel_end;
-uint32_t initial_page_directory[PAGE_DIRECTORY_SIZE];
-uint32_t initial_page_table[PAGE_TABLE_SIZE];
+uint32_t *current_page_directory = 0;
bool
virtual_mm_allocate_page(uint32_t *pt_entry)
@@ -75,5 +76,102 @@ virtual_mm_lookup_directory(uint32_t *page_directory, uint32_t virtual_addr)
ALWAYS_INLINE void
virtual_mm_load_page_directory(uint32_t *page_directory)
{
- __asm__("movl %0, %%cr0" ::"r"(page_directory));
+ __asm__("movl %0, %%eax" ::"r"(page_directory) : "%eax");
+ /* For some reason, that colon is required; else the assembler thinks that
+ * %eax doesn't exist :^) */
+ __asm__("movl %%eax, %%cr3" ::: "%eax");
+}
+
+bool
+virtual_mm_switch_page_directory(uint32_t *page_directory)
+{
+ if (!page_directory)
+ return false;
+ current_page_directory = page_directory;
+ virtual_mm_load_page_directory(page_directory);
+
+ return true;
+}
+
+/* TODO: I have absolutely _no_ idea if this works */
+void
+virtual_mm_flush_tlb_entry(uint32_t *virtual_addr)
+{
+ __asm__("cli;"
+ "invlpg (%0);"
+ "sti" ::"r"(virtual_addr));
+}
+
+bool
+virtual_mm_map_page(uint32_t *physical_addr, uint32_t *virtual_addr)
+{
+ uint32_t *pd_entry
+ = &current_page_directory[PAGE_DIRECTORY_INDEX((uint32_t) virtual_addr)];
+
+ /* If the page directory entry isn't present */
+ if (!PTE_IS_PRESENT(*pd_entry)) {
+ uint32_t *page_table = physical_mm_allocate_block();
+ if (!page_table)
+ return false;
+
+ *pd_entry = 0;
+ ADD_ATTRIB(pd_entry, SET_PDE_PRESENT(1));
+ ADD_ATTRIB(pd_entry, SET_PDE_WRITABLE(1));
+ ADD_ATTRIB(pd_entry, SET_PDE_FRAME((uint32_t) page_table));
+ }
+
+ uint32_t *page_table = (uint32_t *) GET_PDE_FRAME(pd_entry);
+ uint32_t *pt_entry = &page_table[PAGE_TABLE_INDEX((uint32_t) virtual_addr)];
+ *pt_entry = 0;
+
+ ADD_ATTRIB(pt_entry, SET_PTE_PRESENT(1));
+ ADD_ATTRIB(pt_entry, SET_PTE_FRAME((uint32_t) physical_addr));
+
+ return true;
+}
+
+ALWAYS_INLINE static void
+virtual_mm_enable_paging(void)
+{
+ __asm__("movl %%cr0, %%eax;"
+ "orl $0x80000000, %%eax;"
+ "movl %%eax, %%cr0" ::
+ : "eax");
+}
+
+void
+virtual_mm_initialize(void)
+{
+ uint32_t *table = physical_mm_allocate_block();
+ if (!table)
+ ASSERT_NOT_REACHED();
+
+ for (uint32_t i = 0; i < 1024; i++)
+ table[i] = 0;
+
+ /* Identity map the first 4MiB (maps 4KiB 1024 times) */
+ for (uint32_t i = 0, physical_addr = 0, virtual_addr = 0; i < 1024;
+ i++, physical_addr += 4096, virtual_addr += 4096) {
+ uint32_t page = 0;
+ ADD_ATTRIB(&page, SET_PTE_PRESENT(1));
+ ADD_ATTRIB(&page, SET_PTE_FRAME(physical_addr));
+
+ table[PAGE_TABLE_INDEX(virtual_addr)] = page;
+ }
+
+ uint32_t *page_directory = physical_mm_allocate_block();
+ if (!page_directory)
+ ASSERT_NOT_REACHED();
+
+ for (uint32_t i = 0; i < 1024; i++)
+ page_directory[i] = 0;
+
+ uint32_t *pd_entry = &page_directory[PAGE_DIRECTORY_INDEX(0)];
+ ADD_ATTRIB(pd_entry, SET_PDE_PRESENT(1));
+ ADD_ATTRIB(pd_entry, SET_PDE_WRITABLE(1));
+ ADD_ATTRIB(pd_entry, SET_PDE_FRAME((uint32_t) table));
+
+ current_page_directory = page_directory;
+ virtual_mm_switch_page_directory(current_page_directory);
+ virtual_mm_enable_paging();
}