From 4440cd93ee5526ea09e501b073639d8eee8f1ccf Mon Sep 17 00:00:00 2001
From: "iliya.saroukha" <iliya.saroukhanian@etu.hesge.ch>
Date: Tue, 22 Oct 2024 19:05:12 +0200
Subject: [PATCH] feat: paging seemingly fully working now

---
 kernel/mem/paging.c | 121 ++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 118 insertions(+), 3 deletions(-)

diff --git a/kernel/mem/paging.c b/kernel/mem/paging.c
index c1ff3c5..5d0ac1d 100644
--- a/kernel/mem/paging.c
+++ b/kernel/mem/paging.c
@@ -1,7 +1,15 @@
 #include "paging.h"
+#include "boot/multiboot.h"
+#include "boot/multiboot_structs.h"
+#include "common/mem.h"
+#include "common/types.h"
+#include "drivers/display.h"
 #include "frame.h"
 #include "x86.h"
 
+extern void ld_stack_start();
+uint_t stack_start = (uint_t)&ld_stack_start;
+
 static PDE_t kernel_pagedir[PAGETABLES_IN_PD]
     __attribute__((aligned(PAGE_SIZE)));
 
@@ -12,21 +20,128 @@ static PDE_t kernel_pagedir[PAGETABLES_IN_PD]
 // table if one was just allocated, otherwise returns 0.
 static PTE_t *mmap_page(PDE_t *pagedir, uint32_t virt_addr, uint32_t phys_addr,
                         enum privilege_t privilege, enum access_t access) {
-    // TODO
+    uint_t pde_idx = ADDR_TO_PDE(virt_addr);
+    PTE_t *page_table = NULL;
+
+    if (!pagedir[pde_idx].present) {
+        page_table = frame_alloc();
+
+        if (page_table == FRAME_ALLOC_ERR) {
+            return FRAME_ALLOC_ERR;
+        }
+
+        pagedir[pde_idx].present = 1;
+        pagedir[pde_idx].rw = access;
+        pagedir[pde_idx].user = privilege;
+        pagedir[pde_idx].page_sz = 0;
+        pagedir[pde_idx].pagetable_frame_number = ADDR_TO_FRAME_NB(page_table);
+
+        uint_t pte_idx = (virt_addr >> 12) & 0x3FF;
+
+        page_table[pte_idx].present = 1;
+        page_table[pte_idx].user = privilege;
+        page_table[pte_idx].rw = access;
+        page_table[pte_idx].frame_number = ADDR_TO_FRAME_NB(phys_addr);
+
+        return page_table;
+    }
+
+    page_table =
+        (PTE_t *)FRAME_NB_TO_ADDR(pagedir[pde_idx].pagetable_frame_number);
+
+    uint_t pte_idx = (virt_addr >> 12) & 0x3FF;
+
+    page_table[pte_idx].present = 1;
+    page_table[pte_idx].user = privilege;
+    page_table[pte_idx].rw = access;
+    page_table[pte_idx].frame_number = ADDR_TO_FRAME_NB(phys_addr);
+
+    return 0;
 }
 
 void paging_mmap(PDE_t *pagedir, uint32_t virt_addr, uint32_t phys_addr,
                  uint32_t size, enum privilege_t privilege,
                  enum access_t access) {
-    // TODO
+    struct terminal_t term;
+
+    if (term_init(&term) != 0) {
+        return;
+    }
+
+    uint_t va_aligned = ALIGN_TO_PAGE_SIZE(virt_addr);
+    uint_t pa_aligned = ALIGN_TO_PAGE_SIZE(phys_addr);
+
+    uint_t end_addr = va_aligned + size;
+    // i actually hate myself for this `if` block, ugliest stuff ever
+    uint_t to_mmap;
+    if (end_addr < PAGE_SIZE) {
+        to_mmap = PAGE_SIZE;
+    } else {
+        to_mmap = ALIGN_TO_PAGE_SIZE(end_addr);
+    }
+    /*uint_t to_mmap = ALIGN_TO_PAGE_SIZE(va_aligned + size);*/
+
+    for (uint_t i = va_aligned, j = pa_aligned; i < to_mmap;
+         i += PAGE_SIZE, j += FRAME_SIZE) {
+        PTE_t *pt = mmap_page(pagedir, i, j, privilege, access);
+
+        if (pt == FRAME_ALLOC_ERR) {
+            /*kprintf(&term,*/
+            /*        "New page table allocated at 0x%x pointing to 0x%x\n",
+             * pt,*/
+            /*        FRAME_NB_TO_ADDR(pt->frame_number));*/
+            kprintf(&term, "Shit happened\n");
+        }
+    }
 }
 
 static void unmap_page(PDE_t *pagedir, uint32_t virt_addr) {
     // TODO
+    uint_t pde_idx = ADDR_TO_PDE(virt_addr);
+    PDE_t *dir_entry = &pagedir[pde_idx];
+
+    PTE_t *page_table =
+        (PTE_t *)FRAME_NB_TO_ADDR(dir_entry->pagetable_frame_number);
+
+    uint_t pte_idx = (virt_addr >> 12) & 0x3FF;
+
+    frame_free((void *)FRAME_NB_TO_ADDR(page_table[pte_idx].frame_number));
+    memset(&page_table[pte_idx], 0, sizeof(PTE_t));
+
+    for (uint_t i = 0; i < PAGES_IN_PT; i++) {
+        if (!is_frame_free(page_table[i].frame_number)) {
+            return;
+        }
+    }
+
+    frame_free((void *)FRAME_NB_TO_ADDR(dir_entry->pagetable_frame_number));
+    memset(dir_entry, 0, sizeof(PDE_t));
 }
 
 void paging_init(uint_t RAM_in_KB) {
-    // TODO
+    if (!RAM_in_KB) {
+        return;
+    }
+
+    paging_mmap(kernel_pagedir, 0, 0, RAM_in_KB * 1024, PRIVILEGE_KERNEL,
+                ACCESS_READWRITE);
+
+    multiboot_info_t *mbi = multiboot_get_info();
+    uint_t fb_size = mbi->framebuffer_pitch *
+                     (mbi->framebuffer_height * (mbi->framebuffer_bpp / 8));
+
+    // Identity mapping of the framebuffer
+    paging_mmap(kernel_pagedir, mbi->framebuffer_addr, mbi->framebuffer_addr,
+                fb_size, PRIVILEGE_KERNEL, ACCESS_READWRITE);
+
+    // Second mapping of the VBE framebuffer to VA 3GB (3 * (1 << 30))
+    uint_t va_framebuffer = 3 * (1UL << 30);
+    paging_mmap(kernel_pagedir, va_framebuffer, mbi->framebuffer_addr, fb_size,
+                PRIVILEGE_KERNEL, ACCESS_READWRITE);
+
+    unmap_page(kernel_pagedir, 0);
+    // unmapping the stack guard page
+    unmap_page(kernel_pagedir, stack_start);
 
     paging_load_pagedir(kernel_pagedir);
     paging_enable();
-- 
GitLab