make log a bit verbose for some useful information
[lunaix-os.git] / lunaix-os / kernel / mm / pmm.c
index 450353538d6d17d38ad02ec7a3ee88d2fdec5488..bc44be7ab6a30eb7b481f700003f1e65b735ff35 100644 (file)
-#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);
 
-// 我们跳过位于0x0的页。我们不希望空指针是指向一个有效的内存空间。
-#define LOOKUP_START 1
+    pplist_pa = pmm_arch_init_remap(&memory, bctx);
+    
+    if (!pplist_pa) {
+        spin();
+    }
 
-size_t pg_lookup_ptr;
+    pmm_arch_init_pool(&memory);
 
-void
-pmm_init(uintptr_t mem_upper_lim)
-{
-    max_pg = (PG_ALIGN(mem_upper_lim) >> 12);
+    pmm_allocator_init(&memory);
 
-    pg_lookup_ptr = LOOKUP_START;
-
-    // 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));
 }
 
-void*
-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 NULL;
-    }
+    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;
+        }
 
-void*
-pmm_alloc_page(pid_t owner, pp_attr_t attr)
-{
-    // 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;
+        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;
         }
     }
-    if (!good_page_found) {
-        __current->k_status = LXOUTOFMEM;
-    }
-    return (void*)good_page_found;
+
+    return !npages;
 }
 
-int
-pmm_free_page(pid_t owner, void* page)
+bool
+pmm_onhold_range(pfn_t start, size_t npages)
 {
-    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 __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, void* page)
+struct pmem_pool*
+pmm_pool_get(int pool_index)
 {
-    (void*)owner; // TODO: do smth with owner
+    assert(pool_index < POOL_COUNT);
 
-    uint32_t ppn = (uintptr_t)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(void* pa)
+static void
+pmm_log_summary()
 {
-    uint32_t ppn = (uintptr_t)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