diff options
author | dzwdz | 2021-07-19 18:17:50 +0200 |
---|---|---|
committer | dzwdz | 2021-07-19 18:17:50 +0200 |
commit | f2a0c7595bf805cd53001984495e4db0268f5f98 (patch) | |
tree | 95900e23e386beeea8dfd17a102f7360b66adf73 | |
parent | c9ad4bfbf875b0d23e1f7bf7d5aff2d149ba4fd7 (diff) |
very basic paging
-rw-r--r-- | src/kernel/arch/generic.h | 7 | ||||
-rw-r--r-- | src/kernel/arch/i386/pagedir.c | 98 | ||||
-rw-r--r-- | src/kernel/main.c | 16 |
3 files changed, 121 insertions, 0 deletions
diff --git a/src/kernel/arch/generic.h b/src/kernel/arch/generic.h index 46782f8..22efe58 100644 --- a/src/kernel/arch/generic.h +++ b/src/kernel/arch/generic.h @@ -1,6 +1,7 @@ #pragma once #include <kernel/arch/log.h> +#include <stdbool.h> // i have no idea where else to put it // some code assumes that it's a power of 2 @@ -15,3 +16,9 @@ void halt_cpu(); // src/arch/i386/sysenter.s void sysexit(void (*fun)(), void *stack_top); void sysenter_setup(); + +// all of those can allocate memory +struct pagedir *pagedir_new(); +void pagedir_map(struct pagedir *dir, void *virt, void *phys, + bool user, bool writeable); +void pagedir_use(struct pagedir *); diff --git a/src/kernel/arch/i386/pagedir.c b/src/kernel/arch/i386/pagedir.c new file mode 100644 index 0000000..264508b --- /dev/null +++ b/src/kernel/arch/i386/pagedir.c @@ -0,0 +1,98 @@ +#include <kernel/arch/generic.h> +#include <kernel/mem.h> +#include <stdint.h> + +/* <heat> nitpick: I highly recommend you dont use bitfields for paging + * structures + * <heat> you can't change them atomically and the way they're layed out + * in memory is implementation defined iirc + */ +struct pagetable_entry { + uint32_t present : 1; + uint32_t writeable : 1; + uint32_t user : 1; + uint32_t writethru : 1; + uint32_t uncached : 1; + uint32_t dirty : 1; + uint32_t always0 : 1; // memory type thing? + uint32_t global : 1; + uint32_t _unused : 3; + uint32_t address : 21; +}; + +struct pagedir_entry { + uint32_t present : 1; + uint32_t writeable : 1; + uint32_t user : 1; + uint32_t writethru : 1; + uint32_t uncached : 1; + uint32_t accessed : 1; + uint32_t always0 : 1; + uint32_t large : 1; // 4 MiB instead of 4 KiB + uint32_t _unused : 3; + uint32_t address : 21; +} __attribute__((packed)); + +struct pagedir { + struct pagedir_entry e[1024]; +} __attribute__((packed)); + + +struct pagedir *pagedir_new() { + struct pagedir *dir = page_alloc(1); + for (int i = 0; i < 1024; i++) + dir->e[i].present = 0; + return dir; +} + +void pagedir_map(struct pagedir *dir, void *virt, void *phys, + bool user, bool writeable) +{ + uintptr_t virt_casted = (uintptr_t) virt; + uint32_t pd_idx = virt_casted >> 22; + uint32_t pt_idx = virt_casted >> 12 & 0x03FF; + struct pagetable_entry *pagetable; + + if (dir->e[pd_idx].present) { + pagetable = (void*) (dir->e[pd_idx].address << 11); + } else { + pagetable = page_alloc(1); + for (int i = 0; i < 1024; i++) + pagetable[i].present = 0; + + dir->e[pd_idx] = (struct pagedir_entry) { + .present = 1, + .writeable = 1, + .user = 1, + .writethru = 1, + .uncached = 0, + .accessed = 0, + .always0 = 0, + .large = 0, + ._unused = 0, + .address = (uintptr_t) pagetable >> 11 + }; + } + + pagetable[pt_idx] = (struct pagetable_entry) { + .present = 1, + .writeable = writeable, + .user = user, + .writethru = 1, + .uncached = 0, + .dirty = 0, + .always0 = 0, + .global = 0, + ._unused = 0, + .address = (uintptr_t) phys >> 11 + }; +} + +void pagedir_use(struct pagedir *dir) { + asm volatile("mov %0, %%cr3;" + + "mov %%cr0, %%eax;" + "or $0x80000001, %%eax;" + "mov %%eax, %%cr0;" + : : "r" (dir) : "eax"); +} diff --git a/src/kernel/main.c b/src/kernel/main.c index 7f49fed..1b5e504 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -8,10 +8,26 @@ void r3_test(); +static void setup_paging() { + struct pagedir *dir = pagedir_new(); + + // map VGA + pagedir_map(dir, 0xB8000, 0xB8000, true, true); + + // map the kernel + for (size_t p = 0x100000; p < &_bss_end; p += PAGE_SIZE) + pagedir_map(dir, p, p, false, true); // yes, .text is writeable too + + pagedir_use(dir); +} + void kmain(struct kmain_info info) { log_const("mem..."); mem_init(&info); + log_const("paging..."); + setup_paging(); + log_const("creating process..."); void *init_addr = (void*)0x200000; |