Merge branch 'master' into isa/arm64
[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 <asm/mempart.h>
103 #include <asm/pagetable.h>
104 #include <asm/cpu.h>
105
106 #define VMS_SELF                VMS_SELF_MOUNT
107 #define VMS_SELF_L0TI           (__index(VMS_SELF_MOUNT) / L0T_SIZE)
108
109 #define _LnT_LEVEL_SIZE(n)      ( L##n##T_SIZE / PAGE_SIZE )
110 #define _LFTEP_SELF             ( __index(VMS_SELF) )
111 #define _L3TEP_SELF             ( _LFTEP_SELF | (_LFTEP_SELF / _LnT_LEVEL_SIZE(3)) )
112 #define _L2TEP_SELF             ( _L3TEP_SELF | (_LFTEP_SELF / _LnT_LEVEL_SIZE(2)) )
113 #define _L1TEP_SELF             ( _L2TEP_SELF | (_LFTEP_SELF / _LnT_LEVEL_SIZE(1)) )
114 #define _L0TEP_SELF             ( _L1TEP_SELF | (_LFTEP_SELF / _LnT_LEVEL_SIZE(0)) )
115
116 #define _L0TEP_AT(vm_mnt)       ( ((vm_mnt) | (_L0TEP_SELF & L0T_MASK)) )
117 #define _L1TEP_AT(vm_mnt)       ( ((vm_mnt) | (_L1TEP_SELF & L0T_MASK)) )
118 #define _L2TEP_AT(vm_mnt)       ( ((vm_mnt) | (_L2TEP_SELF & L0T_MASK)) )
119 #define _L3TEP_AT(vm_mnt)       ( ((vm_mnt) | (_L3TEP_SELF & L0T_MASK)) )
120 #define _LFTEP_AT(vm_mnt)       ( ((vm_mnt) | (_LFTEP_SELF & L0T_MASK)) )
121
122 #define _VM_OF(ptep)            ( (ptr_t)(ptep) & ~L0T_MASK )
123 #define _VM_PFN_OF(ptep)        ( ((ptr_t)(ptep) & L0T_MASK) / sizeof(pte_t) )
124
125 #define __LnTI_OF(ptep, n)\
126     ( __index(_VM_PFN_OF(ptep) * LFT_SIZE / L##n##T_SIZE) )
127
128 #define __LnTEP(ptep, va, n)\
129     ( (pte_t*)_L##n##TEP_AT(_VM_OF(ptep)) + (__index(va) / L##n##T_SIZE) )
130
131 #define __LnTEP_OF(ptep, n)\
132     ( (pte_t*)_L##n##TEP_AT(_VM_OF(ptep)) + __LnTI_OF(ptep, n))
133
134 #define __LnTEP_SHIFT_NEXT(ptep)\
135     ( (pte_t*)(_VM_OF(ptep) | ((_VM_PFN_OF(ptep) * LFT_SIZE) & L0T_MASK)) )
136
137 #define _has_LnT(n) (L##n##T_SIZE != LFT_SIZE)
138 #define LnT_ENABLED(n) _has_LnT(n)
139
140 extern pte_t 
141 alloc_kpage_at(pte_t* ptep, pte_t pte, int order);
142
143 /**
144  * @brief Try page walk to the pte pointed by ptep and 
145  *        allocate any missing level-table en-route
146  * 
147  * @param ptep 
148  * @param va 
149  */
150 void
151 ptep_alloc_hierarchy(pte_t* ptep, ptr_t va, pte_attr_t prot);
152
153 static inline bool
154 __alloc_level(pte_t* ptep, pte_t pte, pte_attr_t prot)
155 {
156     if (!pte_isnull(pte)) {
157         return true;
158     }
159
160     pte = pte_setprot(pte, prot);
161     return !pte_isnull(alloc_kpage_at(ptep, pte, 0));
162 }
163
164 /**
165  * @brief Get the page frame number encoded in ptep
166  * 
167  * @param ptep 
168  * @return ptr_t 
169  */
170 static inline ptr_t
171 ptep_pfn(pte_t* ptep)
172 {
173     return _VM_PFN_OF(ptep);
174 }
175
176 /**
177  * @brief Get the virtual frame number encoded in ptep
178  * 
179  * @param ptep 
180  * @return ptr_t 
181  */
182 static inline unsigned int
183 ptep_vfn(pte_t* ptep)
184 {
185     return ((ptr_t)ptep & PAGE_MASK) / sizeof(pte_t);
186 }
187
188 static inline ptr_t
189 ptep_va(pte_t* ptep, size_t lvl_size)
190 {
191     return __vaddr(ptep_pfn(ptep) * lvl_size);
192 }
193
194 static inline ptr_t
195 ptep_vm_mnt(pte_t* ptep)
196 {
197     return __vaddr(_VM_OF(ptep));
198 }
199
200 /**
201  * @brief Make a L0TEP from given ptep
202  * 
203  * @param ptep 
204  * @return pte_t* 
205  */
206 static inline pte_t*
207 mkl0tep(pte_t* ptep)
208 {
209     return __LnTEP_OF(ptep, 0);
210 }
211
212 /**
213  * @brief Make a L1TEP from given ptep
214  * 
215  * @param ptep 
216  * @return pte_t* 
217  */
218 static inline pte_t*
219 mkl1tep(pte_t* ptep)
220 {
221     return __LnTEP_OF(ptep, 1);
222 }
223
224 /**
225  * @brief Make a L2TEP from given ptep
226  * 
227  * @param ptep 
228  * @return pte_t* 
229  */
230 static inline pte_t*
231 mkl2tep(pte_t* ptep)
232 {
233     return __LnTEP_OF(ptep, 2);
234 }
235
236 /**
237  * @brief Make a L3TEP from given ptep
238  * 
239  * @param ptep 
240  * @return pte_t* 
241  */
242 static inline pte_t*
243 mkl3tep(pte_t* ptep)
244 {
245     return __LnTEP_OF(ptep, 3);
246 }
247
248 /**
249  * @brief Create the L1T pointed by L0TE
250  * 
251  * @param l0t_ptep 
252  * @param va 
253  * @return pte_t* 
254  */
255 static inline pte_t*
256 mkl1t(pte_t* l0t_ptep, ptr_t va, pte_attr_t prot)
257 {
258 #if _has_LnT(1)
259     if (!l0t_ptep) {
260         return NULL;
261     }
262
263     pte_t pte = pte_at(l0t_ptep);
264     
265     if (pte_huge(pte)) {
266         return l0t_ptep;
267     }
268     
269     return __alloc_level(l0t_ptep, pte, prot) 
270                 ? __LnTEP(l0t_ptep, va, 1) 
271                 : NULL;
272 #else
273     return l0t_ptep;
274 #endif
275 }
276
277 /**
278  * @brief Create the L2T pointed by L1TE
279  * 
280  * @param l0t_ptep 
281  * @param va 
282  * @return pte_t* 
283  */
284 static inline pte_t*
285 mkl2t(pte_t* l1t_ptep, ptr_t va, pte_attr_t prot)
286 {
287 #if _has_LnT(2)
288     if (!l1t_ptep) {
289         return NULL;
290     }
291
292     pte_t pte = pte_at(l1t_ptep);
293     
294     if (pte_huge(pte)) {
295         return l1t_ptep;
296     }
297
298     return __alloc_level(l1t_ptep, pte, prot) 
299                 ? __LnTEP(l1t_ptep, va, 2) 
300                 : NULL;
301 #else
302     return l1t_ptep;
303 #endif
304 }
305
306 /**
307  * @brief Create the L3T pointed by L2TE
308  * 
309  * @param l0t_ptep 
310  * @param va 
311  * @return pte_t* 
312  */
313 static inline pte_t*
314 mkl3t(pte_t* l2t_ptep, ptr_t va, pte_attr_t prot)
315 {
316 #if _has_LnT(3)
317     if (!l2t_ptep) {
318         return NULL;
319     }
320  
321     pte_t pte = pte_at(l2t_ptep);
322     
323     if (pte_huge(pte)) {
324         return l2t_ptep;
325     }
326
327     return __alloc_level(l2t_ptep, pte, prot) 
328                 ? __LnTEP(l2t_ptep, va, 3) 
329                 : NULL;
330 #else
331     return l2t_ptep;
332 #endif
333 }
334
335 /**
336  * @brief Create the LFT pointed by L3TE
337  * 
338  * @param l0t_ptep 
339  * @param va 
340  * @return pte_t* 
341  */
342 static inline pte_t*
343 mklft(pte_t* l3t_ptep, ptr_t va, pte_attr_t prot)
344 {
345     if (!l3t_ptep) {
346         return NULL;
347     }
348
349     pte_t pte = pte_at(l3t_ptep);
350     
351     if (pte_huge(pte)) {
352         return l3t_ptep;
353     }
354
355     return __alloc_level(l3t_ptep, pte, prot) 
356                 ? __LnTEP(l3t_ptep, va, F) 
357                 : NULL;
358 }
359
360 static inline pte_t*
361 getl1tep(pte_t* l0t_ptep, ptr_t va) {
362 #if _has_LnT(1)
363     return __LnTEP(l0t_ptep, va, 1); 
364 #else
365     return l0t_ptep;
366 #endif
367 }
368
369 static inline pte_t*
370 getl2tep(pte_t* l1t_ptep, ptr_t va) {
371 #if _has_LnT(2)
372     return __LnTEP(l1t_ptep, va, 2);
373 #else
374     return l1t_ptep;
375 #endif
376 }
377
378 static inline pte_t*
379 getl3tep(pte_t* l2t_ptep, ptr_t va) {
380 #if _has_LnT(3)
381     return __LnTEP(l2t_ptep, va, 3); 
382 #else
383     return l2t_ptep;
384 #endif
385 }
386
387 static inline pte_t*
388 getlftep(pte_t* l3t_ptep, ptr_t va) {
389     return __LnTEP(l3t_ptep, va, F);
390 }
391
392 static inline unsigned int
393 l0te_index(pte_t* ptep) {
394     return __LnTI_OF(ptep, 1);
395 }
396
397 static inline unsigned int
398 l1te_index(pte_t* ptep) {
399     return __LnTI_OF(ptep, 2);
400 }
401
402 static inline unsigned int
403 l2te_index(pte_t* ptep) {
404     return __LnTI_OF(ptep, 3);
405 }
406
407 static inline unsigned int
408 l3te_index(pte_t* ptep) {
409     return __LnTI_OF(ptep, F);
410 }
411
412 static inline pfn_t
413 pfn(ptr_t addr) {
414     return __index(addr) / PAGE_SIZE;
415 }
416
417 static inline size_t
418 leaf_count(size_t size) {
419     return (size + PAGE_MASK) / PAGE_SIZE;
420 }
421
422 static inline size_t
423 page_count(size_t size, size_t page_size) {
424     return (size + (page_size - 1)) / page_size;
425 }
426
427 static inline unsigned int
428 va_offset(ptr_t addr) {
429     return addr & PAGE_MASK;
430 }
431
432 static inline ptr_t
433 page_addr(ptr_t pfn) {
434     return __vaddr(pfn * PAGE_SIZE);
435 }
436
437 static inline ptr_t
438 page_aligned(ptr_t va) {
439     return va & ~PAGE_MASK;
440 }
441
442 static inline ptr_t
443 page_upaligned(ptr_t va) {
444     return (va + PAGE_MASK) & ~PAGE_MASK;
445 }
446
447 static inline ptr_t
448 napot_aligned(ptr_t va, size_t napot_sz) {
449     return va & ~(napot_sz - 1);
450 }
451
452 static inline ptr_t
453 napot_upaligned(ptr_t va, size_t napot_sz) {
454     return (va + napot_sz - 1) & ~(napot_sz - 1);
455 }
456
457 static inline pte_t*
458 mkptep_va(ptr_t vm_mnt, ptr_t vaddr)
459 {
460     return (pte_t*)(vm_mnt & ~L0T_MASK) + pfn(vaddr);
461 }
462
463 static inline pte_t*
464 mkptep_pn(ptr_t vm_mnt, ptr_t pn)
465 {
466     return (pte_t*)(vm_mnt & ~L0T_MASK) + (pn & L0T_MASK);
467 }
468
469 static inline pfn_t
470 pfn_at(ptr_t va, size_t lvl_size) {
471     return __index(va) / lvl_size;
472 }
473
474
475 /**
476  * @brief Shift the ptep such that it points to an
477  *        immediate lower level of page table
478  * 
479  * @param ptep 
480  * @return pte_t* 
481  */
482 static inline pte_t*
483 ptep_step_into(pte_t* ptep)
484 {
485     return __LnTEP_SHIFT_NEXT(ptep);
486 }
487
488 /**
489  * @brief Shift the ptep such that it points to an
490  *        immediate upper level of page table
491  * 
492  * @param ptep 
493  * @return pte_t* 
494  */
495 static inline pte_t*
496 ptep_step_out(pte_t* ptep)
497 {
498     ptr_t unshifted = (ptr_t)mkptep_pn(VMS_SELF, ptep_pfn(ptep));
499     return mkptep_va(_VM_OF(ptep), unshifted);
500 }
501
502 /**
503  * @brief Make a L0TEP from given mnt and va
504  * 
505  * @param ptep 
506  * @return pte_t* 
507  */
508 static inline pte_t*
509 mkl0tep_va(ptr_t mnt, ptr_t va)
510 {
511     return mkl0tep(mkptep_va(mnt, va));
512 }
513
514 static inline pte_t*
515 mkl1tep_va(ptr_t mnt, ptr_t va)
516 {
517     return mkl1tep(mkptep_va(mnt, va));
518 }
519
520 static inline pte_t*
521 mkl2tep_va(ptr_t mnt, ptr_t va)
522 {
523     return mkl2tep(mkptep_va(mnt, va));
524 }
525
526 static inline pte_t*
527 mkl3tep_va(ptr_t mnt, ptr_t va)
528 {
529     return mkl3tep(mkptep_va(mnt, va));
530 }
531
532 static inline pte_t*
533 mklntep_va(int level, ptr_t mnt, ptr_t va)
534 {
535     if (level == 0)
536         return mkl0tep_va(mnt, va);
537     
538 #if LnT_ENABLED(1)
539     if (level == 1)
540         return mkl1tep_va(mnt, va);
541 #endif
542
543 #if LnT_ENABLED(2)
544     if (level == 2)
545         return mkl2tep_va(mnt, va);
546 #endif
547
548 #if LnT_ENABLED(3)
549     if (level == 3)
550         return mkl3tep_va(mnt, va);
551 #endif
552     
553     return mkptep_va(mnt, va);
554 }
555
556 static inline unsigned long
557 lnt_page_size(int level)
558 {
559     if (level == 0)
560         return L0T_SIZE;
561     if (level == 1)
562         return L1T_SIZE;
563     if (level == 2)
564         return L2T_SIZE;
565     if (level == 3)
566         return L3T_SIZE;
567     
568     return LFT_SIZE;
569 }
570
571 static inline bool
572 pt_last_level(int level)
573 {
574     return level == _PTW_LEVEL - 1;
575 }
576
577 static inline ptr_t
578 va_mntpoint(ptr_t va)
579 {
580     return __vaddr(_VM_OF(va));
581 }
582
583 static inline unsigned int
584 va_level_index(ptr_t va, size_t lvl_size)
585 {
586     return (va / lvl_size) & _PAGE_LEVEL_MASK;
587 }
588
589 static inline bool
590 lntep_implie(pte_t* ptep, ptr_t addr, size_t lvl_size)
591 {
592     return ptep_va(ptep, lvl_size) == __vaddr(addr);
593 }
594
595 static inline bool
596 is_ptep(ptr_t addr)
597 {
598     ptr_t mnt = va_mntpoint(addr);
599     return mnt == VMS_MOUNT_1 || mnt == VMS_SELF;
600 }
601
602 static inline bool
603 vmnt_packed(pte_t* ptep)
604 {
605     return is_ptep(__ptr(ptep));
606 }
607
608 static inline bool
609 active_vms(ptr_t vmnt)
610 {
611     return vmnt == VMS_SELF;
612 }
613
614 static inline bool
615 lntep_implie_vmnts(pte_t* ptep, size_t lvl_size)
616 {
617     return lntep_implie(ptep, VMS_SELF, lvl_size) ||
618            lntep_implie(ptep, VMS_MOUNT_1, lvl_size);
619 }
620
621
622 static inline int
623 ptep_count_level(pte_t* ptep)
624 {
625     int i = 0;
626     ptr_t addr = (ptr_t)ptep;
627
628     if (!is_ptep(addr << (LEVEL_SHIFT * i++)))
629         return MAX_LEVEL - i;
630
631 #if LnT_ENABLED(1)
632     if (!is_ptep(addr << (LEVEL_SHIFT * i++)))
633         return MAX_LEVEL - i;
634 #endif
635
636 #if LnT_ENABLED(2)
637     if (!is_ptep(addr << (LEVEL_SHIFT * i++)))
638         return MAX_LEVEL - i;
639 #endif
640
641 #if LnT_ENABLED(3)
642     if (!is_ptep(addr << (LEVEL_SHIFT * i++)))
643         return MAX_LEVEL - i;
644 #endif
645     
646     return 0;
647 }
648
649 #endif /* __LUNAIX_PAGETABLE_H */