c353d77e0d968cf1f7aa51e53ba9abdd1607ecf3
[lunaix-os.git] / lunaix-os / arch / i386 / boot / kpt_setup.c
1 #define __BOOT_CODE__
2
3 #include <lunaix/mm/pagetable.h>
4 #include <lunaix/compiler.h>
5
6 #include <sys/boot/bstage.h>
7 #include <sys/mm/mm_defs.h>
8
9 // Provided by linker (see linker.ld)
10 extern u8_t __kexec_start[];
11 extern u8_t __kexec_end[];
12 extern u8_t __kexec_text_start[];
13 extern u8_t __kexec_text_end[];
14 extern u8_t __kboot_start[];
15 extern u8_t __kboot_end[];
16
17 // define the initial page table layout
18 struct kernel_map {
19     pte_t l0t[_PAGE_LEVEL_SIZE];
20     pte_t pg_mnt[_PAGE_LEVEL_SIZE];
21
22     struct {
23         pte_t _lft[_PAGE_LEVEL_SIZE];
24     } kernel_lfts[16];
25 } align(4);
26
27 static struct kernel_map kernel_pt __section(".kpg");
28 export_symbol(debug, boot, kernel_pt);
29
30
31 void boot_text
32 _init_page()
33 {
34     struct kernel_map* kpt_pa = (struct kernel_map*)to_kphysical(&kernel_pt);
35
36     pte_t* kl0tep       = (pte_t*) &kpt_pa->l0t[pfn_at(KERNEL_RESIDENT, L0T_SIZE)];
37     pte_t* kl1tep       = (pte_t*)  kpt_pa->kernel_lfts;    
38     pte_t* boot_l0tep   = (pte_t*)  kpt_pa;
39
40     set_pte(boot_l0tep, pte_mkhuge(mkpte_prot(KERNEL_DATA)));
41
42     // --- 将内核重映射至高半区 ---
43
44     // Hook the kernel reserved LFTs onto L0T
45     pte_t pte = mkpte((ptr_t)kl1tep, KERNEL_DATA);
46     
47     for (u32_t i = 0; i < KEXEC_RSVD; i++) {
48         pte = pte_setpaddr(pte, (ptr_t)&kpt_pa->kernel_lfts[i]);
49         set_pte(kl0tep, pte);
50
51         kl0tep++;
52     }
53
54     // Ensure the size of kernel is within the reservation
55     pfn_t kimg_pagecount = 
56         pfn((ptr_t)__kexec_end - (ptr_t)__kexec_start);
57     if (kimg_pagecount > KEXEC_RSVD * _PAGE_LEVEL_SIZE) {
58         // ERROR: require more pages
59         //  here should do something else other than head into blocking
60         asm("ud2");
61     }
62
63     // Now, map the kernel
64
65     pfn_t kimg_end = pfn(to_kphysical(__kexec_end));
66     pfn_t i = pfn(to_kphysical(__kexec_text_start));
67     kl1tep += i;
68
69     // kernel .text
70     pte = pte_setprot(pte, KERNEL_EXEC);
71     pfn_t ktext_end = pfn(to_kphysical(__kexec_text_end));
72     for (; i < ktext_end; i++) {
73         pte = pte_setpaddr(pte, page_addr(i));
74         set_pte(kl1tep, pte);
75
76         kl1tep++;
77     }
78
79     // all remaining kernel sections
80     pte = pte_setprot(pte, KERNEL_DATA);
81     for (; i < kimg_end; i++) {
82         pte = pte_setpaddr(pte, page_addr(i));
83         set_pte(kl1tep, pte);
84
85         kl1tep++;
86     }
87
88     // XXX: Mapping the kernel .rodata section?
89
90     // set mount point
91     pte_t* kmntep = (pte_t*) &kpt_pa->l0t[pfn_at(PG_MOUNT_1, L0T_SIZE)];
92     set_pte(kmntep, mkpte((ptr_t)kpt_pa->pg_mnt, KERNEL_DATA));
93
94     // Build up self-reference
95     pte = mkpte_root((ptr_t)kpt_pa, KERNEL_DATA);
96     set_pte(boot_l0tep + _PAGE_LEVEL_MASK, pte);
97 }
98
99 ptr_t boot_text
100 kpg_init()
101 {
102     ptr_t kmap_pa = to_kphysical(&kernel_pt);
103     for (size_t i = 0; i < sizeof(kernel_pt); i++) {
104         ((u8_t*)kmap_pa)[i] = 0;
105     }
106
107     _init_page();
108
109     return kmap_pa;
110 }