Support to multi-threading and pthread interface (POSIX.1-2008) (#23)
[lunaix-os.git] / lunaix-os / kernel / mm / vmm.c
1 #include <klibc/string.h>
2 #include <lunaix/mm/pmm.h>
3 #include <lunaix/mm/vmm.h>
4 #include <lunaix/spike.h>
5 #include <lunaix/syslog.h>
6
7 #include <sys/cpu.h>
8 #include <sys/mm/mm_defs.h>
9
10 LOG_MODULE("VMM")
11
12 void
13 vmm_init()
14 {
15     // XXX: something here?
16 }
17
18 x86_page_table*
19 vmm_init_pd()
20 {
21     x86_page_table* dir =
22       (x86_page_table*)pmm_alloc_page(PP_FGPERSIST);
23     for (size_t i = 0; i < PG_MAX_ENTRIES; i++) {
24         dir->entry[i] = PTE_NULL;
25     }
26
27     // 递归映射,方便我们在软件层面进行查表地址转换
28     dir->entry[PG_MAX_ENTRIES - 1] = NEW_L1_ENTRY(T_SELF_REF_PERM, dir);
29
30     return dir;
31 }
32
33 int
34 vmm_set_mapping(ptr_t mnt, ptr_t va, ptr_t pa, pt_attr attr, int options)
35 {
36     assert((ptr_t)va % PG_SIZE == 0);
37
38     ptr_t l1_inx = L1_INDEX(va);
39     ptr_t l2_inx = L2_INDEX(va);
40     x86_page_table* l1pt = (x86_page_table*)(mnt | (1023 << 12));
41     x86_page_table* l2pt = (x86_page_table*)(mnt | (l1_inx << 12));
42
43     // See if attr make sense
44     assert(attr <= 128);
45
46     x86_pte_t* l1pte = &l1pt->entry[l1_inx];
47     if (!*l1pte) {
48         x86_page_table* new_l1pt_pa =
49           (x86_page_table*)pmm_alloc_page(PP_FGPERSIST);
50
51         // 物理内存已满!
52         if (!new_l1pt_pa) {
53             return 0;
54         }
55
56         // This must be writable
57         *l1pte = NEW_L1_ENTRY(attr | PG_WRITE | PG_PRESENT, new_l1pt_pa);
58
59         // make sure our new l2 table is visible to CPU
60         cpu_flush_page((ptr_t)l2pt);
61
62         memset((void*)l2pt, 0, PG_SIZE);
63     } else {
64         if ((attr & PG_ALLOW_USER) && !(*l1pte & PG_ALLOW_USER)) {
65             *l1pte |= PG_ALLOW_USER;
66         }
67
68         x86_pte_t pte = l2pt->entry[l2_inx];
69         if (pte && (options & VMAP_IGNORE)) {
70             return 1;
71         }
72     }
73
74     if (mnt == VMS_SELF) {
75         cpu_flush_page(va);
76     }
77
78     if ((options & VMAP_NOMAP)) {
79         return 1;
80     }
81
82     if (!(options & VMAP_GUARDPAGE)) {
83         l2pt->entry[l2_inx] = NEW_L2_ENTRY(attr, pa);
84     } else {
85         l2pt->entry[l2_inx] = MEMGUARD;
86     }
87     
88     return 1;
89 }
90
91 ptr_t
92 vmm_del_mapping(ptr_t mnt, ptr_t va)
93 {
94     assert(((ptr_t)va & 0xFFFU) == 0);
95
96     u32_t l1_index = L1_INDEX(va);
97     u32_t l2_index = L2_INDEX(va);
98
99     // prevent unmap of recursive mapping region
100     if (l1_index == 1023) {
101         return 0;
102     }
103
104     x86_page_table* l1pt = (x86_page_table*)(mnt | (1023 << 12));
105
106     x86_pte_t l1pte = l1pt->entry[l1_index];
107
108     if (l1pte) {
109         x86_page_table* l2pt = (x86_page_table*)(mnt | (l1_index << 12));
110         x86_pte_t l2pte = l2pt->entry[l2_index];
111
112         cpu_flush_page(va);
113         l2pt->entry[l2_index] = PTE_NULL;
114
115         return PG_ENTRY_ADDR(l2pte);
116     }
117
118     return 0;
119 }
120
121 int
122 vmm_lookup(ptr_t va, v_mapping* mapping)
123 {
124     return vmm_lookupat(VMS_SELF, va, mapping);
125 }
126
127 int
128 vmm_lookupat(ptr_t mnt, ptr_t va, v_mapping* mapping)
129 {
130     u32_t l1_index = L1_INDEX(va);
131     u32_t l2_index = L2_INDEX(va);
132
133     x86_page_table* l1pt = (x86_page_table*)(mnt | 1023 << 12);
134     x86_pte_t l1pte = l1pt->entry[l1_index];
135
136     if (l1pte) {
137         x86_pte_t* l2pte =
138           &((x86_page_table*)(mnt | (l1_index << 12)))->entry[l2_index];
139
140         if (l2pte) {
141             mapping->flags = PG_ENTRY_FLAGS(*l2pte);
142             mapping->pa = PG_ENTRY_ADDR(*l2pte);
143             mapping->pn = mapping->pa >> PG_SIZE_BITS;
144             mapping->pte = l2pte;
145             mapping->va = va;
146             return 1;
147         }
148     }
149
150     return 0;
151 }
152
153 ptr_t
154 vmm_v2p(ptr_t va)
155 {
156     u32_t l1_index = L1_INDEX(va);
157     u32_t l2_index = L2_INDEX(va);
158
159     x86_page_table* l1pt = (x86_page_table*)L1_BASE_VADDR;
160     x86_pte_t l1pte = l1pt->entry[l1_index];
161
162     if (l1pte) {
163         x86_pte_t* l2pte =
164           &((x86_page_table*)L2_VADDR(l1_index))->entry[l2_index];
165
166         if (l2pte) {
167             return PG_ENTRY_ADDR(*l2pte) | ((ptr_t)va & 0xfff);
168         }
169     }
170     return 0;
171 }
172
173 ptr_t
174 vmm_v2pat(ptr_t mnt, ptr_t va)
175 {
176     u32_t l1_index = L1_INDEX(va);
177     u32_t l2_index = L2_INDEX(va);
178
179     x86_page_table* l1pt = (x86_page_table*)(mnt | 1023 << 12);
180     x86_pte_t l1pte = l1pt->entry[l1_index];
181
182     if (l1pte) {
183         x86_pte_t* l2pte =
184           &((x86_page_table*)(mnt | (l1_index << 12)))->entry[l2_index];
185
186         if (l2pte) {
187             return PG_ENTRY_ADDR(*l2pte) | ((ptr_t)va & 0xfff);
188         }
189     }
190     return 0;
191 }
192
193 ptr_t
194 vmm_mount_pd(ptr_t mnt, ptr_t pde)
195 {
196     assert(pde);
197
198     x86_page_table* l1pt = (x86_page_table*)L1_BASE_VADDR;
199     l1pt->entry[(mnt >> 22)] = NEW_L1_ENTRY(T_SELF_REF_PERM, pde);
200     cpu_flush_page(mnt);
201     return mnt;
202 }
203
204 ptr_t
205 vmm_unmount_pd(ptr_t mnt)
206 {
207     x86_page_table* l1pt = (x86_page_table*)L1_BASE_VADDR;
208     l1pt->entry[(mnt >> 22)] = 0;
209     cpu_flush_page(mnt);
210     return mnt;
211 }
212
213 ptr_t
214 vmm_dup_page(ptr_t pa)
215 {
216     ptr_t new_ppg = pmm_alloc_page(0);
217     vmm_set_mapping(VMS_SELF, PG_MOUNT_3, new_ppg, PG_PREM_RW, VMAP_NULL);
218     vmm_set_mapping(VMS_SELF, PG_MOUNT_4, pa, PG_PREM_RW, VMAP_NULL);
219
220     asm volatile("movl %1, %%edi\n"
221                  "movl %2, %%esi\n"
222                  "rep movsl\n" ::"c"(1024),
223                  "r"(PG_MOUNT_3),
224                  "r"(PG_MOUNT_4)
225                  : "memory", "%edi", "%esi");
226
227     vmm_del_mapping(VMS_SELF, PG_MOUNT_3);
228     vmm_del_mapping(VMS_SELF, PG_MOUNT_4);
229
230     return new_ppg;
231 }