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];
23 pmm_mark_page_free(uintptr_t ppn)
26 pm_bitmap[group] = pm_bitmap[group] & ~msk;
30 pmm_mark_page_occupied(uintptr_t ppn)
33 pm_bitmap[group] = pm_bitmap[group] | msk;
37 pmm_mark_chunk_free(uintptr_t start_ppn, size_t page_count)
39 MARK_CHUNK_AUX_VAR(start_ppn, page_count)
41 // nasty bit level hacks but it reduce # of iterations.
43 pm_bitmap[group] &= ~(((1U << leading_shifts) - 1) << (8 - offset - leading_shifts));
47 // prevent unsigned overflow
48 for (uint32_t i = 0; group_count !=0 && i < group_count - 1; i++, group++) {
53 ~(((1U << (page_count > 8 ? remainder : 0)) - 1) << (8 - remainder));
57 pmm_mark_chunk_occupied(uint32_t start_ppn, size_t page_count)
59 MARK_CHUNK_AUX_VAR(start_ppn, page_count)
61 pm_bitmap[group] |= (((1U << leading_shifts) - 1) << (8 - offset - leading_shifts));
65 // prevent unsigned overflow
66 for (uint32_t i = 0; group_count !=0 && i < group_count - 1; i++, group++) {
67 pm_bitmap[group] = 0xFFU;
71 (((1U << (page_count > 8 ? remainder : 0)) - 1) << (8 - remainder));
74 // 我们跳过位于0x0的页。我们不希望空指针是指向一个有效的内存空间。
75 #define LOOKUP_START 1
80 pmm_init(uintptr_t mem_upper_lim)
82 max_pg = (PG_ALIGN(mem_upper_lim) >> 12);
84 pg_lookup_ptr = LOOKUP_START;
86 // mark all as occupied
87 for (size_t i = 0; i < PM_BMP_MAX_SIZE; i++) {
95 // Next fit approach. Maximize the throughput!
96 uintptr_t good_page_found = NULL;
97 size_t old_pg_ptr = pg_lookup_ptr;
98 size_t upper_lim = max_pg;
100 while (!good_page_found && pg_lookup_ptr < upper_lim) {
101 chunk = pm_bitmap[pg_lookup_ptr >> 3];
103 // skip the fully occupied chunk, reduce # of iterations
104 if (chunk != 0xFFU) {
105 for (size_t i = pg_lookup_ptr % 8; i < 8; i++, pg_lookup_ptr++) {
106 if (!(chunk & (0x80U >> i))) {
107 pmm_mark_page_occupied(pg_lookup_ptr);
108 good_page_found = pg_lookup_ptr << 12;
115 // We've searched the interval [old_pg_ptr, max_pg) but failed
116 // may be chances in [1, old_pg_ptr) ?
118 if (pg_lookup_ptr >= upper_lim && old_pg_ptr != LOOKUP_START) {
119 upper_lim = old_pg_ptr;
120 pg_lookup_ptr = LOOKUP_START;
121 old_pg_ptr = LOOKUP_START;
125 return (void*)good_page_found;
129 pmm_free_page(void* page)
131 // TODO: Add kernel reserved memory page check
132 uint32_t pg = (uintptr_t)page >> 12;
133 if (pg && pg < max_pg)
135 pmm_mark_page_free(pg);