X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/1fe5f5eb5378a47bf0f3451762743c162e40faad..cbc8fdbfe473e23e19690204418e19999a9522d1:/lunaix-os/kernel/mm/pmm.c diff --git a/lunaix-os/kernel/mm/pmm.c b/lunaix-os/kernel/mm/pmm.c index ffb51e6..bc44be7 100644 --- a/lunaix-os/kernel/mm/pmm.c +++ b/lunaix-os/kernel/mm/pmm.c @@ -1,165 +1,135 @@ -#include -#include #include +#include +#include +#include +#include -// This is a very large array... -static struct pp_struct pm_table[PM_BMP_MAX_SIZE]; +#include "pmm_internal.h" -static ptr_t max_pg; +LOG_MODULE("pmm") -void -pmm_mark_page_free(ptr_t ppn) -{ - pm_table[ppn].ref_counts = 0; -} - -void -pmm_mark_page_occupied(pid_t owner, ptr_t ppn, pp_attr_t attr) +static inline bool +__check_typemask(struct ppage* page, ppage_type_t typemask) { - pm_table[ppn] = - (struct pp_struct){ .owner = owner, .ref_counts = 1, .attr = attr }; + return !page->type || (page->type & typemask); } -void -pmm_mark_chunk_free(ptr_t start_ppn, size_t page_count) -{ - for (size_t i = start_ppn; i < start_ppn + page_count && i < max_pg; i++) { - pm_table[i].ref_counts = 0; - } -} +static struct pmem memory; +export_symbol(debug, pmm, memory); void -pmm_mark_chunk_occupied(pid_t owner, - u32_t start_ppn, - size_t page_count, - pp_attr_t attr) +pmm_init(struct boot_handoff* bctx) { - 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 }; - } -} + ptr_t pplist_pa; -// 我们跳过位于0x0的页。我们不希望空指针是指向一个有效的内存空间。 -#define LOOKUP_START 1 + llist_init_head(&memory.reserved); -volatile size_t pg_lookup_ptr; + pplist_pa = pmm_arch_init_remap(&memory, bctx); + + if (!pplist_pa) { + spin(); + } -void -pmm_init(ptr_t mem_upper_lim) -{ - max_pg = (PG_ALIGN(mem_upper_lim) >> 12); + pmm_arch_init_pool(&memory); - pg_lookup_ptr = LOOKUP_START; + pmm_allocator_init(&memory); - // mark all as occupied - for (size_t i = 0; i < PM_BMP_MAX_SIZE; i++) { - pm_table[i] = - (struct pp_struct){ .owner = 0, .attr = 0, .ref_counts = 1 }; + for (size_t i = 0; i < POOL_COUNT; i++) + { + pmm_allocator_init_pool(&memory.pool[i]); } + + pfn_t pplist_size = memory.list_len * sizeof(struct ppage); + pmm_onhold_range(pfn(pplist_pa), leaf_count(pplist_size)); } -ptr_t -pmm_alloc_cpage(pid_t owner, size_t num_pages, pp_attr_t attr) +static inline bool must_inline optimize("-fipa-cp-clone") +__pmm_mark_range(pfn_t start, size_t npages, const bool hold) { - 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 (start >= memory.list_len) { + return true; } - if (p2 == max_pg && p2 - p1 < num_pages) { - return NULLPTR; - } + struct ppage *_start, *_end, + *_mark_start, *_mark_end; - pmm_mark_chunk_occupied(owner, p1, num_pages, attr); + _start = ppage(start); + _end = ppage(start + npages - 1); + + struct pmem_pool* pool; + for (int i = 0; npages && i < POOL_COUNT; i++) { + pool = &memory.pool[i]; - return p1 << 12; -} + _mark_start = MAX(pool->pool_start, _start); + _mark_end = MIN(pool->pool_end, _end); + if (pool->pool_end < _mark_start || _mark_end < pool->pool_start) { + continue; + } -ptr_t -pmm_alloc_page(pid_t owner, pp_attr_t attr) -{ - // Next fit approach. Maximize the throughput! - ptr_t good_page_found = (ptr_t)NULL; - size_t old_pg_ptr = pg_lookup_ptr; - size_t upper_lim = max_pg; - struct pp_struct* pm; - while (!good_page_found && pg_lookup_ptr < upper_lim) { - 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; + bool _r; + if (hold) { + _r = pmm_allocator_trymark_onhold(pool, _mark_start, _mark_end); } else { - pg_lookup_ptr++; - - // We've searched the interval [old_pg_ptr, max_pg) but failed - // may be chances in [1, old_pg_ptr) ? - // Let's find out! - if (pg_lookup_ptr >= upper_lim && old_pg_ptr != LOOKUP_START) { - upper_lim = old_pg_ptr; - pg_lookup_ptr = LOOKUP_START; - old_pg_ptr = LOOKUP_START; - } + _r = pmm_allocator_trymark_unhold(pool, _mark_start, _mark_end); + } + + if (_r) + { + npages -= (ppfn(_mark_end) - ppfn(_mark_start)) + 1; } } - return good_page_found; + + return !npages; } -int -pmm_free_page(pid_t owner, ptr_t page) +bool +pmm_onhold_range(pfn_t start, size_t npages) { - 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; - } + return __pmm_mark_range(start, npages, true); +} - // TODO: 检查权限,保证:1) 只有正在使用该页(包括被分享者)的进程可以释放; - // 2) 内核可释放所有页。 - pm->ref_counts--; - return 1; +bool +pmm_unhold_range(pfn_t start, size_t npages) +{ + return __pmm_mark_range(start, npages, false); } -int -pmm_ref_page(pid_t owner, ptr_t page) +struct pmem_pool* +pmm_pool_get(int pool_index) { - (void)owner; // TODO: do smth with owner + assert(pool_index < POOL_COUNT); - u32_t ppn = page >> 12; + return &memory.pool[pool_index]; +} - if (ppn >= PM_BMP_MAX_SIZE) { - return 0; - } +struct pmem_pool* +pmm_declare_pool(int pool, pfn_t start, pfn_t size) +{ + struct pmem_pool* _pool = &memory.pool[pool]; - struct pp_struct* pm = &pm_table[ppn]; - if (ppn >= max_pg || !pm->ref_counts) { - return 0; - } + _pool->type = POOL_UNIFIED; + _pool->pool_end = ppage(start + size - 1); + _pool->pool_start = ppage(start); - pm->ref_counts++; - return 1; + return _pool; } -struct pp_struct* -pmm_query(ptr_t pa) +static void +pmm_log_summary() { - u32_t ppn = pa >> 12; - - if (ppn >= PM_BMP_MAX_SIZE) { - return NULL; + pfn_t len; + struct pmem_pool* _pool; + + INFO("init: nr_pages=%ld, gran=0x%lx", memory.list_len, 1 << PAGE_SHIFT); + + for (int i = 0; i < POOL_COUNT; i++) + { + _pool = &memory.pool[i]; + len = ppfn(_pool->pool_end) - ppfn(_pool->pool_start) + 1; + + INFO("pool #%d (%d), %ld-%ld(0x%lx)", + i , _pool->type, + ppfn(_pool->pool_start), ppfn(_pool->pool_end), len); } - - return &pm_table[ppn]; -} \ No newline at end of file +} +owloysius_fetch_init(pmm_log_summary, on_sysconf); \ No newline at end of file