1#include <math/bit.h>
2#include <mem/anon_vma.h>
3#include <mem/fixed_size_alloc.h>
4#include <mem/folio.h>
5#include <mem/pmm.h>
6#include <smp/perdomain.h>
7#include <string.h>
8#include <types/refcount.h>
9
10FIXED_SIZE_RANGE_PERDOMAIN_DEFINE(folio, .obj_size = sizeof(struct folio),
11 .obj_align = PAGE_PAYLOAD_ALIGNMENT);
12
13struct folio *folio_alloc_folio_struct(void) {
14 return FSR_PERDOMAIN_ALLOC(folio);
15}
16
17void folio_free_folio_struct(struct folio *f) {
18 folio_unbind_pages(f);
19 return FSR_PERDOMAIN_FREE(folio, f);
20}
21
22/* TODO: implement later
23void folio_free(struct folio *folio) {
24 if (folio_is_anon(folio)) {
25 anon_vma_putref(folio_get_anon_vma(folio));
26 } else if (folio_is_file_vma_range(folio)) {
27 // TODO: When we get file VMA
28 }
29
30 size_t pages = pow2(folio->order);
31
32 pmm_free_pages(page_get_paddr(folio->base_page), pages);
33 folio_free_folio_struct(folio);
34} */
35
36struct folio *folio_alloc_full(uint8_t order, struct alloc_params params) {
37 size_t pages = pow2(n: order);
38 struct folio *folio = folio_alloc_folio_struct();
39 if (!folio)
40 return NULL;
41
42 paddr_t phys = pmm_alloc_pages(pages, params.flags);
43 if (!phys) {
44 folio_free_folio_struct(f: folio);
45 return NULL;
46 }
47
48 struct page *base_page = page_for_paddr(paddr: phys);
49 folio->base_page = base_page;
50 folio->order = order;
51 atomic_init(&folio->mapcount, 0);
52 refcount_init(rc: &folio->refcount, val: 1);
53 folio->mapping = NULL;
54 atomic_init(&folio->flags, 0);
55 folio_bind_pages(f: folio);
56
57 return folio;
58}
59
60void folio_zero(struct folio *f) {
61 vaddr_t vaddr;
62 folio_for_each_page_vaddr(vaddr, f) {
63 memset((void *) vaddr, 0, PAGE_SIZE);
64 }
65}
66
67void folio_copy(const struct folio *src, struct folio *dst) {
68 enforce(src->order == dst->order);
69 size_t nr_pages = folio_nr_pages(f: src);
70 for (size_t i = 0; i < nr_pages; i++) {
71 vaddr_t src_vaddr = folio_get_vaddr_for(f: src, n: i);
72 vaddr_t dst_vaddr = folio_get_vaddr_for(f: dst, n: i);
73 memcpy((void *) dst_vaddr, (void *) src_vaddr, PAGE_SIZE);
74 }
75}
76
77void folio_bind_pages(struct folio *f) {
78 struct page *page;
79 folio_for_each_page_struct(page, f) {
80 page_set_folio(p: page, f);
81 }
82}
83
84void folio_unbind_pages(struct folio *f) {
85 struct page *page;
86 folio_for_each_page_struct(page, f) {
87 page_clear_folio(p: page);
88 }
89}
90
91bool page_is_folio_head(struct page *p) {
92 return page_get_folio(p)->base_page == p;
93}
94
95uint32_t page_get_folio_index(struct page *p) {
96 struct folio *f = page_get_folio(p);
97 return page_get_pfn(bp: p) - page_get_pfn(bp: f->base_page);
98}
99