A Total Overhaul on the Lunaix's Virtual Memory Model (#26)
[lunaix-os.git] / lunaix-os / arch / i386 / boot / kpt_setup.c
index 50d95eef45c8257d683706ed2b8636cf7e2f7416..26a348d13b4eb9fa8b8cb7ad67b0de18fd65bd4e 100644 (file)
 #define __BOOT_CODE__
 
-#include <lunaix/mm/page.h>
+#include <lunaix/mm/pagetable.h>
+#include <lunaix/compiler.h>
 
 #include <sys/boot/bstage.h>
-#include <sys/mm/mempart.h>
+#include <sys/mm/mm_defs.h>
 
-#define PT_ADDR(ptd, pt_index) ((ptd_t*)ptd + (pt_index + 1) * 1024)
-#define SET_PDE(ptd, pde_index, pde) *((ptd_t*)ptd + pde_index) = pde;
-#define SET_PTE(ptd, pt_index, pte_index, pte)                                 \
-    *(PT_ADDR(ptd, pt_index) + pte_index) = pte;
-#define sym_val(sym) (ptr_t)(&sym)
-
-#define KERNEL_PAGE_COUNT                                                      \
-    ((sym_val(__kexec_end) - sym_val(__kexec_start) + 0x1000 - 1) >> 12);
-#define HHK_PAGE_COUNT                                                         \
-    ((sym_val(__kexec_boot_end) - 0x100000 + 0x1000 - 1) >> 12)
-
-#define V2P(vaddr) ((ptr_t)(vaddr)-KERNEL_EXEC)
-
-// use table #1
-#define PG_TABLE_IDENTITY 0
+// Provided by linker (see linker.ld)
+extern u8_t __kexec_start[];
+extern u8_t __kexec_end[];
+extern u8_t __kexec_text_start[];
+extern u8_t __kexec_text_end[];
+extern u8_t __kboot_start[];
+extern u8_t __kboot_end[];
 
-// use table #2-8
-// hence the max size of kernel is 8MiB
-#define PG_TABLE_KERNEL 1
+// define the initial page table layout
+struct kernel_map {
+    pte_t l0t[_PAGE_LEVEL_SIZE];
 
-// use table #9
-#define PG_TABLE_STACK 8
+    struct {
+        pte_t _lft[_PAGE_LEVEL_SIZE];
+    } kernel_lfts[16];
+} align(4);
 
-// Provided by linker (see linker.ld)
-extern u8_t __kexec_start;
-extern u8_t __kexec_end;
-extern u8_t __kexec_text_start;
-extern u8_t __kexec_text_end;
+static struct kernel_map kernel_pt __section(".kpg");
+export_symbol(debug, boot, kernel_pt);
 
-extern u8_t __kexec_boot_end;
 
 void boot_text
