1#include <math/pow.h>
2#include <mem/fixed_size_alloc.h>
3#include <mem/folio.h>
4#include <mem/pmm.h>
5#include <smp/perdomain.h>
6#include <string.h>
7#include <types/refcount.h>
8
9FIXED_SIZE_RANGE_PERDOMAIN_DECLARE(folio, .obj_size = sizeof(struct folio),
10 .obj_align = PAGE_PAYLOAD_ALIGNMENT);
11
12struct folio *folio_alloc_folio_struct() {
13 return FSR_PERDOMAIN_ALLOC(folio);
14}
15
16void folio_free_folio_struct(struct folio *f) {
17 folio_unbind_pages(f);
18 return FSR_PERDOMAIN_FREE(folio, f);
19}
20
21struct folio *folio_alloc_internal(uint8_t order, enum alloc_flags f,
22 enum alloc_behavior b) {
23 size_t pages = pow2(n: order);
24 struct folio *folio = folio_alloc_folio_struct();
25 if (!folio)
26 return NULL;
27
28 paddr_t phys = pmm_alloc_pages(pages, f);
29 if (!phys) {
30 folio_free_folio_struct(f: folio);
31 return NULL;
32 }
33
34 struct page *base_page = page_for_paddr(paddr: phys);
35 folio->base_page = base_page;
36 folio->order = order;
37 folio->mapcount = 0;
38 refcount_init(rc: &folio->refcount, val: 1);
39 folio->mapping = NULL;
40 folio->flags = 0;
41 folio_bind_pages(f: folio);
42
43 return folio;
44}
45
46void folio_zero(struct folio *f) {
47 vaddr_t vaddr;
48 folio_for_each_page_vaddr(f, vaddr) {
49 memset((void *) vaddr, 0, PAGE_SIZE);
50 }
51}
52
53void folio_copy(const struct folio *src, struct folio *dst) {
54 kassert(src->order == dst->order);
55 vaddr_t src_vaddr, dst_vaddr;
56 folio_for_each_page_vaddr(src, src_vaddr) {
57 dst_vaddr = page_get_vaddr(bp: folio_get_page(f: dst, n: __i));
58 memcpy((void *) dst_vaddr, (void *) src_vaddr, PAGE_SIZE);
59 }
60}
61
62void folio_bind_pages(struct folio *f) {
63 struct page *page;
64 folio_for_each_page_struct(f, page) {
65 page_set_folio(p: page, f);
66 }
67}
68
69void folio_unbind_pages(struct folio *f) {
70 struct page *page;
71 folio_for_each_page_struct(f, page) {
72 page_clear_folio(p: page);
73 }
74}
75
76bool page_is_folio_head(struct page *p) {
77 return page_get_folio(p)->base_page == p;
78}
79
80uint32_t page_get_folio_index(struct page *p) {
81 struct folio *f = page_get_folio(p);
82 return page_get_pfn(bp: p) - page_get_pfn(bp: f->base_page);
83}
84