Boot framework rework (#45)
[lunaix-os.git] / lunaix-os / arch / x86 / boot / i386 / kremap32.c
1 #define __BOOT_CODE__
2
3 #include <lunaix/mm/pagetable.h>
4 #include <lunaix/compiler.h>
5 #include <lunaix/sections.h>
6
7 #include <sys/boot/bstage.h>
8 #include <sys/mm/mm_defs.h>
9
10 #define PF_X 0x1
11 #define PF_W 0x2
12 #define ksection_maps autogen_name(ksecmap)
13
14 extern_autogen(ksecmap);
15
16 bridge_farsym(__kexec_text_start);
17 bridge_farsym(ksection_maps);
18
19 // define the initial page table layout
20 struct kernel_map;
21
22 static struct kernel_map kernel_pt __section(".kpg");
23 export_symbol(debug, boot, kernel_pt);
24
25 struct kernel_map 
26 {
27     pte_t l0t[_PAGE_LEVEL_SIZE];
28     pte_t pg_mnt[_PAGE_LEVEL_SIZE];
29
30     struct {
31         pte_t _lft[_PAGE_LEVEL_SIZE];
32     } kernel_lfts[16];
33 } align(4);
34
35 static void boot_text
36 do_remap()
37 {
38     struct kernel_map* kpt_pa = (struct kernel_map*)to_kphysical(&kernel_pt);
39     
40     size_t mia_casa_i   = pfn_at(KERNEL_RESIDENT, L0T_SIZE);
41     pte_t* klptep       = (pte_t*) &kpt_pa->l0t[mia_casa_i];
42     pte_t* ktep         = (pte_t*)  kpt_pa->kernel_lfts;    
43     pte_t* boot_l0tep   = (pte_t*)  kpt_pa;
44
45     set_pte(boot_l0tep, pte_mkhuge(mkpte_prot(KERNEL_PGTAB)));
46
47     // --- 将内核重映射至高半区 ---
48
49     // Hook the kernel reserved LFTs onto L0T
50     pte_t pte = mkpte((ptr_t)ktep, KERNEL_PGTAB);
51     
52     for (u32_t i = 0; i < KEXEC_RSVD; i++) {
53         pte = pte_setpaddr(pte, (ptr_t)&kpt_pa->kernel_lfts[i]);
54         set_pte(klptep, pte);
55
56         klptep++;
57     }
58
59     struct ksecmap* maps;
60     struct ksection* section;
61     pfn_t pgs;
62     pte_t *kmntep;
63
64     maps = (struct ksecmap*)to_kphysical(__far(ksection_maps));
65     ktep += pfn(to_kphysical(__far(__kexec_text_start)));
66
67     // Ensure the size of kernel is within the reservation
68     if (leaf_count(maps->ksize) > KEXEC_RSVD * _PAGE_LEVEL_SIZE) 
69     {
70         // ERROR: require more pages
71         //  here should do something else other than head into blocking
72         asm("ud2");
73     }
74
75     // Now, map the sections
76
77     for (unsigned int i = 0; i < maps->num; i++)
78     {
79         section = &maps->secs[i];
80
81         if (section->va < KERNEL_RESIDENT) {
82             continue;
83         }
84
85         pte = mkpte_prot(KERNEL_RDONLY);
86         if ((section->flags & PF_X)) {
87             pte = pte_mkexec(pte);
88         }
89         if ((section->flags & PF_W)) {
90             pte = pte_mkwritable(pte);
91         }
92
93         pgs = leaf_count(section->size);
94         for (pfn_t j = 0; j < pgs; j++)
95         {
96             pte = pte_setpaddr(pte, section->pa + page_addr(j));
97             set_pte(ktep, pte);
98
99             ktep++;
100         }
101     }
102
103     // set mount point
104     kmntep = (pte_t*) &kpt_pa->l0t[pfn_at(PG_MOUNT_1, L0T_SIZE)];
105     set_pte(kmntep, mkpte((ptr_t)kpt_pa->pg_mnt, KERNEL_PGTAB));
106
107     // Build up self-reference
108     int level = (VMS_SELF / L0T_SIZE) & _PAGE_LEVEL_MASK;
109     
110     pte = mkpte_root((ptr_t)kpt_pa, KERNEL_PGTAB);
111     set_pte(&boot_l0tep[level], pte);
112 }
113
114 ptr_t boot_text
115 remap_kernel()
116 {
117     ptr_t kmap_pa = to_kphysical(&kernel_pt);
118     for (size_t i = 0; i < sizeof(kernel_pt); i++) {
119         ((u8_t*)kmap_pa)[i] = 0;
120     }
121
122     do_remap();
123
124     return kmap_pa;
125 }