在二级引导器中建立MMU页表数据,目的就是要在内核加载运行之初开启长模式。
为了简化编程,使用长模式下的2MB分页方式。
#define KINITPAGE_PHYADR 0x1000000void init_bstartpages(machbstart_t *mbsp){//顶级页目录u64_t *p = (u64_t *)(KINITPAGE_PHYADR); //16MB地址处//页目录指针u64_t *pdpte = (u64_t *)(KINITPAGE_PHYADR + 0x1000);//页目录u64_t *pde = (u64_t *)(KINITPAGE_PHYADR + 0x2000);//物理地址从0开始u64_t adr = 0;if (1 > move_krlimg(mbsp, (u64_t)(KINITPAGE_PHYADR), (0x1000 * 16 + 0x2000))){kerror("move_krling err");}//将顶级页目录、页目录指针的空间清0for (uint_t mi = 0; mi < PGENTY_SIZE; mi++){p[mi] = 0;pdpte[mi] = 0;}//映射for (uint_t pdei = 0; pdei < 16; pdei++){pdpte[pdei] = (u64_t)((u32_t)pde | KPDPTE_RW | KPDPTE_P);for (uint_t pdeii = 0; pdeii < PGENTY_SIZE; pdeii++){//大页KPDE_PS 2MB, 可读写KPDE_RW, 存在KPDE_Ppde[pdeii] = 0 | adr | KPDE_PS | KPDE_RW | KPDE_P;adr += 0x200000;}pde = (u64_t *)((u32_t)pde + 0x1000);}//让顶级页目录中第0项和第((KRNL_VIRTUAL_ADDRESS_START) >> KPML4_SHIFT)&0x1ff项,指向同一个页目录指针页p[((KRNL_VIRTUAL_ADDRESS_START)>>KPML_4_SHIFT)&0x1ff] = (u64_t)((u32_t)pdpte | KPML4_RW | KPML4_P);p[0] = (u64_t)((u32_t)pdpte | KPML4_RW | KPML4_P);//把页表首地址保存在机器信息结构中。mbsp->mb_pml4padr = (u64_t)(KINITPAGE_PHYADR);mbsp->mb_subpageslen = (u64_t)(0x1000 * 16 + 0x2000);mbsp->mb_kpmapphymemsz = (u64_t)(0x400000000);return;}
