| 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 | |
| 9 | FIXED_SIZE_RANGE_PERDOMAIN_DECLARE(folio, .obj_size = sizeof(struct folio), |
| 10 | .obj_align = PAGE_PAYLOAD_ALIGNMENT); |
| 11 | |
| 12 | struct folio *folio_alloc_folio_struct() { |
| 13 | return FSR_PERDOMAIN_ALLOC(folio); |
| 14 | } |
| 15 | |
| 16 | void folio_free_folio_struct(struct folio *f) { |
| 17 | folio_unbind_pages(f); |
| 18 | return FSR_PERDOMAIN_FREE(folio, f); |
| 19 | } |
| 20 | |
| 21 | struct 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 | |
| 46 | void 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 | |
| 53 | void 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 | |
| 62 | void 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 | |
| 69 | void 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 | |
| 76 | bool page_is_folio_head(struct page *p) { |
| 77 | return page_get_folio(p)->base_page == p; |
| 78 | } |
| 79 | |
| 80 | uint32_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 | |