在二级引导器中建立MMU页表数据,目的就是要在内核加载运行之初开启长模式。

    为了简化编程,使用长模式下的2MB分页方式。

    1. #define KINITPAGE_PHYADR 0x1000000
    2. void init_bstartpages(machbstart_t *mbsp)
    3. {
    4. //顶级页目录
    5. u64_t *p = (u64_t *)(KINITPAGE_PHYADR); //16MB地址处
    6. //页目录指针
    7. u64_t *pdpte = (u64_t *)(KINITPAGE_PHYADR + 0x1000);
    8. //页目录
    9. u64_t *pde = (u64_t *)(KINITPAGE_PHYADR + 0x2000);
    10. //物理地址从0开始
    11. u64_t adr = 0;
    12. if (1 > move_krlimg(mbsp, (u64_t)(KINITPAGE_PHYADR), (0x1000 * 16 + 0x2000)))
    13. {
    14. kerror("move_krling err");
    15. }
    16. //将顶级页目录、页目录指针的空间清0
    17. for (uint_t mi = 0; mi < PGENTY_SIZE; mi++)
    18. {
    19. p[mi] = 0;
    20. pdpte[mi] = 0;
    21. }
    22. //映射
    23. for (uint_t pdei = 0; pdei < 16; pdei++)
    24. {
    25. pdpte[pdei] = (u64_t)((u32_t)pde | KPDPTE_RW | KPDPTE_P);
    26. for (uint_t pdeii = 0; pdeii < PGENTY_SIZE; pdeii++)
    27. {
    28. //大页KPDE_PS 2MB, 可读写KPDE_RW, 存在KPDE_P
    29. pde[pdeii] = 0 | adr | KPDE_PS | KPDE_RW | KPDE_P;
    30. adr += 0x200000;
    31. }
    32. pde = (u64_t *)((u32_t)pde + 0x1000);
    33. }
    34. //让顶级页目录中第0项和第((KRNL_VIRTUAL_ADDRESS_START) >> KPML4_SHIFT)&0x1ff项,指向同一个页目录指针页
    35. p[((KRNL_VIRTUAL_ADDRESS_START)>>KPML_4_SHIFT)&0x1ff] = (u64_t)((u32_t)pdpte | KPML4_RW | KPML4_P);
    36. p[0] = (u64_t)((u32_t)pdpte | KPML4_RW | KPML4_P);
    37. //把页表首地址保存在机器信息结构中。
    38. mbsp->mb_pml4padr = (u64_t)(KINITPAGE_PHYADR);
    39. mbsp->mb_subpageslen = (u64_t)(0x1000 * 16 + 0x2000);
    40. mbsp->mb_kpmapphymemsz = (u64_t)(0x400000000);
    41. return;
    42. }