Unifying the Lunaix's Physical Memory Model (#28)
[lunaix-os.git] / lunaix-os / includes / lunaix / mm / pagetable.h
1 #ifndef __LUNAIX_PAGETABLE_H
2 #define __LUNAIX_PAGETABLE_H
3
4 /*
5     Defines page related attributes for different page table
6     hierarchies. In Lunaix, we define five arch-agnostic alias
7     to those arch-dependent hierarchies:
8
9         + L0T: Level-0 Table, the root page table    
10         + L1T: Level-1 Table, indexed by L0P entries 
11         + L2T: Level-2 Table, indexed by L1P entries 
12         + L3T: Level-3 Table, indexed by L2P entries 
13         + LFT: Leaf-Level Table (Level-4), indexed by L3P entries    
14     
15     Therefore, "LnTE" can be used to refer "Entry in a Level-n Table".
16     Consequently, we can further define 
17         
18         + LnTEP - pointer to an entry within LnT
19         + LnTP  - pointer to (the first entry of) LnT
20         
21     To better identify all derived value from virtual and physical 
22     adress, we defines:
23         
24         + Virtual Address Space (VAS):
25           A set of all virtual addresses that can be interpreted
26           by page table walker.
27
28         + Virtual Mappings Space (VMS):
29           A imaginary linear table compose a set of mappings that 
30           define the translation rules from virtual memory address 
31           space to physical memory address. (Note: mappings are stored 
32           in the hierarchy of page tables, however it is transparent, 
33           just as indexing into a big linear table, thus 'imaginary')
34           A VMS is a realisation of a VAS.
35
36         + Virtual Mappings Mounting (VM_MNT or MNT):
37           A subregion within current VAS for where the VA/PA mappings
38           of another VMS are accessible.
39
40         + Page Frame Number (PFN): 
41           Index of a page with it's base size. For most machine, it
42           is 4K. Note, this is not limited to physical address, for 
43           virtual address, this is the index of a virtual page within
44           it's VMS.
45
46         + Virtual Frame Number (VFN):
47           Index of a virtual page within it's parent page table. It's
48           range is bounded aboved by maximium number of PTEs per page
49           table
50
51     In the context of x86 archiecture (regardless x86_32 or x86_64),
52     these naming have the following realisations:
53         
54         + L0T: PD           (32-Bit 2-Level paging)
55                PML4         (4-Level Paging)
56                PML5         (5-Level Paging)
57
58         + L1T: ( N/A )      (32-Bit 2-Level paging)
59                PDP          (4-Level Paging)
60                PML4         (5-Level Paging)
61         
62         + L2T: ( N/A )      (32-Bit 2-Level paging)
63                PD           (4-Level Paging)
64                PDP          (5-Level Paging)
65
66         + L3T: ( N/A )      (32-Bit 2-Level paging)
67                ( N/A )      (4-Level Paging)
68                PD           (5-Level Paging)
69
70         + LFT: Page Table   (All)
71
72         + VAS: 
73                [0, 2^32)    (32-Bit 2-Level paging)
74                [0, 2^48)    (4-Level Paging)
75                [0, 2^57)    (5-Level Paging)
76
77         + PFN (Vitrual): 
78                [0, 2^22)    (32-Bit 2-Level paging)
79                [0, 2^36)    (4-Level Paging)
80                [0, 2^45)    (5-Level Paging)
81         
82         + PFN (Physical):
83                [0, 2^32)    (x86_32)
84                [0, 2^52)    (x86_64, all paging modes)
85
86         + VFN: [0, 1024)    (32-Bit 2-Level paging)
87                [0, 512)     (4-Level Paging)
88                [0, 512)     (5-Level Paging)
89
90     In addition, we also defines VMS_{MASK|SIZE} to provide
91     information about maximium size of addressable virtual 
92     memory space (hence VMS). Which is effectively a 
93     "Level -1 Page" (i.e., _PAGE_Ln_SIZE(-1))
94
95
96 */
97
98 struct __pte;
99 typedef struct __pte pte_t;
100
101
102 #include <sys/mm/pagetable.h>
103 #include <sys/cpu.h>
104
105 #define _LnTEP_AT(vm_mnt, sz)   ( ((vm_mnt) | L0T_MASK) & ~(sz) )
106 #define _L0TEP_AT(vm_mnt)       ( ((vm_mnt) | L0T_MASK) & ~LFT_MASK )
107 #define _L1TEP_AT(vm_mnt)       ( ((vm_mnt) | L0T_MASK) & ~L3T_MASK )
108 #define _L2TEP_AT(vm_mnt)       ( ((vm_mnt) | L0T_MASK) & ~L2T_MASK )
109 #define _L3TEP_AT(vm_mnt)       ( ((vm_mnt) | L0T_MASK) & ~L1T_MASK )
110 #define _LFTEP_AT(vm_mnt)       ( ((vm_mnt) | L0T_MASK) & ~L0T_MASK )
111
112 #define _VM_OF(ptep)            ( (ptr_t)(ptep) & ~L0T_MASK )
113 #define _VM_PFN_OF(ptep)        ( ((ptr_t)(ptep) & L0T_MASK) / sizeof(pte_t) )
114 #define VMS_SELF                ( ~L0T_MASK & VMS_MASK )
115
116 #define __LnTI_OF(ptep, n)\
117     (_VM_PFN_OF(ptep) * LFT_SIZE / L##n##T_SIZE)
118
119 #define __LnTEP(ptep, va, n)\
120     ( (pte_t*)_L##n##TEP_AT(_VM_OF(ptep)) + (((va) & VMS_MASK) / L##n##T_SIZE) )
121
122 #define __LnTEP_OF(ptep, n)\
123     ( (pte_t*)_L##n##TEP_AT(_VM_OF(ptep)) + __LnTI_OF(ptep, n))
124
125 #define __LnTEP_SHIFT_NEXT(ptep)\
126     ( (pte_t*)(_VM_OF(ptep) | ((_VM_PFN_OF(ptep) * LFT_SIZE) & L0T_MASK)) )
127
128 #define _has_LnT(n) (L##n##T_SIZE != LFT_SIZE)
129 #define LnT_ENABLED(n) _has_LnT(n)
130
131 #define ptep_with_level(ptep, lvl_size)                 \
132     ({                                                  \
133         ptr_t __p = _LnTEP_AT(_VM_OF(ptep), lvl_size);  \
134         ((ptr_t)(ptep) & __p) == __p;                   \
135     })
136
137 extern pte_t 
138 alloc_kpage_at(pte_t* ptep, pte_t pte, int order);
139
140 /**
141  * @brief Try page walk to the pte pointed by ptep and 
142  *        allocate any missing level-table en-route
143  * 
144  * @param ptep 
145  * @param va 
146  */
147 void
148 ptep_alloc_hierarchy(pte_t* ptep, ptr_t va, pte_attr_t prot);
149
150 static inline bool
151 __alloc_level(pte_t* ptep, pte_t pte, pte_attr_t prot)
152 {
153     if (!pte_isnull(pte)) {
154         return true;
155     }
156
157     pte = pte_setprot(pte, prot);
158     return !pte_isnull(alloc_kpage_at(ptep, pte, 0));
159 }
160
161 /**
162  * @brief Get the page frame number encoded in ptep
163  * 
164  * @param ptep 
165  * @return ptr_t 
166  */
167 static inline ptr_t
168 ptep_pfn(pte_t* ptep)
169 {
170     return _VM_PFN_OF(ptep);
171 }
172
173 /**
174  * @brief Get the virtual frame number encoded in ptep
175  * 
176  * @param ptep 
177  * @return ptr_t 
178  */
179 static inline unsigned int
180 ptep_vfn(pte_t* ptep)
181 {
182     return ((ptr_t)ptep & PAGE_MASK) / sizeof(pte_t);
183 }
184
185 static inline ptr_t
186 ptep_va(pte_t* ptep, size_t lvl_size)
187 {
188     return ((ptr_t)ptep) / sizeof(pte_t) * lvl_size;
189 }
190
191 static inline ptr_t
192 ptep_vm_mnt(pte_t* ptep)
193 {
194     return _VM_OF(ptep);
195 }
196
197 /**
198  * @brief Make a L0TEP from given ptep
199  * 
200  * @param ptep 
201  * @return pte_t* 
202  */
203 static inline pte_t*
204 mkl0tep(pte_t* ptep)
205 {
206     return __LnTEP_OF(ptep, 0);
207 }
208
209 /**
210  * @brief Make a L1TEP from given ptep
211  * 
212  * @param ptep 
213  * @return pte_t* 
214  */
215 static inline pte_t*
216 mkl1tep(pte_t* ptep)
217 {
218     return __LnTEP_OF(ptep, 1);
219 }
220
221 /**
222  * @brief Make a L2TEP from given ptep
223  * 
224  * @param ptep 
225  * @return pte_t* 
226  */
227 static inline pte_t*
228 mkl2tep(pte_t* ptep)
229 {
230     return __LnTEP_OF(ptep, 2);
231 }
232
233 /**
234  * @brief Make a L3TEP from given ptep
235  * 
236  * @param ptep 
237  * @return pte_t* 
238  */
239 static inline pte_t*
240 mkl3tep(pte_t* ptep)
241 {
242     return __LnTEP_OF(ptep, 3);
243 }
244
245 /**
246  * @brief Create the L1T pointed by L0TE
247  * 
248  * @param l0t_ptep 
249  * @param va 
250  * @return pte_t* 
251  */
252 static inline pte_t*
253 mkl1t(pte_t* l0t_ptep, ptr_t va, pte_attr_t prot)
254 {
255 #if _has_LnT(1)
256     if (!l0t_ptep) {
257         return NULL;
258     }
259
260     pte_t pte = pte_at(l0t_ptep);
261     
262     if (pte_huge(pte)) {
263         return l0t_ptep;
264     }
265     
266     return __alloc_level(l0t_ptep, pte, prot) 
267                 ? __LnTEP(l0t_ptep, va, 1) 
268                 : NULL;
269 #else
270     return l0t_ptep;
271 #endif
272 }
273
274 /**
275  * @brief Create the L2T pointed by L1TE
276  * 
277  * @param l0t_ptep 
278  * @param va 
279  * @return pte_t* 
280  */
281 static inline pte_t*
282 mkl2t(pte_t* l1t_ptep, ptr_t va, pte_attr_t prot)
283 {
284 #if _has_LnT(2)
285     if (!l1t_ptep) {
286         return NULL;
287     }
288
289     pte_t pte = pte_at(l1t_ptep);
290     
291     if (pte_huge(pte)) {
292         return l1t_ptep;
293     }
294
295     return __alloc_level(l1t_ptep, pte, prot) 
296                 ? __LnTEP(l1t_ptep, va, 2) 
297                 : NULL;
298 #else
299     return l1t_ptep;
300 #endif
301 }
302
303 /**
304  * @brief Create the L3T pointed by L2TE
305  * 
306  * @param l0t_ptep 
307  * @param va 
308  * @return pte_t* 
309  */
310 static inline pte_t*
311 mkl3t(pte_t* l2t_ptep, ptr_t va, pte_attr_t prot)
312 {
313 #if _has_LnT(3)
314     if (!l2t_ptep) {
315         return NULL;
316     }
317  
318     pte_t pte = pte_at(l2t_ptep);
319     
320     if (pte_huge(pte)) {
321         return l2t_ptep;
322     }
323
324     return __alloc_level(l2t_ptep, pte, prot) 
325                 ? __LnTEP(l2t_ptep, va, 3) 
326                 : NULL;
327 #else
328     return l2t_ptep;
329 #endif
330 }
331
332 /**
333  * @brief Create the LFT pointed by L3TE
334  * 
335  * @param l0t_ptep 
336  * @param va 
337  * @return pte_t* 
338  */
339 static inline pte_t*
340 mklft(pte_t* l3t_ptep, ptr_t va, pte_attr_t prot)
341 {
342     if (!l3t_ptep) {
343         return NULL;
344     }
345
346     pte_t pte = pte_at(l3t_ptep);
347     
348     if (pte_huge(pte)) {
349         return l3t_ptep;
350     }
351
352     return __alloc_level(l3t_ptep, pte, prot) 
353                 ? __LnTEP(l3t_ptep, va, F) 
354                 : NULL;
355 }
356
357 static inline pte_t*
358 getl1tep(pte_t* l0t_ptep, ptr_t va) {
359 #if _has_LnT(1)
360     return __LnTEP(l0t_ptep, va, 1); 
361 #else
362     return l0t_ptep;
363 #endif
364 }
365
366 static inline pte_t*
367 getl2tep(pte_t* l1t_ptep, ptr_t va) {
368 #if _has_LnT(2)
369     return __LnTEP(l1t_ptep, va, 2);
370 #else
371     return l1t_ptep;
372 #endif
373 }
374
375 static inline pte_t*
376 getl3tep(pte_t* l2t_ptep, ptr_t va) {
377 #if _has_LnT(3)
378     return __LnTEP(l2t_ptep, va, 3); 
379 #else
380     return l2t_ptep;
381 #endif
382 }
383
384 static inline pte_t*
385 getlftep(pte_t* l3t_ptep, ptr_t va) {
386     return __LnTEP(l3t_ptep, va, F);
387 }
388
389 static inline unsigned int
390 l0te_index(pte_t* ptep) {
391     return __LnTI_OF(ptep, 1);
392 }
393
394 static inline unsigned int
395 l1te_index(pte_t* ptep) {
396     return __LnTI_OF(ptep, 2);
397 }
398
399 static inline unsigned int
400 l2te_index(pte_t* ptep) {
401     return __LnTI_OF(ptep, 3);
402 }
403
404 static inline unsigned int
405 l3te_index(pte_t* ptep) {
406     return __LnTI_OF(ptep, F);
407 }
408
409 static inline pfn_t
410 pfn(ptr_t addr) {
411     return (addr / PAGE_SIZE) & VMS_MASK;
412 }
413
414 static inline size_t
415 leaf_count(size_t size) {
416     return (size + PAGE_MASK) / PAGE_SIZE;
417 }
418
419 static inline size_t
420 page_count(size_t size, size_t page_size) {
421     return (size + (page_size - 1)) / page_size;
422 }
423
424 static inline unsigned int
425 va_offset(ptr_t addr) {
426     return addr & PAGE_MASK;
427 }
428
429 static inline ptr_t
430 page_addr(ptr_t pfn) {
431     return pfn * PAGE_SIZE;
432 }
433
434 static inline ptr_t
435 page_aligned(ptr_t va) {
436     return va & ~PAGE_MASK;
437 }
438
439 static inline ptr_t
440 page_upaligned(ptr_t va) {
441     return (va + PAGE_MASK) & ~PAGE_MASK;
442 }
443
444 static inline ptr_t
445 napot_aligned(ptr_t va, size_t napot_sz) {
446     return va & ~(napot_sz - 1);
447 }
448
449 static inline ptr_t
450 napot_upaligned(ptr_t va, size_t napot_sz) {
451     return (va + napot_sz - 1) & ~(napot_sz - 1);
452 }
453
454 static inline pte_t*
455 mkptep_va(ptr_t vm_mnt, ptr_t vaddr)
456 {
457     return (pte_t*)(vm_mnt & ~L0T_MASK) + pfn(vaddr);
458 }
459
460 static inline pte_t*
461 mkptep_pn(ptr_t vm_mnt, ptr_t pn)
462 {
463     return (pte_t*)(vm_mnt & ~L0T_MASK) + (pn & L0T_MASK);
464 }
465
466 static inline pfn_t
467 pfn_at(ptr_t va, size_t lvl_size) {
468     return va / lvl_size;
469 }
470
471
472 /**
473  * @brief Shift the ptep such that it points to an
474  *        immediate lower level of page table
475  * 
476  * @param ptep 
477  * @return pte_t* 
478  */
479 static inline pte_t*
480 ptep_step_into(pte_t* ptep)
481 {
482     return __LnTEP_SHIFT_NEXT(ptep);
483 }
484
485 /**
486  * @brief Shift the ptep such that it points to an
487  *        immediate upper level of page table
488  * 
489  * @param ptep 
490  * @return pte_t* 
491  */
492 static inline pte_t*
493 ptep_step_out(pte_t* ptep)
494 {
495     ptr_t unshifted = (ptr_t)mkptep_pn(VMS_SELF, ptep_pfn(ptep));
496     return mkptep_va(_VM_OF(ptep), unshifted);
497 }
498
499 /**
500  * @brief Make a L0TEP from given mnt and va
501  * 
502  * @param ptep 
503  * @return pte_t* 
504  */
505 static inline pte_t*
506 mkl0tep_va(ptr_t mnt, ptr_t va)
507 {
508     return mkl0tep(mkptep_va(mnt, va));
509 }
510
511 static inline bool
512 pt_last_level(int level)
513 {
514     return level == _PTW_LEVEL - 1;
515 }
516
517 static inline ptr_t
518 va_mntpoint(ptr_t va)
519 {
520     return _VM_OF(va);
521 }
522
523 static inline ptr_t
524 va_actual(ptr_t va)
525 {
526     return page_addr(_VM_OF(va) ^ va);
527 }
528
529 #endif /* __LUNAIX_PAGETABLE_H */