X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/cd09c4b222e4ddf45a42522563ae2471a829d1c8..003db17f7a36a8098827f40df8fedc087b5a26f6:/lunaix-os/kernel/mm/pmm.c?ds=sidebyside diff --git a/lunaix-os/kernel/mm/pmm.c b/lunaix-os/kernel/mm/pmm.c index c6b0a25..4503535 100644 --- a/lunaix-os/kernel/mm/pmm.c +++ b/lunaix-os/kernel/mm/pmm.c @@ -1,72 +1,43 @@ #include #include +#include -#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]; -#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; - -uint8_t pm_bitmap[PM_BMP_MAX_SIZE]; - -uintptr_t max_pg; +static uintptr_t max_pg; void pmm_mark_page_free(uintptr_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(pid_t owner, uintptr_t ppn, pp_attr_t attr) { - MARK_PG_AUX_VAR(ppn) - pm_bitmap[group] = pm_bitmap[group] | msk; + pm_table[ppn] = + (struct pp_struct){ .owner = owner, .ref_counts = 1, .attr = attr }; } void pmm_mark_chunk_free(uintptr_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(pid_t owner, + uint32_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){ .owner = owner, .ref_counts = 1, .attr = attr }; } - - pm_bitmap[group] |= - (((1U << (page_count > 8 ? remainder : 0)) - 1) << (8 - remainder)); } // 我们跳过位于0x0的页。我们不希望空指针是指向一个有效的内存空间。 @@ -77,38 +48,55 @@ size_t pg_lookup_ptr; void pmm_init(uintptr_t mem_upper_lim) { - max_pg = (PG_ALIGN(mem_upper_lim) >> 12) + 1; + max_pg = (PG_ALIGN(mem_upper_lim) >> 12); pg_lookup_ptr = LOOKUP_START; // 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){ .owner = 0, .attr = 0, .ref_counts = 1 }; } } void* -pmm_alloc_page() +pmm_alloc_cpage(pid_t owner, 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 NULL; + } + + pmm_mark_chunk_occupied(owner, p1, num_pages, attr); + + return p1 << 12; +} + +void* +pmm_alloc_page(pid_t owner, pp_attr_t attr) { // Next fit approach. Maximize the throughput! - uintptr_t good_page_found = NULL; + uintptr_t good_page_found = (uintptr_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, + .owner = owner, + .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) ? @@ -120,18 +108,61 @@ pmm_alloc_page() } } } + if (!good_page_found) { + __current->k_status = LXOUTOFMEM; + } return (void*)good_page_found; } int -pmm_free_page(void* page) +pmm_free_page(pid_t owner, void* 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; + struct pp_struct* pm = &pm_table[(intptr_t)page >> 12]; + + // Is this a MMIO mapping or double free? + if (((intptr_t)page >> 12) >= max_pg || !(pm->ref_counts)) { + return 0; + } + + // 如果是锁定页,则不作处理 + if ((pm->attr & PP_FGLOCKED)) { + return 0; } - return 0; + + // TODO: 检查权限,保证:1) 只有正在使用该页(包括被分享者)的进程可以释放; + // 2) 内核可释放所有页。 + pm->ref_counts--; + return 1; +} + +int +pmm_ref_page(pid_t owner, void* page) +{ + (void*)owner; // TODO: do smth with owner + + uint32_t ppn = (uintptr_t)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(void* pa) +{ + uint32_t ppn = (uintptr_t)pa >> 12; + + if (ppn >= PM_BMP_MAX_SIZE) { + return NULL; + } + + return &pm_table[ppn]; } \ No newline at end of file