1#include <math/pow.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_DECLARE(folio, .obj_size = sizeof(struct folio),
11 .obj_align = PAGE_PAYLOAD_ALIGNMENT);
12
13struct folio *folio_alloc_folio_struct() {
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_put(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_internal(uint8_t order, enum alloc_flags f,
37 enum alloc_behavior b) {
38 size_t pages = pow2(n: order);
39 struct folio *folio = folio_alloc_folio_struct();
40 if (!folio)
41 return NULL;
42
43 paddr_t phys = pmm_alloc_pages(pages, f);
44 if (!phys) {
45 folio_free_folio_struct(f: folio);
46 return NULL;
47 }
48
49 struct page *base_page = page_for_paddr(paddr: phys);
50 folio->base_page = base_page;
51 folio->order = order;
52 folio->mapcount = 0;
53 refcount_init(rc: &folio->refcount, val: 1);
54 folio->mapping = NULL;
55 folio->flags = 0;
56 folio_bind_pages(f: folio);
57
58 return folio;
59}
60
61void folio_zero(struct folio *f) {
62 vaddr_t vaddr;
63 folio_for_each_page_vaddr(f, vaddr) {
64 memset((void *) vaddr, 0, PAGE_SIZE);
65 }
66}
67
68void folio_copy(const struct folio *src, struct folio *dst) {
69 kassert(src->order == dst->order);
70 vaddr_t src_vaddr, dst_vaddr;
71 folio_for_each_page_vaddr(src, src_vaddr) {
72 dst_vaddr = page_get_vaddr(bp: folio_get_page(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(f, page) {
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(f, page) {
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