1 #ifndef __LUNAIX_PAGETABLE_H
2 #define __LUNAIX_PAGETABLE_H
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:
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
15 Therefore, "LnTE" can be used to refer "Entry in a Level-n Table".
16 Consequently, we can further define
18 + LnTEP - pointer to an entry within LnT
19 + LnTP - pointer to (the first entry of) LnT
21 To better identify all derived value from virtual and physical
24 + Virtual Address Space (VAS):
25 A set of all virtual addresses that can be interpreted
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.
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.
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
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
51 In the context of x86 archiecture (regardless x86_32 or x86_64),
52 these naming have the following realisations:
54 + L0T: PD (32-Bit 2-Level paging)
58 + L1T: ( N/A ) (32-Bit 2-Level paging)
62 + L2T: ( N/A ) (32-Bit 2-Level paging)
66 + L3T: ( N/A ) (32-Bit 2-Level paging)
67 ( N/A ) (4-Level Paging)
70 + LFT: Page Table (All)
73 [0, 2^32) (32-Bit 2-Level paging)
74 [0, 2^48) (4-Level Paging)
75 [0, 2^57) (5-Level Paging)
78 [0, 2^22) (32-Bit 2-Level paging)
79 [0, 2^36) (4-Level Paging)
80 [0, 2^45) (5-Level Paging)
84 [0, 2^52) (x86_64, all paging modes)
86 + VFN: [0, 1024) (32-Bit 2-Level paging)
87 [0, 512) (4-Level Paging)
88 [0, 512) (5-Level Paging)
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))
99 typedef struct __pte pte_t;
102 #include <asm/mempart.h>
103 #include <asm/pagetable.h>
106 #define VMS_SELF VMS_SELF_MOUNT
107 #define VMS_SELF_L0TI (__index(VMS_SELF_MOUNT) / L0T_SIZE)
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)) )
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)) )
122 #define _VM_OF(ptep) ( (ptr_t)(ptep) & ~L0T_MASK )
123 #define _VM_PFN_OF(ptep) ( ((ptr_t)(ptep) & L0T_MASK) / sizeof(pte_t) )
125 #define __LnTI_OF(ptep, n)\
126 ( __index(_VM_PFN_OF(ptep) * LFT_SIZE / L##n##T_SIZE) )
128 #define __LnTEP(ptep, va, n)\
129 ( (pte_t*)_L##n##TEP_AT(_VM_OF(ptep)) + (__index(va) / L##n##T_SIZE) )
131 #define __LnTEP_OF(ptep, n)\
132 ( (pte_t*)_L##n##TEP_AT(_VM_OF(ptep)) + __LnTI_OF(ptep, n))
134 #define __LnTEP_SHIFT_NEXT(ptep)\
135 ( (pte_t*)(_VM_OF(ptep) | ((_VM_PFN_OF(ptep) * LFT_SIZE) & L0T_MASK)) )
137 #define _has_LnT(n) (L##n##T_SIZE != LFT_SIZE)
138 #define LnT_ENABLED(n) _has_LnT(n)
141 alloc_kpage_at(pte_t* ptep, pte_t pte, int order);
144 * @brief Try page walk to the pte pointed by ptep and
145 * allocate any missing level-table en-route
151 ptep_alloc_hierarchy(pte_t* ptep, ptr_t va, pte_attr_t prot);
154 __alloc_level(pte_t* ptep, pte_t pte, pte_attr_t prot)
156 if (!pte_isnull(pte)) {
160 pte = pte_setprot(pte, prot);
161 return !pte_isnull(alloc_kpage_at(ptep, pte, 0));
165 * @brief Get the page frame number encoded in ptep
171 ptep_pfn(pte_t* ptep)
173 return _VM_PFN_OF(ptep);
177 * @brief Get the virtual frame number encoded in ptep
182 static inline unsigned int
183 ptep_vfn(pte_t* ptep)
185 return ((ptr_t)ptep & PAGE_MASK) / sizeof(pte_t);
189 ptep_va(pte_t* ptep, size_t lvl_size)
191 return __vaddr(ptep_pfn(ptep) * lvl_size);
195 ptep_vm_mnt(pte_t* ptep)
197 return __vaddr(_VM_OF(ptep));
201 * @brief Make a L0TEP from given ptep
209 return __LnTEP_OF(ptep, 0);
213 * @brief Make a L1TEP from given ptep
221 return __LnTEP_OF(ptep, 1);
225 * @brief Make a L2TEP from given ptep
233 return __LnTEP_OF(ptep, 2);
237 * @brief Make a L3TEP from given ptep
245 return __LnTEP_OF(ptep, 3);
249 * @brief Create the L1T pointed by L0TE
256 mkl1t(pte_t* l0t_ptep, ptr_t va, pte_attr_t prot)
263 pte_t pte = pte_at(l0t_ptep);
269 return __alloc_level(l0t_ptep, pte, prot)
270 ? __LnTEP(l0t_ptep, va, 1)
278 * @brief Create the L2T pointed by L1TE
285 mkl2t(pte_t* l1t_ptep, ptr_t va, pte_attr_t prot)
292 pte_t pte = pte_at(l1t_ptep);
298 return __alloc_level(l1t_ptep, pte, prot)
299 ? __LnTEP(l1t_ptep, va, 2)
307 * @brief Create the L3T pointed by L2TE
314 mkl3t(pte_t* l2t_ptep, ptr_t va, pte_attr_t prot)
321 pte_t pte = pte_at(l2t_ptep);
327 return __alloc_level(l2t_ptep, pte, prot)
328 ? __LnTEP(l2t_ptep, va, 3)
336 * @brief Create the LFT pointed by L3TE
343 mklft(pte_t* l3t_ptep, ptr_t va, pte_attr_t prot)
349 pte_t pte = pte_at(l3t_ptep);
355 return __alloc_level(l3t_ptep, pte, prot)
356 ? __LnTEP(l3t_ptep, va, F)
361 getl1tep(pte_t* l0t_ptep, ptr_t va) {
363 return __LnTEP(l0t_ptep, va, 1);
370 getl2tep(pte_t* l1t_ptep, ptr_t va) {
372 return __LnTEP(l1t_ptep, va, 2);
379 getl3tep(pte_t* l2t_ptep, ptr_t va) {
381 return __LnTEP(l2t_ptep, va, 3);
388 getlftep(pte_t* l3t_ptep, ptr_t va) {
389 return __LnTEP(l3t_ptep, va, F);
392 static inline unsigned int
393 l0te_index(pte_t* ptep) {
394 return __LnTI_OF(ptep, 1);
397 static inline unsigned int
398 l1te_index(pte_t* ptep) {
399 return __LnTI_OF(ptep, 2);
402 static inline unsigned int
403 l2te_index(pte_t* ptep) {
404 return __LnTI_OF(ptep, 3);
407 static inline unsigned int
408 l3te_index(pte_t* ptep) {
409 return __LnTI_OF(ptep, F);
414 return __index(addr) / PAGE_SIZE;
418 leaf_count(size_t size) {
419 return (size + PAGE_MASK) / PAGE_SIZE;
423 page_count(size_t size, size_t page_size) {
424 return (size + (page_size - 1)) / page_size;
427 static inline unsigned int
428 va_offset(ptr_t addr) {
429 return addr & PAGE_MASK;
433 page_addr(ptr_t pfn) {
434 return __vaddr(pfn * PAGE_SIZE);
438 page_aligned(ptr_t va) {
439 return va & ~PAGE_MASK;
443 page_upaligned(ptr_t va) {
444 return (va + PAGE_MASK) & ~PAGE_MASK;
448 napot_aligned(ptr_t va, size_t napot_sz) {
449 return va & ~(napot_sz - 1);
453 napot_upaligned(ptr_t va, size_t napot_sz) {
454 return (va + napot_sz - 1) & ~(napot_sz - 1);
458 mkptep_va(ptr_t vm_mnt, ptr_t vaddr)
460 return (pte_t*)(vm_mnt & ~L0T_MASK) + pfn(vaddr);
464 mkptep_pn(ptr_t vm_mnt, ptr_t pn)
466 return (pte_t*)(vm_mnt & ~L0T_MASK) + (pn & L0T_MASK);
470 pfn_at(ptr_t va, size_t lvl_size) {
471 return __index(va) / lvl_size;
476 * @brief Shift the ptep such that it points to an
477 * immediate lower level of page table
483 ptep_step_into(pte_t* ptep)
485 return __LnTEP_SHIFT_NEXT(ptep);
489 * @brief Shift the ptep such that it points to an
490 * immediate upper level of page table
496 ptep_step_out(pte_t* ptep)
498 ptr_t unshifted = (ptr_t)mkptep_pn(VMS_SELF, ptep_pfn(ptep));
499 return mkptep_va(_VM_OF(ptep), unshifted);
503 * @brief Make a L0TEP from given mnt and va
509 mkl0tep_va(ptr_t mnt, ptr_t va)
511 return mkl0tep(mkptep_va(mnt, va));
515 mkl1tep_va(ptr_t mnt, ptr_t va)
517 return mkl1tep(mkptep_va(mnt, va));
521 mkl2tep_va(ptr_t mnt, ptr_t va)
523 return mkl2tep(mkptep_va(mnt, va));
527 mkl3tep_va(ptr_t mnt, ptr_t va)
529 return mkl3tep(mkptep_va(mnt, va));
533 mklntep_va(int level, ptr_t mnt, ptr_t va)
536 return mkl0tep_va(mnt, va);
540 return mkl1tep_va(mnt, va);
545 return mkl2tep_va(mnt, va);
550 return mkl3tep_va(mnt, va);
553 return mkptep_va(mnt, va);
556 static inline unsigned long
557 lnt_page_size(int level)
572 pt_last_level(int level)
574 return level == _PTW_LEVEL - 1;
578 va_mntpoint(ptr_t va)
580 return __vaddr(_VM_OF(va));
583 static inline unsigned int
584 va_level_index(ptr_t va, size_t lvl_size)
586 return (va / lvl_size) & _PAGE_LEVEL_MASK;
590 lntep_implie(pte_t* ptep, ptr_t addr, size_t lvl_size)
592 return ptep_va(ptep, lvl_size) == __vaddr(addr);
598 ptr_t mnt = va_mntpoint(addr);
599 return mnt == VMS_MOUNT_1 || mnt == VMS_SELF;
603 vmnt_packed(pte_t* ptep)
605 return is_ptep(__ptr(ptep));
609 active_vms(ptr_t vmnt)
611 return vmnt == VMS_SELF;
615 lntep_implie_vmnts(pte_t* ptep, size_t lvl_size)
617 return lntep_implie(ptep, VMS_SELF, lvl_size) ||
618 lntep_implie(ptep, VMS_MOUNT_1, lvl_size);
623 ptep_count_level(pte_t* ptep)
626 ptr_t addr = (ptr_t)ptep;
628 if (!is_ptep(addr << (LEVEL_SHIFT * i++)))
629 return MAX_LEVEL - i;
632 if (!is_ptep(addr << (LEVEL_SHIFT * i++)))
633 return MAX_LEVEL - i;
637 if (!is_ptep(addr << (LEVEL_SHIFT * i++)))
638 return MAX_LEVEL - i;
642 if (!is_ptep(addr << (LEVEL_SHIFT * i++)))
643 return MAX_LEVEL - i;
649 static inline pte_t must_inline
650 pte_advance(pte_t pte, unsigned long lvl_size)
652 return pte_setpaddr(pte, pte_paddr(pte) + lvl_size);
655 #endif /* __LUNAIX_PAGETABLE_H */