add generic kremap for kernel remapping
[lunaix-os.git] / lunaix-os / arch / x86 / boot / x86_64 / kremap64.c
index bf3bb33dd552ff80c73272c1c6bf256ff887854b..8d32345a3aef27908d49ff55937cecce30032b57 100644 (file)
 #define __BOOT_CODE__
 
-#include <lunaix/mm/pagetable.h>
-#include <lunaix/compiler.h>
-
-#include <sys/boot/bstage.h>
-#include <sys/mm/mm_defs.h>
+#include <asm/boot_stage.h>
+#include <asm/mm_defs.h>
+#include <asm-generic/init_pagetable.h>
 
 #define RSVD_PAGES 32
 
-bridge_farsym(__kexec_start);
-bridge_farsym(__kexec_end);
-bridge_farsym(__kexec_text_start);
-bridge_farsym(__kexec_text_end);
-
-// define the initial page table layout
-struct kernel_map;
-
-static struct kernel_map kpt __section(".kpg");
-export_symbol(debug, boot, kpt);
-
-struct kernel_map {
-    pte_t l0t[_PAGE_LEVEL_SIZE];        // root table
-    pte_t l1t_rsvd[_PAGE_LEVEL_SIZE];   // 0~4G reservation
-
+struct kernel_map 
+{
     struct {
         pte_t _lft[_PAGE_LEVEL_SIZE];
     } krsvd[RSVD_PAGES];
 } align(8);
 
-struct allocator
-{
-    struct kernel_map* kpt_pa;
-    int pt_usage;
-};
-
-static inline ptr_t
-alloc_rsvd_page(struct allocator* _alloc)
-{
-    if (_alloc->pt_usage >= KEXEC_RSVD) {
-        asm ("ud2");
-    }
-
-    return __ptr(&_alloc->kpt_pa->krsvd[_alloc->pt_usage++]);
-}
-
-static pte_t* boot_text
-prealloc_pt(struct allocator* _allc, ptr_t va, 
-            pte_attr_t prot, size_t to_gran) 
-{
-    int lvl_i;
-    pte_t *ptep, pte;
-    size_t gran = L0T_SIZE;
-
-    ptep = (pte_t*)&_allc->kpt_pa->l0t[0];
-
-    for (int i = 0; i < _PTW_LEVEL && gran > to_gran; i++)
-    {
-        lvl_i = va_level_index(va, gran);
-        ptep = &ptep[lvl_i];
-        pte  = pte_at(ptep);
-
-        gran = gran >> _PAGE_LEVEL_SHIFT;
-
-        if (pte_isnull(pte)) {
-            pte = mkpte(alloc_rsvd_page(_allc), KERNEL_DATA);
-            if (to_gran == gran) {
-                pte = pte_setprot(pte, prot);
-            }
-
-            set_pte(ptep, pte);
-        }
-        ptep = (pte_t*) pte_paddr(pte);
-    }
-
-    return ptep;
-}
+static struct kernel_map kpt __section(".kpg");
+export_symbol(debug, boot, kpt);
 
-static void boot_text
+static ptr_t boot_text
 do_remap()
 {
-    struct kernel_map* kpt_pa = (struct kernel_map*)to_kphysical(&kpt);
-    
-    pte_t* boot_l0tep   = (pte_t*)  kpt_pa;
-    pte_t *klptep, pte;
-
-    // identity map the first 4G for legacy compatibility
-    pte_t* l1_rsvd = (pte_t*) kpt_pa->l1t_rsvd;
-    pte_t id_map   = pte_mkhuge(mkpte_prot(KERNEL_DATA));
-    
-    set_pte(boot_l0tep, mkpte((ptr_t)l1_rsvd, KERNEL_DATA));
-    
-    for (int i = 0; i < 4; i++, l1_rsvd++)
-    {
-        id_map = pte_setpaddr(id_map, (ptr_t)i << 30);
-        set_pte(l1_rsvd, id_map);
-    }
-
-    // Remap the kernel to -2GiB
-
-    int table_usage = 0;
-    unsigned int lvl_i = 0;
-    struct allocator alloc = {
-        .kpt_pa = kpt_pa,
-        .pt_usage = 0
-    };
+    struct pt_alloc alloc;
+    struct ptw_state ptw;
+    pte_t pte;
 
-    prealloc_pt(&alloc, VMAP, KERNEL_DATA, L1T_SIZE);
+    init_pt_alloc(&alloc, to_kphysical(&kpt), sizeof(kpt));
+    init_ptw_state(&ptw, &alloc, kpt_alloc_table(&alloc));
 
-    prealloc_pt(&alloc, PG_MOUNT_1, KERNEL_DATA, LFT_SIZE);
+    pte = pte_mkhuge(mkpte_prot(KERNEL_PGTAB));
+    kpt_set_ptes(&ptw, 0, pte, L1T_SIZE, 4);
 
-
-    ptr_t kstart = page_aligned(__far(__kexec_text_start));
+    kpt_mktable_at(&ptw, VMAP, L0T_SIZE);
 
 #if LnT_ENABLED(3)
     size_t gran  = L3T_SIZE;
@@ -118,74 +37,25 @@ do_remap()
     size_t gran  = L2T_SIZE;
 #endif
 
-    prealloc_pt(&alloc, PMAP, KERNEL_DATA, gran);
-    klptep = prealloc_pt(&alloc, kstart, KERNEL_DATA, gran);
-    klptep += va_level_index(kstart, gran);
-
-    pte = mkpte(0, KERNEL_DATA);
-    for (int i = alloc.pt_usage; i < KEXEC_RSVD; i++)
-    {
-        pte = pte_setpaddr(pte, (ptr_t)&kpt_pa->krsvd[i]);
-        set_pte(klptep++, pte);
-    }
-
-    // this is the first LFT we hooked on.
-    // all these LFT are contig in physical address
-    klptep = (pte_t*) &kpt_pa->krsvd[alloc.pt_usage];
-    
-    // Ensure the size of kernel is within the reservation
-    int remain = KEXEC_RSVD - table_usage;
-    pfn_t kimg_pagecount = 
-        pfn(__far(__kexec_end) - __far(__kexec_start));
-    if (kimg_pagecount > remain * _PAGE_LEVEL_SIZE) {
-        // ERROR: require more pages
-        //  here should do something else other than head into blocking
-        asm("ud2");
-    }
-
-    // kernel .text
-    pfn_t ktext_end = pfn(to_kphysical(__far(__kexec_text_end)));
-    pfn_t i = pfn(to_kphysical(kstart));
-
-    klptep += i;
-    pte = pte_setprot(pte, KERNEL_EXEC);
-    for (; i < ktext_end; i++) {
-        pte = pte_setpaddr(pte, page_addr(i));
-        set_pte(klptep, pte);
+    kpt_mktable_at(&ptw, KMAP, gran);
+    kpt_mktable_at(&ptw, PMAP, gran);
 
-        klptep++;
-    }
-    
-    pfn_t kimg_end = pfn(to_kphysical(__far(__kexec_end)));
+    kpt_migrate_highmem(&ptw);
 
-    // all remaining kernel sections
-    pte = pte_setprot(pte, KERNEL_DATA);
-    for (; i < kimg_end; i++) {
-        pte = pte_setpaddr(pte, page_addr(i));
-        set_pte(klptep, pte);
+    pte = mkpte(__ptr(ptw.root), KERNEL_PGTAB);
+    kpt_set_ptes(&ptw, VMS_SELF, pte, L0T_SIZE, 1);
 
-        klptep++;
-    }
-
-    // Build up self-reference
-    lvl_i = va_level_index(VMS_SELF, L0T_SIZE);
-    pte   = mkpte_root(__ptr(kpt_pa), KERNEL_DATA);
-    set_pte(boot_l0tep + lvl_i, pte);
+    return __ptr(ptw.root);
 }
 
-
 ptr_t boot_text
 remap_kernel()
-{
-    ptr_t kmap_pa = to_kphysical(&kpt);
-    
+{    
     asm volatile("movq %1, %%rdi\n"
                  "rep stosb\n" ::"c"(sizeof(kpt)),
-                 "r"(kmap_pa),
+                 "r"(to_kphysical(&kpt)),
                  "a"(0)
                  : "rdi", "memory");
 
-    do_remap();
-
-    return kmap_pa;
+    return do_remap();
 }
\ No newline at end of file