refactor: elf parsing utility and exec related
[lunaix-os.git] / lunaix-os / kernel / mm / pmm.c
index 47087fdd3dad383b518d547137e9a1a68162f67e..3ebe22a10d34fdcec5446283534a1e10e4ca0051 100644 (file)
@@ -1,80 +1,49 @@
 #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];
 
-#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 uintptr_t max_pg;
 
-uint8_t pm_bitmap[PM_BMP_MAX_SIZE];
-
-uintptr_t max_pg;
-
-//  ... |xxxx xxxx |
-//  ... |-->|
 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,
+                        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){ .owner = owner, .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)
@@ -85,32 +54,49 @@ pmm_init(uintptr_t mem_upper_lim)
 
     // 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) ?
@@ -122,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
+
+    u32_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)
+{
+    u32_t ppn = (uintptr_t)pa >> 12;
+
+    if (ppn >= PM_BMP_MAX_SIZE) {
+        return NULL;
+    }
+
+    return &pm_table[ppn];
 }
\ No newline at end of file