1 #include <lunaix/mm/page.h>
2 #include <lunaix/mm/vmm.h>
3 #include <lunaix/mm/pmm.h>
4 #include <libc/string.h>
6 // TODO: Move these nasty inline asm stuff into hal
7 // These should be arch dependent
13 "andl $0xfffff000, %0"
20 void set_pd(ptd_t* pd) {
24 "andl $0xfffff000, %%eax\n"
33 // TODO: something here?
36 ptd_t* vmm_init_pd() {
37 ptd_t* dir = pmm_alloc_page();
38 for (size_t i = 0; i < 1024; i++)
43 // 自己映射自己,方便我们在软件层面进行查表地址转换
44 dir[1023] = PDE(T_SELF_REF_PERM, dir);
49 void* vmm_map_page(void* va, void* pa, pt_attr dattr, pt_attr tattr) {
55 uintptr_t pd_offset = PD_INDEX(va);
56 uintptr_t pt_offset = PT_INDEX(va);
57 ptd_t* ptd = PTD_BASE_VADDR;
59 // 在页表与页目录中找到一个可用的空位进行映射(位于va或其附近)
60 ptd_t* pde = ptd[pd_offset];
61 pt_t* pt = (uintptr_t)(PT_BASE_VADDR | (pd_offset << 12));
62 while (pde && pd_offset < 1024) {
63 if (pt_offset == 1024) {
67 pt = (pt_t*)PT_VADDR(pd_offset);
69 // 页表有空位,只需要开辟一个新的 PTE
70 if (pt && !pt[pt_offset]) {
71 pt[pt_offset] = PTE(tattr, pa);
72 return V_ADDR(pd_offset, pt_offset, PG_OFFSET(va));
78 if (pd_offset > 1024) {
82 // 页目录有空位,需要开辟一个新的 PDE
83 uint8_t* new_pt_pa = pmm_alloc_page();
90 ptd[pd_offset] = PDE(dattr, new_pt_pa);
91 memset((void*)PT_VADDR(pd_offset), 0, PM_PAGE_SIZE);
93 pt[pt_offset] = PTE(tattr, pa);
95 return V_ADDR(pd_offset, pt_offset, PG_OFFSET(va));
98 void* vmm_alloc_page(void* vpn, pt_attr dattr, pt_attr tattr) {
99 void* pp = pmm_alloc_page();
100 void* result = vmm_map_page(vpn, pp, dattr, tattr);
107 void vmm_unmap_page(void* vpn) {
108 uintptr_t pd_offset = PD_INDEX(vpn);
109 uintptr_t pt_offset = PT_INDEX(vpn);
110 ptd_t* self_pde = PTD_BASE_VADDR;
112 ptd_t pde = self_pde[pd_offset];
115 pt_t* pt = (pt_t*)PT_VADDR(pd_offset);
116 uint32_t pte = pt[pt_offset];
117 if (IS_CACHED(pte) && pmm_free_page(pte)) {
120 __asm__("invlpg (%0)" :: "r"((uintptr_t)vpn) : "memory");
127 void* vmm_v2p(void* va) {
128 uintptr_t pd_offset = PD_INDEX(va);
129 uintptr_t pt_offset = PT_INDEX(va);
130 uintptr_t po = PG_OFFSET(va);
131 ptd_t* self_pde = PTD_BASE_VADDR;
133 ptd_t pde = self_pde[pd_offset];
135 pt_t pte = ((pt_t*)PT_VADDR(pd_offset))[pt_offset];
137 uintptr_t ppn = pte >> 12;
138 return (void*)P_ADDR(ppn, po);