#include <lunaix/mm/page.h>
#include <lunaix/mm/pmm.h>
+#include <lunaix/status.h>
-#define MARK_PG_AUX_VAR(ppn) \
- uint32_t group = ppn / 8; \
- uint32_t msk = (0x80U >> (ppn % 8)); \
+// This is a very large array...
+static struct pp_struct pm_table[PM_BMP_MAX_SIZE];
+export_symbol(debug, pmm, pm_table);
-#define MARK_CHUNK_AUX_VAR(start_ppn, page_count) \
- uint32_t group = start_ppn / 8; \
- uint32_t offset = start_ppn % 8; \
- uint32_t group_count = (page_count + offset) / 8; \
- uint32_t remainder = (page_count + offset) % 8; \
- uint32_t leading_shifts = \
- (page_count + offset) < 8 ? page_count : 8 - offset;
+static ptr_t max_pg;
+export_symbol(debug, pmm, max_pg);
-uint8_t pm_bitmap[PM_BMP_MAX_SIZE];
-
-uintptr_t max_pg;
-
-// ... |xxxx xxxx |
-// ... |-->|
void
-pmm_mark_page_free(uintptr_t ppn)
+pmm_mark_page_free(ptr_t ppn)
{
- MARK_PG_AUX_VAR(ppn)
- pm_bitmap[group] = pm_bitmap[group] & ~msk;
+ pm_table[ppn].ref_counts = 0;
}
void
-pmm_mark_page_occupied(uintptr_t ppn)
+pmm_mark_page_occupied(ptr_t ppn, pp_attr_t attr)
{
- MARK_PG_AUX_VAR(ppn)
- pm_bitmap[group] = pm_bitmap[group] | msk;
+ pm_table[ppn] =
+ (struct pp_struct){ .ref_counts = 1, .attr = attr };
}
void
-pmm_mark_chunk_free(uintptr_t start_ppn, size_t page_count)
+pmm_mark_chunk_free(ptr_t start_ppn, size_t page_count)
{
- MARK_CHUNK_AUX_VAR(start_ppn, page_count)
-
- // nasty bit level hacks but it reduce # of iterations.
-
- pm_bitmap[group] &= ~(((1U << leading_shifts) - 1) << (8 - offset - leading_shifts));
-
- group++;
-
- // prevent unsigned overflow
- for (uint32_t i = 0; group_count !=0 && i < group_count - 1; i++, group++) {
- pm_bitmap[group] = 0;
+ for (size_t i = start_ppn; i < start_ppn + page_count && i < max_pg; i++) {
+ pm_table[i].ref_counts = 0;
}
-
- pm_bitmap[group] &=
- ~(((1U << (page_count > 8 ? remainder : 0)) - 1) << (8 - remainder));
}
void
-pmm_mark_chunk_occupied(uint32_t start_ppn, size_t page_count)
+pmm_mark_chunk_occupied(u32_t start_ppn,
+ size_t page_count,
+ pp_attr_t attr)
{
- MARK_CHUNK_AUX_VAR(start_ppn, page_count)
-
- pm_bitmap[group] |= (((1U << leading_shifts) - 1) << (8 - offset - leading_shifts));
-
- group++;
-
- // prevent unsigned overflow
- for (uint32_t i = 0; group_count !=0 && i < group_count - 1; i++, group++) {
- pm_bitmap[group] = 0xFFU;
+ for (size_t i = start_ppn; i < start_ppn + page_count && i < max_pg; i++) {
+ pm_table[i] =
+ (struct pp_struct){ .ref_counts = 1, .attr = attr };
}
-
- pm_bitmap[group] |=
- (((1U << (page_count > 8 ? remainder : 0)) - 1) << (8 - remainder));
}
// 我们跳过位于0x0的页。我们不希望空指针是指向一个有效的内存空间。
#define LOOKUP_START 1
-size_t pg_lookup_ptr;
+volatile size_t pg_lookup_ptr;
void
-pmm_init(uintptr_t mem_upper_lim)
+pmm_init(ptr_t mem_upper_lim)
{
max_pg = (PG_ALIGN(mem_upper_lim) >> 12);
// mark all as occupied
for (size_t i = 0; i < PM_BMP_MAX_SIZE; i++) {
- pm_bitmap[i] = 0xFFU;
+ pm_table[i] =
+ (struct pp_struct){ .attr = 0, .ref_counts = 1 };
}
}
-void*
-pmm_alloc_page()
+ptr_t
+pmm_alloc_cpage(size_t num_pages, pp_attr_t attr)
+{
+ size_t p1 = 0;
+ size_t p2 = 0;
+
+ while (p2 < max_pg && p2 - p1 < num_pages) {
+ (!(&pm_table[p2])->ref_counts) ? (p2++) : (p1 = ++p2);
+ }
+
+ if (p2 == max_pg && p2 - p1 < num_pages) {
+ return NULLPTR;
+ }
+
+ pmm_mark_chunk_occupied(p1, num_pages, attr);
+
+ return p1 << 12;
+}
+
+ptr_t
+pmm_alloc_page(pp_attr_t attr)
{
// Next fit approach. Maximize the throughput!
- uintptr_t good_page_found = NULL;
+ ptr_t good_page_found = (ptr_t)NULL;
size_t old_pg_ptr = pg_lookup_ptr;
size_t upper_lim = max_pg;
- uint8_t chunk = 0;
+ struct pp_struct* pm;
while (!good_page_found && pg_lookup_ptr < upper_lim) {
- chunk = pm_bitmap[pg_lookup_ptr >> 3];
-
- // skip the fully occupied chunk, reduce # of iterations
- if (chunk != 0xFFU) {
- for (size_t i = pg_lookup_ptr % 8; i < 8; i++, pg_lookup_ptr++) {
- if (!(chunk & (0x80U >> i))) {
- pmm_mark_page_occupied(pg_lookup_ptr);
- good_page_found = pg_lookup_ptr << 12;
- break;
- }
- }
+ pm = &pm_table[pg_lookup_ptr];
+
+ if (!pm->ref_counts) {
+ *pm = (struct pp_struct){ .attr = attr,
+ .ref_counts = 1 };
+ good_page_found = pg_lookup_ptr << 12;
+ break;
} else {
- pg_lookup_ptr += 8;
+ pg_lookup_ptr++;
// We've searched the interval [old_pg_ptr, max_pg) but failed
// may be chances in [1, old_pg_ptr) ?
}
}
}
- return (void*)good_page_found;
+ return good_page_found;
+}
+
+int
+pmm_free_page(ptr_t page)
+{
+ struct pp_struct* pm = &pm_table[page >> 12];
+
+ // Is this a MMIO mapping or double free?
+ if ((page >> 12) >= max_pg || !(pm->ref_counts)) {
+ return 0;
+ }
+
+ // 如果是锁定页,则不作处理
+ if ((pm->attr & PP_FGLOCKED)) {
+ return 0;
+ }
+
+ // TODO: 检查权限,保证:1) 只有正在使用该页(包括被分享者)的进程可以释放;
+ // 2) 内核可释放所有页。
+ pm->ref_counts--;
+ return 1;
}
int
-pmm_free_page(void* page)
+pmm_ref_page(ptr_t page)
{
- // TODO: Add kernel reserved memory page check
- uint32_t pg = (uintptr_t)page >> 12;
- if (pg && pg < max_pg)
- {
- pmm_mark_page_free(pg);
- return 1;
+ u32_t ppn = page >> 12;
+
+ if (ppn >= PM_BMP_MAX_SIZE) {
+ return 0;
+ }
+
+ struct pp_struct* pm = &pm_table[ppn];
+ if (ppn >= max_pg || !pm->ref_counts) {
+ return 0;
+ }
+
+ pm->ref_counts++;
+ return 1;
+}
+
+struct pp_struct*
+pmm_query(ptr_t pa)
+{
+ u32_t ppn = pa >> 12;
+
+ if (ppn >= PM_BMP_MAX_SIZE) {
+ return NULL;
}
- return 0;
+
+ return &pm_table[ppn];
}
\ No newline at end of file