1 #include <lunaix/mm/page.h>
2 #include <lunaix/mm/pmm.h>
4 #define MARK_PG_AUX_VAR(ppn) \
5 uint32_t group = ppn / 8; \
6 uint32_t msk = (0x80U >> (ppn % 8)); \
8 #define MARK_CHUNK_AUX_VAR(start_ppn, page_count) \
9 uint32_t group = start_ppn / 8; \
10 uint32_t offset = start_ppn % 8; \
11 uint32_t group_count = (page_count + offset) / 8; \
12 uint32_t remainder = (page_count + offset) % 8; \
13 uint32_t leading_shifts = \
14 (page_count + offset) < 8 ? page_count : 8 - offset;
16 uint8_t pm_bitmap[PM_BMP_MAX_SIZE];
21 pmm_mark_page_free(uintptr_t ppn)
24 pm_bitmap[group] = pm_bitmap[group] & ~msk;
28 pmm_mark_page_occupied(uintptr_t ppn)
31 pm_bitmap[group] = pm_bitmap[group] | msk;
35 pmm_mark_chunk_free(uintptr_t start_ppn, size_t page_count)
37 MARK_CHUNK_AUX_VAR(start_ppn, page_count)
39 // nasty bit level hacks but it reduce # of iterations.
41 pm_bitmap[group] &= ~(((1U << leading_shifts) - 1) << (8 - offset - leading_shifts));
45 // prevent unsigned overflow
46 for (uint32_t i = 0; group_count !=0 && i < group_count - 1; i++, group++) {
51 ~(((1U << (page_count > 8 ? remainder : 0)) - 1) << (8 - remainder));
55 pmm_mark_chunk_occupied(uint32_t start_ppn, size_t page_count)
57 MARK_CHUNK_AUX_VAR(start_ppn, page_count)
59 pm_bitmap[group] |= (((1U << leading_shifts) - 1) << (8 - offset - leading_shifts));
63 // prevent unsigned overflow
64 for (uint32_t i = 0; group_count !=0 && i < group_count - 1; i++, group++) {
65 pm_bitmap[group] = 0xFFU;
69 (((1U << (page_count > 8 ? remainder : 0)) - 1) << (8 - remainder));
72 // 我们跳过位于0x0的页。我们不希望空指针是指向一个有效的内存空间。
73 #define LOOKUP_START 1
78 pmm_init(uintptr_t mem_upper_lim)
80 max_pg = (PG_ALIGN(mem_upper_lim) >> 12) + 1;
82 pg_lookup_ptr = LOOKUP_START;
84 // mark all as occupied
85 for (size_t i = 0; i < PM_BMP_MAX_SIZE; i++) {
93 // Next fit approach. Maximize the throughput!
94 uintptr_t good_page_found = NULL;
95 size_t old_pg_ptr = pg_lookup_ptr;
96 size_t upper_lim = max_pg;
98 while (!good_page_found && pg_lookup_ptr < upper_lim) {
99 chunk = pm_bitmap[pg_lookup_ptr >> 3];
101 // skip the fully occupied chunk, reduce # of iterations
102 if (chunk != 0xFFU) {
103 for (size_t i = pg_lookup_ptr % 8; i < 8; i++, pg_lookup_ptr++) {
104 if (!(chunk & (0x80U >> i))) {
105 pmm_mark_page_occupied(pg_lookup_ptr);
106 good_page_found = pg_lookup_ptr << 12;
113 // We've searched the interval [old_pg_ptr, max_pg) but failed
114 // may be chances in [1, old_pg_ptr) ?
116 if (pg_lookup_ptr >= upper_lim && old_pg_ptr != LOOKUP_START) {
117 upper_lim = old_pg_ptr;
118 pg_lookup_ptr = LOOKUP_START;
119 old_pg_ptr = LOOKUP_START;
123 return (void*)good_page_found;
127 pmm_free_page(void* page)
129 // TODO: Add kernel reserved memory page check
130 uint32_t pg = (uintptr_t)page >> 12;
131 if (pg && pg < max_pg)
133 pmm_mark_page_free(pg);