diff options
Diffstat (limited to 'kernel/vm.c')
-rw-r--r-- | kernel/vm.c | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/kernel/vm.c b/kernel/vm.c new file mode 100644 index 0000000..c1adbe7 --- /dev/null +++ b/kernel/vm.c @@ -0,0 +1,108 @@ +#include "kernel/vm.h"
+#include "kernel/kalloc.h"
+#include "kernel/lib.h"
+#include "kernel/riscv.h"
+
+enum
+{
+ VM_VALID = 1,
+ VM_USER = 16,
+ VM_GLOBAL = 32,
+ VM_ACCESSED = 64,
+ VM_DIRTY = 128,
+};
+
+struct PageTable
+{
+ uint32_t entries[1024];
+};
+typedef struct PageTable PageTable;
+static_assert(sizeof(PageTable) == PAGE_SIZE);
+
+static PageTable* kroot = nullptr;
+
+static inline bool is_aligned(uint32_t p)
+{
+ return (p & (PAGE_SIZE - 1)) == 0;
+}
+
+static inline void* offset_page(void* p)
+{
+ return (void*)((char*)p + PAGE_SIZE);
+}
+
+void kvm_map_one(PageTable* root, void* va, void* pa, uint32_t mode)
+{
+ uint32_t vpn[] = {
+ ((uint32_t)va >> 12) & 0x3ff,
+ ((uint32_t)va >> 22) & 0x3ff,
+ };
+
+ uint32_t fl = root->entries[vpn[1]];
+ if (!(fl & VM_VALID))
+ {
+ PageTable* child = (PageTable*)kzalloc();
+ fl = (((uint32_t)child >> 2) & 0xffff'fc00) | VM_VALID;
+ root->entries[vpn[1]] = fl;
+ }
+
+ PageTable* child = (PageTable*)((fl & 0xffff'fc00) << 2);
+
+ uint32_t ppn[] = {
+ ((uint32_t)pa >> 12) & 0x3ff,
+ ((uint32_t)pa >> 22) & 0x3ff,
+ };
+
+ child->entries[vpn[0]] = (ppn[1] << 20) | (ppn[0] << 10) | VM_VALID | mode;
+}
+
+void kvm_map(void* va, void* pa, uint32_t size, uint32_t mode)
+{
+ if (!is_aligned((uint32_t)va)) panic("kvm_map: virtual address not aligned");
+ if (!is_aligned((uint32_t)pa)) panic("kvm_map: physical address not aligned");
+ if (!is_aligned(size)) panic("kvm_map: size not aligned");
+
+ for (; size > 0; size -= PAGE_SIZE)
+ {
+ kvm_map_one(kroot, va, pa, mode);
+ va = offset_page(va);
+ pa = offset_page(pa);
+ }
+}
+
+extern char _text_start;
+extern char _text_end;
+
+extern char _rodata_start;
+extern char _rodata_end;
+
+extern char _data_start;
+extern char _data_end;
+
+extern char _bss_start;
+extern char _bss_end;
+
+extern char _stack_start;
+extern char _stack_end;
+
+extern char _heap_start;
+extern char _heap_end;
+
+void kvm_init()
+{
+ kroot = (PageTable*)kzalloc();
+
+ kvm_map(&_text_start, &_text_start, &_text_end - &_text_start, VM_R | VM_X);
+ kvm_map(&_rodata_start, &_rodata_start, &_rodata_end - &_rodata_start, VM_R);
+ kvm_map(&_data_start, &_data_start, &_data_end - &_data_start, VM_RW);
+ kvm_map(&_bss_start, &_bss_start, &_bss_end - &_bss_start, VM_RW);
+ kvm_map(&_heap_start, &_heap_start, &_heap_end - &_heap_start, VM_RW);
+ kvm_map(&_stack_start, &_stack_start, &_stack_end - &_stack_start, VM_RW);
+
+ kvm_map((void*)0x1000'0000, (void*)0x1000'0000, PAGE_SIZE, VM_RW); // UART
+ kvm_map((void*)0x0c00'0000, (void*)0x0c00'0000, 0x8000, VM_RW); // APLIC-M
+ kvm_map((void*)0x0d00'0000, (void*)0x0d00'0000, 0x8000, VM_RW); // APLIC-S
+
+ w_satp(SATP_MODE_SV32 | ((uint32_t)kroot >> 12));
+ sfence_vma();
+}
|