chore: make things more general
[lunaix-os.git] / lunaix-os / kernel / mm / vmm.c
1 #include <hal/cpu.h>
2 #include <klibc/string.h>
3 #include <lunaix/mm/pmm.h>
4 #include <lunaix/mm/vmm.h>
5 #include <lunaix/spike.h>
6
7 void
8 vmm_init()
9 {
10     // XXX: something here?
11 }
12
13 x86_page_table*
14 vmm_init_pd()
15 {
16     x86_page_table* dir =
17       (x86_page_table*)pmm_alloc_page(KERNEL_PID, PP_FGPERSIST);
18     for (size_t i = 0; i < PG_MAX_ENTRIES; i++) {
19         dir->entry[i] = PTE_NULL;
20     }
21
22     // 递归映射,方便我们在软件层面进行查表地址转换
23     dir->entry[PG_MAX_ENTRIES - 1] = NEW_L1_ENTRY(T_SELF_REF_PERM, dir);
24
25     return dir;
26 }
27
28 int
29 vmm_set_mapping(uintptr_t mnt,
30                 uintptr_t va,
31                 uintptr_t pa,
32                 pt_attr attr,
33                 int options)
34 {
35     assert((uintptr_t)va % PG_SIZE == 0);
36
37     uintptr_t l1_inx = L1_INDEX(va);
38     uintptr_t l2_inx = L2_INDEX(va);
39     x86_page_table* l1pt = (x86_page_table*)(mnt | (1023 << 12));
40     x86_page_table* l2pt = (x86_page_table*)(mnt | (l1_inx << 12));
41
42     // See if attr make sense
43     assert(attr <= 128);
44
45     if (!l1pt->entry[l1_inx]) {
46         x86_page_table* new_l1pt_pa = pmm_alloc_page(KERNEL_PID, PP_FGPERSIST);
47
48         // 物理内存已满!
49         if (!new_l1pt_pa) {
50             return 0;
51         }
52
53         // This must be writable
54         l1pt->entry[l1_inx] = NEW_L1_ENTRY(attr | PG_WRITE, new_l1pt_pa);
55         memset((void*)l2pt, 0, PG_SIZE);
56     } else {
57         x86_pte_t pte = l2pt->entry[l2_inx];
58         if (pte && (options & VMAP_IGNORE)) {
59             return 1;
60         }
61     }
62
63     if (mnt == PD_REFERENCED) {
64         cpu_invplg(va);
65     }
66
67     if ((options & VMAP_NOMAP)) {
68         return 1;
69     }
70
71     l2pt->entry[l2_inx] = NEW_L2_ENTRY(attr, pa);
72     return 1;
73 }
74
75 uintptr_t
76 vmm_del_mapping(uintptr_t mnt, uintptr_t va)
77 {
78     assert(((uintptr_t)va & 0xFFFU) == 0);
79
80     uint32_t l1_index = L1_INDEX(va);
81     uint32_t l2_index = L2_INDEX(va);
82
83     // prevent unmap of recursive mapping region
84     if (l1_index == 1023) {
85         return 0;
86     }
87
88     x86_page_table* l1pt = (x86_page_table*)(mnt | (1023 << 12));
89
90     x86_pte_t l1pte = l1pt->entry[l1_index];
91
92     if (l1pte) {
93         x86_page_table* l2pt = (x86_page_table*)(mnt | (l1_index << 12));
94         x86_pte_t l2pte = l2pt->entry[l2_index];
95
96         cpu_invplg(va);
97         l2pt->entry[l2_index] = PTE_NULL;
98
99         return PG_ENTRY_ADDR(l2pte);
100     }
101
102     return 0;
103 }
104
105 int
106 vmm_lookup(uintptr_t va, v_mapping* mapping)
107 {
108     uint32_t l1_index = L1_INDEX(va);
109     uint32_t l2_index = L2_INDEX(va);
110
111     x86_page_table* l1pt = (x86_page_table*)L1_BASE_VADDR;
112     x86_pte_t l1pte = l1pt->entry[l1_index];
113
114     if (l1pte) {
115         x86_pte_t* l2pte =
116           &((x86_page_table*)L2_VADDR(l1_index))->entry[l2_index];
117         if (l2pte) {
118             mapping->flags = PG_ENTRY_FLAGS(*l2pte);
119             mapping->pa = PG_ENTRY_ADDR(*l2pte);
120             mapping->pn = mapping->pa >> PG_SIZE_BITS;
121             mapping->pte = l2pte;
122             mapping->va = va;
123             return 1;
124         }
125     }
126     return 0;
127 }
128
129 void*
130 vmm_mount_pd(uintptr_t mnt, void* pde)
131 {
132     x86_page_table* l1pt = (x86_page_table*)L1_BASE_VADDR;
133     l1pt->entry[(mnt >> 22)] = NEW_L1_ENTRY(T_SELF_REF_PERM, pde);
134     cpu_invplg(mnt);
135     return mnt;
136 }
137
138 void*
139 vmm_unmount_pd(uintptr_t mnt)
140 {
141     x86_page_table* l1pt = (x86_page_table*)L1_BASE_VADDR;
142     l1pt->entry[(mnt >> 22)] = 0;
143     cpu_invplg(mnt);
144 }