1 #include <libc/string.h>
2 #include <lunaix/mm/page.h>
3 #include <lunaix/mm/pmm.h>
4 #include <lunaix/mm/vmm.h>
6 // TODO: Move these nasty inline asm stuff into hal
7 // These should be arch dependent
13 __asm__("movl %%cr3, %0\n"
14 "andl $0xfffff000, %0"
17 return (ptd_t*)P2V(pd);
24 __asm__("movl %0, %%eax\n"
25 "andl $0xfffff000, %%eax\n"
35 // TODO: something here?
41 ptd_t* dir = pmm_alloc_page();
42 for (size_t i = 0; i < 1024; i++) {
46 // 自己映射自己,方便我们在软件层面进行查表地址转换
47 dir[1023] = PDE(T_SELF_REF_PERM, dir);
53 vmm_map_page(void* va, void* pa, pt_attr dattr, pt_attr tattr)
60 uintptr_t pd_offset = PD_INDEX(va);
61 uintptr_t pt_offset = PT_INDEX(va);
62 ptd_t* ptd = (ptd_t*)PTD_BASE_VADDR;
64 // 在页表与页目录中找到一个可用的空位进行映射(位于va或其附近)
65 ptd_t pde = ptd[pd_offset];
66 pt_t* pt = (pt_t*)PT_VADDR(pd_offset);
67 while (pde && pd_offset < 1024) {
68 if (pt_offset == 1024) {
72 pt = (pt_t*)PT_VADDR(pd_offset);
74 // 页表有空位,只需要开辟一个新的 PTE
75 if (pt && !pt[pt_offset]) {
76 pt[pt_offset] = PTE(tattr, pa);
77 return (void*)V_ADDR(pd_offset, pt_offset, PG_OFFSET(va));
83 if (pd_offset > 1024) {
87 // 页目录有空位,需要开辟一个新的 PDE
88 uint8_t* new_pt_pa = pmm_alloc_page();
95 ptd[pd_offset] = PDE(dattr, new_pt_pa);
97 memset((void*)PT_VADDR(pd_offset), 0, PM_PAGE_SIZE);
98 pt[pt_offset] = PTE(tattr, pa);
100 return (void*)V_ADDR(pd_offset, pt_offset, PG_OFFSET(va));
104 vmm_alloc_page(void* vpn, pt_attr dattr, pt_attr tattr)
106 void* pp = pmm_alloc_page();
107 void* result = vmm_map_page(vpn, pp, dattr, tattr);
115 vmm_unmap_page(void* vpn)
117 uintptr_t pd_offset = PD_INDEX(vpn);
118 uintptr_t pt_offset = PT_INDEX(vpn);
119 ptd_t* self_pde = (ptd_t*)PTD_BASE_VADDR;
121 ptd_t pde = self_pde[pd_offset];
124 pt_t* pt = (pt_t*)PT_VADDR(pd_offset);
125 uint32_t pte = pt[pt_offset];
126 if (IS_CACHED(pte) && pmm_free_page((void*)pte)) {
129 __asm__("invlpg (%0)" ::"r"((uintptr_t)vpn) : "memory");
139 uintptr_t pd_offset = PD_INDEX(va);
140 uintptr_t pt_offset = PT_INDEX(va);
141 uintptr_t po = PG_OFFSET(va);
142 ptd_t* self_pde = (ptd_t*)PTD_BASE_VADDR;
144 ptd_t pde = self_pde[pd_offset];
146 pt_t pte = ((pt_t*)PT_VADDR(pd_offset))[pt_offset];
148 uintptr_t ppn = pte >> 12;
149 return (void*)P_ADDR(ppn, po);