-_init_page(x86_page_table* ptd)
+_init_page()
 {
-    ptd->entry[0] = NEW_L1_ENTRY(PG_PREM_RW, (ptd_t*)ptd + PG_MAX_ENTRIES);
-
-    // 对低1MiB空间进行对等映射(Identity
-    // mapping),也包括了我们的VGA,方便内核操作。
-    x86_page_table* id_pt =
-      (x86_page_table*)GET_PG_ADDR(ptd->entry[PG_TABLE_IDENTITY]);
+    struct kernel_map* kpt_pa = (struct kernel_map*)to_kphysical(&kernel_pt);
 
-    for (u32_t i = 0; i < 256; i++) {
-        id_pt->entry[i] = NEW_L2_ENTRY(PG_PREM_RW, (i << PG_SIZE_BITS));
-    }
+    pte_t* kl0tep       = (pte_t*) &kpt_pa->l0t[pfn_at(KERNEL_RESIDENT, L0T_SIZE)];
+    pte_t* kl1tep       = (pte_t*)  kpt_pa->kernel_lfts;    
+    pte_t* boot_l0tep   = (pte_t*)  kpt_pa;
 
-    // 对等映射我们的hhk_init,这样一来,当分页与地址转换开启后,我们依然能够照常执行最终的
-    // jmp 指令来跳转至
-    //  内核的入口点
-    for (u32_t i = 0; i < HHK_PAGE_COUNT; i++) {
-        id_pt->entry[256 + i] =
-          NEW_L2_ENTRY(PG_PREM_RW, 0x100000 + (i << PG_SIZE_BITS));
-    }
+    set_pte(boot_l0tep, pte_mkhuge(mkpte_prot(KERNEL_DATA)));
 
     // --- 将内核重映射至高半区 ---
 
-    // 这里是一些计算,主要是计算应当映射进的 页目录 与 页表 的条目索引(Entry
-    // Index)
-    u32_t kernel_pde_index = L1_INDEX(sym_val(__kexec_start));
-    u32_t kernel_pte_index = L2_INDEX(sym_val(__kexec_start));
-    u32_t kernel_pg_counts = KERNEL_PAGE_COUNT;
-
-    // 将内核所需要的页表注册进页目录
-    //  当然,就现在而言,我们的内核只占用不到50个页(每个页表包含1024个页)
-    //  这里分配了3个页表(12MiB),未雨绸缪。
-    for (u32_t i = 0; i < PG_TABLE_STACK - PG_TABLE_KERNEL; i++) {
-        ptd->entry[kernel_pde_index + i] =
-          NEW_L1_ENTRY(PG_PREM_RW, PT_ADDR(ptd, PG_TABLE_KERNEL + i));
+    // Hook the kernel reserved LFTs onto L0T
+    pte_t pte = mkpte((ptr_t)kl1tep, KERNEL_DATA);
+    
+    for (u32_t i = 0; i < KEXEC_RSVD; i++) {
+        pte = pte_setpaddr(pte, (ptr_t)&kpt_pa->kernel_lfts[i]);
+        set_pte(kl0tep, pte);
+
+        kl0tep++;
     }
 
-    // 首先,检查内核的大小是否可以fit进我们这几个表(12MiB)
-    if (kernel_pg_counts >
-        (PG_TABLE_STACK - PG_TABLE_KERNEL) * PG_MAX_ENTRIES) {
+    // Ensure the size of kernel is within the reservation
+    pfn_t kimg_pagecount = 
+        pfn((ptr_t)__kexec_end - (ptr_t)__kexec_start);
+    if (kimg_pagecount > KEXEC_RSVD * _PAGE_LEVEL_SIZE) {
         // ERROR: require more pages
         //  here should do something else other than head into blocking
         asm("ud2");
     }
 
-    // 计算内核.text段的物理地址
-    ptr_t kernel_pm = V2P(&__kexec_start);
-    ptr_t ktext_start = V2P(&__kexec_text_start);
-    ptr_t ktext_end = V2P(&__kexec_text_end);
+    // Now, map the kernel
+
+    pfn_t kimg_end = pfn(to_kphysical(__kexec_end));
+    pfn_t i = pfn(to_kphysical(__kexec_text_start));
+    kl1tep += i;
 
-    // 重映射内核至高半区地址(>=0xC0000000)
-    for (u32_t i = 0; i < kernel_pg_counts; i++) {
-        ptr_t paddr = kernel_pm + (i << PG_SIZE_BITS);
-        u32_t flags = PG_PREM_RW;
+    // kernel .text
+    pte = pte_setprot(pte, KERNEL_EXEC);
+    pfn_t ktext_end = pfn(to_kphysical(__kexec_text_end));
+    for (; i < ktext_end; i++) {
+        pte = pte_setpaddr(pte, page_addr(i));
+        set_pte(kl1tep, pte);
+
+        kl1tep++;
+    }
 
-        if (paddr >= ktext_start && paddr <= ktext_end) {
-            flags = PG_PREM_R;
-        }
+    // all remaining kernel sections
+    pte = pte_setprot(pte, KERNEL_DATA);
+    for (; i < kimg_end; i++) {
+        pte = pte_setpaddr(pte, page_addr(i));
+        set_pte(kl1tep, pte);
 
-        SET_PTE(ptd,
-                PG_TABLE_KERNEL,
-                kernel_pte_index + i,
-                NEW_L2_ENTRY(flags, paddr))
+        kl1tep++;
     }
 
-    // 最后一个entry用于循环映射
-    ptd->entry[PG_MAX_ENTRIES - 1] = NEW_L1_ENTRY(T_SELF_REF_PERM, ptd);
+    // XXX: Mapping the kernel .rodata section?
+
+    // Build up self-reference
+    pte = mkpte_root((ptr_t)kpt_pa, KERNEL_DATA);
+    set_pte(boot_l0tep + _PAGE_LEVEL_MASK, pte);
 }
 
-void boot_text
-kpg_init(x86_page_table* ptd, u32_t kpg_size)
+ptr_t boot_text
+kpg_init()
 {
-
-    // 初始化 kpg 全为0
-    //      P.s. 真没想到GRUB会在这里留下一堆垃圾! 老子的页表全乱套了!
-    u8_t* kpg = (u8_t*)ptd;
-    for (u32_t i = 0; i < kpg_size; i++) {
-        *(kpg + i) = 0;
+    ptr_t kmap_pa = to_kphysical(&kernel_pt);
+    for (size_t i = 0; i < sizeof(kernel_pt); i++) {
+        ((u8_t*)kmap_pa)[i] = 0;
     }
 
-    _init_page(ptd);
+    _init_page();
+
+    return kmap_pa;
 }
\ No newline at end of file