summaryrefslogtreecommitdiffstats
path: root/arch/x86_64/paging.c
diff options
context:
space:
mode:
authorJon Santmyer <jon@jonsantmyer.com>2024-03-11 21:30:31 -0400
committerJon Santmyer <jon@jonsantmyer.com>2024-03-11 21:30:31 -0400
commitd1ff7bcc91886626dc9060ec5fb67ee102ab7c1d (patch)
tree8f0b5cd8aad31089131785dc6e37b659490f9955 /arch/x86_64/paging.c
downloadjove-kernel-d1ff7bcc91886626dc9060ec5fb67ee102ab7c1d.tar.gz
jove-kernel-d1ff7bcc91886626dc9060ec5fb67ee102ab7c1d.tar.bz2
jove-kernel-d1ff7bcc91886626dc9060ec5fb67ee102ab7c1d.zip
usermode capable kernel with logging syscall
Diffstat (limited to 'arch/x86_64/paging.c')
-rw-r--r--arch/x86_64/paging.c202
1 files changed, 202 insertions, 0 deletions
diff --git a/arch/x86_64/paging.c b/arch/x86_64/paging.c
new file mode 100644
index 0000000..76b5735
--- /dev/null
+++ b/arch/x86_64/paging.c
@@ -0,0 +1,202 @@
+#include "paging.h"
+#include <stddef.h>
+#include "lib/jove.h"
+#include "io/log.h"
+#include "lib/string.h"
+#include "boot/boot.h"
+
+extern void *_kernel_end;
+
+PAGEALIGN static uint64_t s_kernel_initial_pml4[512];
+PAGEALIGN static uint64_t s_kernel_initial_pml3[2][512];
+PAGEALIGN static uint64_t s_kernel_initial_pml2[2][512];
+PAGEALIGN static uint64_t s_kernel_initial_pml1[2][512];
+static struct PageDirectory s_kernel_initial_pd;
+
+struct PageDirectory *mem_current_pd;
+
+physptr_t
+mem_linear_tophys_koffset(uintptr_t virt)
+{
+ return (virt - boot_kernel_virtual_base) + boot_kernel_physical_address;
+}
+
+uintptr_t
+mem_phys_tolinear(physptr_t phys)
+{
+ return (uintptr_t)(phys + 0xFFFF800000000000ULL);
+}
+
+static size_t
+s_paging_pmle(size_t l, uintptr_t addr)
+{
+ size_t shift = (12 + (9 * l));
+ return (addr & (0x1FFULL << shift)) >> shift;
+}
+
+static union PageEntry*
+s_paging_fetch_table(union PageEntry *pt, size_t l, uintptr_t virt)
+{
+ size_t pmle = s_paging_pmle(l, virt);
+ union PageEntry entry = pt[pmle];
+ bool entry_new = false;
+ if(!entry.p) {
+ entry_new = true;
+ entry.value = mem_phys_take4k();
+ entry.p = 1;
+ entry.rw = 1;
+ entry.us = 1;
+ pt[pmle] = entry;
+ }
+ union PageEntry *table = (union PageEntry*)(mem_phys_tolinear(entry.paddr << 12));
+ if(entry_new) memset(table, 0, PAGESIZE);
+ return table;
+}
+
+static union PageEntry*
+s_paging_get_table(union PageEntry *pt, size_t l, uintptr_t virt)
+{
+ if(pt == NULL) return NULL;
+ size_t pmle = s_paging_pmle(l, virt);
+ union PageEntry entry = pt[pmle];
+ if(!entry.p) return NULL;
+ return (union PageEntry*)(mem_phys_tolinear(entry.paddr << 12));
+}
+
+physptr_t
+mem_linear_tophys(uintptr_t virt)
+{
+ struct PageDirectory *pd = mem_current_pd;
+ union PageEntry *pml3 = s_paging_get_table(pd->pml4_vaddr, 3, virt);
+ union PageEntry *pml2 = s_paging_get_table(pd->pml4_vaddr, 3, virt);
+ union PageEntry *pml1 = s_paging_get_table(pd->pml4_vaddr, 3, virt);
+ if(pml1 == NULL) return 0;
+
+ size_t pml1i = s_paging_pmle(0, virt);
+
+ if(!pml1[pml1i].p) return 0;
+ return pml1[pml1i].paddr << 12;
+}
+
+bool
+mem_check_ptr(const void *ptr)
+{
+ if(ptr == NULL) return false;
+ return mem_linear_tophys((uintptr_t)ptr) != 0;
+}
+
+void
+mem_paging_map4k(struct PageDirectory *pd, physptr_t phys, uintptr_t virt, uint8_t flg)
+{
+ union PageEntry *pml3 = s_paging_fetch_table(pd->pml4_vaddr, 3, virt);
+ union PageEntry *pml2 = s_paging_fetch_table(pml3, 2, virt);
+ union PageEntry *pml1 = s_paging_fetch_table(pml2, 1, virt);
+ size_t pml1e = s_paging_pmle(0, virt);
+
+ pml1[pml1e] = (union PageEntry) {
+ .p = (flg & 1) > 0,
+ .rw = (flg & 2) > 0,
+ .us = (flg & 4) > 0,
+ .paddr = phys >> 12
+ };
+}
+
+union PageEntry
+mem_paging_fetch4k(struct PageDirectory *pd, uintptr_t virt)
+{
+ union PageEntry *pml3 = s_paging_fetch_table(pd->pml4_vaddr, 3, virt);
+ union PageEntry *pml2 = s_paging_fetch_table(pml3, 2, virt);
+ union PageEntry *pml1 = s_paging_fetch_table(pml2, 1, virt);
+ return pml1[s_paging_pmle(0, virt)];
+}
+
+void
+mem_pd_ensure_4k(struct PageDirectory *pd, uintptr_t virt, uint8_t flg)
+{
+ union PageEntry pml1e = mem_paging_fetch4k(pd, virt);
+ if(!pml1e.p) {
+ uintptr_t phys = mem_phys_take4k();
+ mem_paging_map4k(pd, phys, virt, flg);
+ }
+}
+
+void
+mem_pd_ensure_range(struct PageDirectory *pd, uintptr_t from, uintptr_t to, uint8_t flg)
+{
+ from &= ~0xFFF;
+ for(; from < to; from += PAGESIZE)
+ mem_pd_ensure_4k(pd, from, flg);
+}
+
+void
+mem_ensure_range(uintptr_t from, uintptr_t to, bool rw, bool user)
+{
+ mem_pd_ensure_range(mem_current_pd, from, to, 1 | (rw << 1) | (user << 2));
+}
+
+void mem_pd_new(struct PageDirectory *pd)
+{
+ physptr_t pml4p = mem_phys_take4k();
+ union PageEntry *pml4 = (union PageEntry*)mem_phys_tolinear(pml4p);
+ memset(pml4, 0, PAGESIZE);
+ memcpy(&pml4[256], &pd->pml4_vaddr[256], PAGESIZE / 2);
+
+ *pd = (struct PageDirectory){
+ .pml4_vaddr = pml4,
+ .pml4_paddr = pml4p,
+ .references = 1
+ };
+}
+
+void mem_pd_clone(struct PageDirectory *pd, struct PageDirectory *parent)
+{
+ mem_pd_new(pd);
+ for(size_t i = 0; i < 256; i++) {
+
+ }
+}
+
+void
+mem_paging_setup(void)
+{
+ memset(s_kernel_initial_pml4, 0, PAGESIZE);
+ memset(s_kernel_initial_pml3, 0, 2 * PAGESIZE);
+ memset(s_kernel_initial_pml2, 0, 2 * PAGESIZE);
+ memset(s_kernel_initial_pml1, 0, PAGESIZE);
+ s_kernel_initial_pd = (struct PageDirectory){
+ .pml4_vaddr = (union PageEntry*)&s_kernel_initial_pml4,
+ .pml4_paddr = mem_linear_tophys_koffset((uintptr_t)&s_kernel_initial_pml4),
+ .references = 1
+ };
+ mem_current_pd = &s_kernel_initial_pd;
+
+ /* Map first few GiBs */
+ s_kernel_initial_pml4[256] =
+ mem_linear_tophys_koffset((uintptr_t)&s_kernel_initial_pml3[0])
+ | 3;
+ s_kernel_initial_pml3[0][0] =
+ mem_linear_tophys_koffset((uintptr_t)&s_kernel_initial_pml2[0])
+ | 3;
+ for(int i = 0; i < 512; i++) {
+ s_kernel_initial_pml2[0][i] = (i * (PAGESIZE * 512)) | 0x80 | 3;
+ }
+
+ size_t kernel_pml4e = (boot_kernel_virtual_base >> (39));
+ size_t kernel_pml3e = (boot_kernel_virtual_base >> (30)) % 512;
+ size_t kernel_pml2e = (boot_kernel_virtual_base >> (21)) % 512;
+ size_t kernel_npages = ((((uintptr_t)&_kernel_end) - boot_kernel_virtual_base) >> 12) + 1;
+ klogf("Kernel has %i pages\n", kernel_npages);
+
+ /* Map kernel pages */
+ s_kernel_initial_pml4[511] =
+ mem_linear_tophys_koffset((uintptr_t)&s_kernel_initial_pml3[1]) | 3;
+ s_kernel_initial_pml3[1][kernel_pml3e] =
+ mem_linear_tophys_koffset((uintptr_t)&s_kernel_initial_pml2[1]) | 3;
+ s_kernel_initial_pml2[1][kernel_pml2e] =
+ mem_linear_tophys_koffset((uintptr_t)&s_kernel_initial_pml1[0]) | 3;
+ for(int i = 0; i < kernel_npages; i++) {
+ s_kernel_initial_pml1[0][i] = (i * PAGESIZE) + boot_kernel_physical_address | 3;
+ }
+
+ __asm__ volatile("mov %0, %%cr3":: "r"(s_kernel_initial_pd.pml4_paddr));
+}