-#include <lunaix/mm/page.h>
-#include <lunaix/mm/pmm.h>
#include <lunaix/status.h>
+#include <lunaix/mm/pagetable.h>
+#include <lunaix/spike.h>
+#include <lunaix/owloysius.h>
+#include <lunaix/syslog.h>
-// This is a very large array...
-static struct pp_struct pm_table[PM_BMP_MAX_SIZE];
+#include "pmm_internal.h"
-static uintptr_t max_pg;
+LOG_MODULE("pmm")
-void
-pmm_mark_page_free(uintptr_t ppn)
+static inline bool
+__check_typemask(struct ppage* page, ppage_type_t typemask)
{
- pm_table[ppn].ref_counts = 0;
+ return !page->type || (page->type & typemask);
}
-void
-pmm_mark_page_occupied(pid_t owner, uintptr_t ppn, pp_attr_t attr)
-{
- pm_table[ppn] = (struct pp_struct) {
- .owner = owner,
- .ref_counts = 1,
- .attr = attr
- };
-}
+static struct pmem memory;
+export_symbol(debug, pmm, memory);
void
-pmm_mark_chunk_free(uintptr_t start_ppn, size_t page_count)
+pmm_init(struct boot_handoff* bctx)
{
- for (size_t i = start_ppn; i < start_ppn + page_count && i < max_pg; i++)
- {
- pm_table[i].ref_counts = 0;
- }
-}
+ ptr_t pplist_pa;
-void
-pmm_mark_chunk_occupied(pid_t owner, uint32_t start_ppn, size_t page_count, pp_attr_t attr)
-{
- 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
- };
+ llist_init_head(&memory.reserved);
+
+ pplist_pa = pmm_arch_init_remap(&memory, bctx);
+
+ if (!pplist_pa) {
+ spin();
}
-}
-// 我们跳过位于0x0的页。我们不希望空指针是指向一个有效的内存空间。
-#define LOOKUP_START 1
+ pmm_arch_init_pool(&memory);
-size_t pg_lookup_ptr;
+ pmm_allocator_init(&memory);
-void
-pmm_init(uintptr_t mem_upper_lim)
-{
- max_pg = (PG_ALIGN(mem_upper_lim) >> 12);
+ for (size_t i = 0; i < POOL_COUNT; i++)
+ {
+ pmm_allocator_init_pool(&memory.pool[i]);
+ }
- pg_lookup_ptr = LOOKUP_START;
+ pfn_t pplist_size = memory.list_len * sizeof(struct ppage);
+ pmm_onhold_range(pfn(pplist_pa), leaf_count(pplist_size));
+}
- // 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
- };
+static inline bool must_inline optimize("-fipa-cp-clone")
+__pmm_mark_range(pfn_t start, size_t npages, const bool hold)
+{
+ if (start >= memory.list_len) {
+ return true;
}
-}
-void*
-pmm_alloc_cpage(pid_t owner, size_t num_pages, pp_attr_t attr) {
- size_t p1 = 0;
- size_t p2 = 0;
+ struct ppage *_start, *_end,
+ *_mark_start, *_mark_end;
- while (p2 < max_pg && p2 - p1 < num_pages)
- {
- (!(&pm_table[p2])->ref_counts) ? (p2++) : (p1 = p2);
- }
+ _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];
+
+ _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;
+ }
- if (p2 < max_pg) {
- return NULL;
+ bool _r;
+ if (hold) {
+ _r = pmm_allocator_trymark_onhold(pool, _mark_start, _mark_end);
+ } else {
+ _r = pmm_allocator_trymark_unhold(pool, _mark_start, _mark_end);
+ }
+
+ if (_r)
+ {
+ npages -= (ppfn(_mark_end) - ppfn(_mark_start)) + 1;
+ }
}
- pmm_mark_chunk_occupied(owner, p1, num_pages, attr);
+ return !npages;
+}
- return p1 << 12;
+bool
+pmm_onhold_range(pfn_t start, size_t npages)
+{
+ return __pmm_mark_range(start, npages, true);
}
-void*
-pmm_alloc_page(pid_t owner, pp_attr_t attr)
+bool
+pmm_unhold_range(pfn_t start, size_t npages)
{
- // Next fit approach. Maximize the throughput!
- uintptr_t good_page_found = (uintptr_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;
- } 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;
- }
- }
- }
- if (!good_page_found) {
- __current->k_status = LXOUTOFMEM;
- }
- return (void*)good_page_found;
+ return __pmm_mark_range(start, npages, false);
}
-int
-pmm_free_page(pid_t owner, void* page)
+struct pmem_pool*
+pmm_pool_get(int pool_index)
{
- 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;
- }
+ assert(pool_index < POOL_COUNT);
- // TODO: 检查权限,保证:1) 只有正在使用该页(包括被分享者)的进程可以释放; 2) 内核可释放所有页。
- pm->ref_counts--;
- return 1;
+ return &memory.pool[pool_index];
}
-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 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(void* pa) {
- uint32_t ppn = (uintptr_t)pa >> 12;
-
- if (ppn >= PM_BMP_MAX_SIZE) {
- return NULL;
- }
+static void
+pmm_log_summary()
+{
+ pfn_t len;
+ struct pmem_pool* _pool;
+
+ INFO("init: nr_pages=%ld, gran=0x%lx", memory.list_len, 1 << PAGE_SHIFT);
- return &pm_table[ppn];
-}
\ No newline at end of file
+ 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);
+ }
+}
+owloysius_fetch_init(pmm_log_summary, on_sysconf);
\ No newline at end of file