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 <sys/mm/pagetable.h>
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 )
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 )
116 #define __LnTI_OF(ptep, n)\
117 (_VM_PFN_OF(ptep) * LFT_SIZE / L##n##T_SIZE)
119 #define __LnTEP(ptep, va, n)\
120 ( (pte_t*)_L##n##TEP_AT(_VM_OF(ptep)) + (((va) & VMS_MASK) / L##n##T_SIZE) )
122 #define __LnTEP_OF(ptep, n)\
123 ( (pte_t*)_L##n##TEP_AT(_VM_OF(ptep)) + __LnTI_OF(ptep, n))
125 #define __LnTEP_SHIFT_NEXT(ptep)\
126 ( (pte_t*)(_VM_OF(ptep) | ((_VM_PFN_OF(ptep) * LFT_SIZE) & L0T_MASK)) )
128 #define _has_LnT(n) (L##n##T_SIZE != LFT_SIZE)
129 #define LnT_ENABLED(n) _has_LnT(n)
131 #define ptep_with_level(ptep, lvl_size) \
133 ptr_t __p = _LnTEP_AT(_VM_OF(ptep), lvl_size); \
134 ((ptr_t)(ptep) & __p) == __p; \
138 vmm_alloc_page(pte_t* ptep, pte_t pte);
141 * @brief Try page walk to the pte pointed by ptep and
142 * allocate any missing level-table en-route
148 ptep_alloc_hierarchy(pte_t* ptep, ptr_t va, pte_attr_t prot);
151 __alloc_level(pte_t* ptep, pte_t pte, pte_attr_t prot)
153 if (!pte_isnull(pte)) {
157 pte = pte_setprot(pte, prot);
158 return !pte_isnull(vmm_alloc_page(ptep, pte));
162 * @brief Get the page frame number encoded in ptep
168 ptep_pfn(pte_t* ptep)
170 return _VM_PFN_OF(ptep);
174 * @brief Get the virtual frame number encoded in ptep
179 static inline unsigned int
180 ptep_vfn(pte_t* ptep)
182 return ((ptr_t)ptep & PAGE_MASK) / sizeof(pte_t);
186 ptep_va(pte_t* ptep, size_t lvl_size)
188 return ((ptr_t)ptep) / sizeof(pte_t) * lvl_size;
192 ptep_vm_mnt(pte_t* ptep)
198 * @brief Make a L0TEP from given ptep
206 return __LnTEP_OF(ptep, 0);
210 * @brief Make a L1TEP from given ptep
218 return __LnTEP_OF(ptep, 1);
222 * @brief Make a L2TEP from given ptep
230 return __LnTEP_OF(ptep, 2);
234 * @brief Make a L3TEP from given ptep
242 return __LnTEP_OF(ptep, 3);
246 * @brief Create the L1T pointed by L0TE
253 mkl1t(pte_t* l0t_ptep, ptr_t va, pte_attr_t prot)
260 pte_t pte = pte_at(l0t_ptep);
266 return __alloc_level(l0t_ptep, pte, prot)
267 ? __LnTEP(l0t_ptep, va, 1)
275 * @brief Create the L2T pointed by L1TE
282 mkl2t(pte_t* l1t_ptep, ptr_t va, pte_attr_t prot)
289 pte_t pte = pte_at(l1t_ptep);
295 return __alloc_level(l1t_ptep, pte, prot)
296 ? __LnTEP(l1t_ptep, va, 2)
304 * @brief Create the L3T pointed by L2TE
311 mkl3t(pte_t* l2t_ptep, ptr_t va, pte_attr_t prot)
318 pte_t pte = pte_at(l2t_ptep);
324 return __alloc_level(l2t_ptep, pte, prot)
325 ? __LnTEP(l2t_ptep, va, 3)
333 * @brief Create the LFT pointed by L3TE
340 mklft(pte_t* l3t_ptep, ptr_t va, pte_attr_t prot)
346 pte_t pte = pte_at(l3t_ptep);
352 return __alloc_level(l3t_ptep, pte, prot)
353 ? __LnTEP(l3t_ptep, va, F)
358 getl1tep(pte_t* l0t_ptep, ptr_t va) {
360 return __LnTEP(l0t_ptep, va, 1);
367 getl2tep(pte_t* l1t_ptep, ptr_t va) {
369 return __LnTEP(l1t_ptep, va, 2);
376 getl3tep(pte_t* l2t_ptep, ptr_t va) {
378 return __LnTEP(l2t_ptep, va, 3);
385 getlftep(pte_t* l3t_ptep, ptr_t va) {
386 return __LnTEP(l3t_ptep, va, F);
389 static inline unsigned int
390 l0te_index(pte_t* ptep) {
391 return __LnTI_OF(ptep, 1);
394 static inline unsigned int
395 l1te_index(pte_t* ptep) {
396 return __LnTI_OF(ptep, 2);
399 static inline unsigned int
400 l2te_index(pte_t* ptep) {
401 return __LnTI_OF(ptep, 3);
404 static inline unsigned int
405 l3te_index(pte_t* ptep) {
406 return __LnTI_OF(ptep, F);
411 return (addr / PAGE_SIZE) & VMS_MASK;
415 leaf_count(size_t size) {
416 return (size + PAGE_MASK) / PAGE_SIZE;
420 page_count(size_t size, size_t page_size) {
421 return (size + (page_size - 1)) / page_size;
424 static inline unsigned int
425 va_offset(ptr_t addr) {
426 return addr & PAGE_MASK;
430 page_addr(ptr_t pfn) {
431 return pfn * PAGE_SIZE;
436 return va & ~PAGE_MASK;
440 va_alignup(ptr_t va) {
441 return (va + PAGE_MASK) & ~PAGE_MASK;
445 mkptep_va(ptr_t vm_mnt, ptr_t vaddr)
447 return (pte_t*)(vm_mnt & ~L0T_MASK) + pfn(vaddr);
451 mkptep_pn(ptr_t vm_mnt, ptr_t pn)
453 return (pte_t*)(vm_mnt & ~L0T_MASK) + (pn & L0T_MASK);
457 pfn_at(ptr_t va, size_t lvl_size) {
458 return va / lvl_size;
463 * @brief Shift the ptep such that it points to an
464 * immediate lower level of page table
470 ptep_step_into(pte_t* ptep)
472 return __LnTEP_SHIFT_NEXT(ptep);
476 * @brief Shift the ptep such that it points to an
477 * immediate upper level of page table
483 ptep_step_out(pte_t* ptep)
485 ptr_t unshifted = (ptr_t)mkptep_pn(VMS_SELF, ptep_pfn(ptep));
486 return mkptep_va(_VM_OF(ptep), unshifted);
490 * @brief Make a L0TEP from given mnt and va
496 mkl0tep_va(ptr_t mnt, ptr_t va)
498 return mkl0tep(mkptep_va(mnt, va));
502 pt_last_level(int level)
504 return level == _PTW_LEVEL - 1;
507 #endif /* __LUNAIX_PAGETABLE_H */