physical page list mapping
[lunaix-os.git] / lunaix-os / includes / lunaix / mm / page.h
1 #ifndef __LUNAIX_PAGE_H
2 #define __LUNAIX_PAGE_H
3
4 #include <lunaix/mm/pmm.h>
5 #include <lunaix/mm/vmm.h>
6 #include <lunaix/mm/vmtlb.h>
7
8 #include <klibc/string.h>
9
10 /**
11  * @brief A leaflet represent a bunch 4k ppage
12  *        as single multi-ordered page, as such
13  *        big page can seen as an unfolded version
14  *        of these small 4k ppages hence the name.
15  *        It is introduced to solve the issue that
16  *        is discovered during refactoring - It is 
17  *        jolly unclear whether the ppage is a head, 
18  *        tail, or even worse, the middle one, when
19  *        passing around between functions.
20  *        This concept is surprisingly similar to
21  *        Linux's struct folio (I swear to the 
22  *        Almighty Princess of the Sun, Celestia, 
23  *        that I don't quite understand what folio 
24  *        is until I've wrote the conceptually same 
25  *        thing)
26  * 
27  */
28 struct leaflet
29 {
30     struct ppage lead_page;
31 };
32
33 static inline struct leaflet*
34 get_leaflet(struct ppage* page)
35 {
36     return (struct leaflet*)leading_page(page);
37 }
38
39 static inline struct ppage*
40 get_ppage(struct leaflet* leaflet)
41 {
42     return (struct ppage*)leaflet;
43 }
44
45 static inline struct leaflet*
46 alloc_leaflet(int order)
47 {
48     return (struct leaflet*)pmm_alloc_napot_type(POOL_UNIFIED, order, 0);
49 }
50
51 static inline struct leaflet*
52 alloc_leaflet_pinned(int order)
53 {
54     return (struct leaflet*)pmm_alloc_napot_type(POOL_UNIFIED, order, PP_FGLOCKED);
55 }
56
57 static inline void
58 leaflet_borrow(struct leaflet* leaflet)
59 {
60     struct ppage* const page = get_ppage(leaflet);
61     assert(page->refs);
62     if (reserved_page(page)) {
63         return;
64     }
65     
66     page->refs++;
67 }
68
69 static inline void
70 leaflet_return(struct leaflet* leaflet)
71 {
72     struct ppage* const page = get_ppage(leaflet);
73     assert(page->refs);
74     pmm_free_one(page, 0);
75 }
76
77 static inline unsigned int
78 leaflet_refcount(struct leaflet* leaflet)
79 {
80     return get_ppage(leaflet)->refs;
81 }
82
83 static inline int
84 leaflet_order(struct leaflet* leaflet)
85 {
86     return ppage_order(get_ppage(leaflet));
87 }
88
89 static inline int
90 leaflet_size(struct leaflet* leaflet)
91 {
92     return PAGE_SIZE << leaflet_order(leaflet);
93 }
94
95 static inline int
96 leaflet_nfold(struct leaflet* leaflet)
97 {
98     return 1 << leaflet_order(leaflet);
99 }
100
101 static inline struct leaflet*
102 ppfn_leaflet(pfn_t ppfn)
103 {
104     return get_leaflet(ppage(ppfn));
105 }
106
107 static inline struct leaflet*
108 pte_leaflet(pte_t pte)
109 {
110     struct ppage* ppfn = ppage(pfn(pte_paddr(pte)));
111     return get_leaflet(ppfn);
112 }
113
114 static inline struct leaflet*
115 pte_leaflet_aligned(pte_t pte)
116 {
117     struct ppage* ppfn = ppage(pfn(pte_paddr(pte)));
118     struct leaflet* _l = get_leaflet(ppfn);
119
120     assert((ptr_t)_l == (ptr_t)ppfn);
121     return _l;
122 }
123
124 static inline pfn_t
125 leaflet_ppfn(struct leaflet* leaflet)
126 {
127     return ppfn(get_ppage(leaflet));
128 }
129
130 static inline ptr_t
131 leaflet_addr(struct leaflet* leaflet)
132 {
133     return page_addr(ppfn(get_ppage(leaflet)));
134 }
135
136 static inline void
137 unpin_leaflet(struct leaflet* leaflet)
138 {
139     change_page_type(get_ppage(leaflet), 0);
140 }
141
142 static inline void
143 pin_leaflet(struct leaflet* leaflet)
144 {
145     change_page_type(get_ppage(leaflet), PP_FGLOCKED);
146 }
147
148 static inline int
149 to_napot_order(int nr_pages)
150 {
151     int order;
152     
153     order = ilog2(nr_pages);
154     return is_pot(nr_pages) ? order : order + 1;
155 }
156
157 /**
158  * @brief Map a leaflet
159  * 
160  * @param ptep 
161  * @param leaflet 
162  * @return pages folded into that leaflet
163  */
164 static inline size_t
165 ptep_map_leaflet(pte_t* ptep, pte_t pte, struct leaflet* leaflet)
166 {
167     // We do not support huge leaflet yet
168     assert(leaflet_order(leaflet) < LEVEL_SHIFT);
169
170     pte = pte_setppfn(pte, leaflet_ppfn(leaflet));
171     pte = pte_mkloaded(pte);
172
173     int n = leaflet_nfold(leaflet);
174     vmm_set_ptes_contig(ptep, pte, LFT_SIZE, n);
175
176     return n;
177 }
178
179 /**
180  * @brief Unmap a leaflet
181  * 
182  * @param ptep 
183  * @param leaflet 
184  * @return pages folded into that leaflet
185  */
186 static inline size_t
187 ptep_unmap_leaflet(pte_t* ptep, struct leaflet* leaflet)
188 {
189     // We do not support huge leaflet yet
190     assert(leaflet_order(leaflet) < LEVEL_SHIFT);
191
192     int n = leaflet_nfold(leaflet);
193     vmm_unset_ptes(ptep, n);
194
195     return n;
196 }
197
198 static inline ptr_t
199 leaflet_mount(struct leaflet* leaflet)
200 {
201     pte_t* ptep = mkptep_va(VMS_SELF, PG_MOUNT_VAR);    
202     ptep_map_leaflet(ptep, mkpte_prot(KERNEL_DATA), leaflet);
203
204     tlb_flush_kernel_ranged(PG_MOUNT_VAR, leaflet_nfold(leaflet));
205
206     return PG_MOUNT_VAR;
207 }
208
209 static inline void
210 leaflet_unmount(struct leaflet* leaflet)
211 {
212     pte_t* ptep = mkptep_va(VMS_SELF, PG_MOUNT_VAR);    
213     vmm_unset_ptes(ptep, leaflet_nfold(leaflet));
214
215     tlb_flush_kernel_ranged(PG_MOUNT_VAR, leaflet_nfold(leaflet));
216 }
217
218 static inline void
219 leaflet_fill(struct leaflet* leaflet, unsigned int val)
220 {
221     ptr_t mnt;
222     
223     mnt = leaflet_mount(leaflet);
224     memset((void*)mnt, val, leaflet_size(leaflet));
225     leaflet_unmount(leaflet);
226 }
227
228 static inline void
229 leaflet_wipe(struct leaflet* leaflet)
230 {
231     leaflet_fill(leaflet, 0);
232 }
233
234 /**
235  * @brief Duplicate the leaflet
236  *
237  * @return Duplication of given leaflet
238  *
239  */
240 struct leaflet*
241 dup_leaflet(struct leaflet* leaflet);
242
243
244 /**
245  * @brief Maps a number of contiguous ptes in kernel 
246  *        address space
247  * 
248  * @param pte the pte to be mapped
249  * @param lvl_size size of the page pointed by the given pte
250  * @param n number of ptes
251  * @return ptr_t 
252  */
253 ptr_t
254 vmap_ptes_at(pte_t pte, size_t lvl_size, int n);
255
256 /**
257  * @brief Maps a number of contiguous ptes in kernel 
258  *        address space (leaf page size)
259  * 
260  * @param pte the pte to be mapped
261  * @param n number of ptes
262  * @return ptr_t 
263  */
264 static inline ptr_t
265 vmap_leaf_ptes(pte_t pte, int n)
266 {
267     return vmap_ptes_at(pte, LFT_SIZE, n);
268 }
269
270 /**
271  * @brief Maps a contiguous range of physical address 
272  *        into kernel address space (leaf page size)
273  * 
274  * @param paddr start of the physical address range
275  * @param size size of the physical range
276  * @param prot default protection to be applied
277  * @return ptr_t 
278  */
279 static inline ptr_t
280 vmap(struct leaflet* leaflet, pte_attr_t prot)
281 {
282     pte_t _pte = mkpte(page_addr(leaflet_ppfn(leaflet)), prot);
283     return vmap_ptes_at(_pte, LFT_SIZE, leaflet_nfold(leaflet));
284 }
285
286 void
287 vunmap(ptr_t ptr, struct leaflet* leaflet);
288
289 static inline ptr_t
290 vmap_range(pfn_t start, size_t npages, pte_attr_t prot)
291 {
292     pte_t _pte = mkpte(page_addr(start), prot);
293     return vmap_ptes_at(_pte, LFT_SIZE, npages);
294 }
295
296 static inline void
297 vunmap_range(pfn_t start, size_t npages)
298 {
299     pte_t* ptep = mkptep_va(VMS_SELF, start);
300     vmm_set_ptes_contig(ptep, null_pte, LFT_SIZE, npages);
301 }
302
303
304 /**
305  * @brief Allocate a page in kernel space.
306  * 
307  * @param ptep 
308  * @param pte 
309  * @param order 
310  * @return pte_t 
311  */
312 pte_t 
313 alloc_kpage_at(pte_t* ptep, pte_t pte, int order);
314
315 static inline void*
316 vmalloc_page(int order)
317 {
318     struct leaflet* leaf = alloc_leaflet(0);
319     if (!leaf) {
320         return NULL;
321     }
322
323     return (void*)vmap(leaf, KERNEL_DATA);
324 }
325
326 static inline void
327 vmfree(void* ptr)
328 {
329     struct leaflet* leaf = ppfn_leaflet(pfn((ptr_t)ptr));
330     leaflet_return(leaf);
331 }
332
333 #endif /* __LUNAIX_PAGE_H */