feat: experimental tty console with scrollback buffer.
[lunaix-os.git] / lunaix-os / kernel / mm / kalloc.c
index 675a51f4033fe0191a5fba16c46e0f558e22f40e..ba00b09c8c2525f0a3f0d70b50dcdb2703205417 100644 (file)
@@ -2,29 +2,28 @@
  * @file kalloc.c
  * @author Lunaixsky
  * @brief Implicit free list implementation of malloc family, for kernel use.
- * 
+ *
  * This version of code is however the simplest and yet insecured, thread unsafe
  * it just to demonstrate how the malloc/free works behind the curtain
  * @version 0.1
  * @date 2022-03-05
- * 
+ *
  * @copyright Copyright (c) 2022
- * 
+ *
  */
-#include <lunaix/mm/kalloc.h>
 #include <lunaix/mm/dmm.h>
+#include <lunaix/mm/kalloc.h>
+#include <lunaix/mm/vmm.h>
 
-#include <lunaix/constants.h>
+#include <lunaix/common.h>
 #include <lunaix/spike.h>
 
-#include <libc/string.h>
+#include <klibc/string.h>
 
 #include <stdint.h>
 
 extern uint8_t __kernel_heap_start;
 
-heap_context_t __kalloc_kheap;
-
 void*
 lx_malloc_internal(heap_context_t* heap, size_t size);
 
@@ -42,16 +41,17 @@ lx_grow_heap(heap_context_t* heap, size_t sz);
 
 /*
     At the beginning, we allocate an empty page and put our initial marker
-    
+
     | 4/1 | 0/1 |
     ^     ^ brk
     start
 
-    Then, expand the heap further, with HEAP_INIT_SIZE (evaluated to 4096, i.e., 1 pg size)
-    This will allocate as much pages and override old epilogue marker with a free region hdr
-        and put new epilogue marker. These are handled by lx_grow_heap which is internally used
-        by alloc to expand the heap at many moment when needed.
-    
+    Then, expand the heap further, with HEAP_INIT_SIZE (evaluated to 4096, i.e.,
+   1 pg size) This will allocate as much pages and override old epilogue marker
+   with a free region hdr and put new epilogue marker. These are handled by
+   lx_grow_heap which is internally used by alloc to expand the heap at many
+   moment when needed.
+
     | 4/1 | 4096/0 |   .......   | 4096/0 | 0/1 |
     ^     ^ brk_old                       ^
     start                                 brk
@@ -59,43 +59,71 @@ lx_grow_heap(heap_context_t* heap, size_t sz);
     Note: the brk always point to the beginning of epilogue.
 */
 
+// FIXME: This should be per-process but not global!
+static heap_context_t kheap;
+
 int
-kalloc_init() {
-    __kalloc_kheap.start = &__kernel_heap_start;
-    __kalloc_kheap.brk = NULL;
-    __kalloc_kheap.max_addr = (void*)K_STACK_START;
+kalloc_init()
+{
+    kheap.start = KHEAP_START;
+    kheap.brk = NULL;
+    kheap.max_addr =
+      (void*)PROC_START; // 在新的布局中,堆结束的地方即为进程表开始的地方
+
+    for (size_t i = 0; i < KHEAP_SIZE_MB >> 2; i++) {
+        vmm_set_mapping(PD_REFERENCED,
+                        (uintptr_t)kheap.start + (i << 22),
+                        0,
+                        PG_PREM_RW,
+                        VMAP_NOMAP);
+    }
 
-    if (!dmm_init(&__kalloc_kheap)) {
+    if (!dmm_init(&kheap)) {
         return 0;
     }
 
-    SW(__kalloc_kheap.start, PACK(4, M_ALLOCATED));
-    SW(__kalloc_kheap.start + WSIZE, PACK(0, M_ALLOCATED));
-    __kalloc_kheap.brk += WSIZE;
+    SW(kheap.start, PACK(4, M_ALLOCATED));
+    SW(kheap.start + WSIZE, PACK(0, M_ALLOCATED));
+    kheap.brk += WSIZE;
 
-    return lx_grow_heap(&__kalloc_kheap, HEAP_INIT_SIZE) != NULL;
+    return lx_grow_heap(&kheap, HEAP_INIT_SIZE) != NULL;
 }
 
 void*
-lxmalloc(size_t size) {
-    return lx_malloc_internal(&__kalloc_kheap, size);
+lxmalloc(size_t size)
+{
+    mutex_lock(&kheap.lock);
+    void* r = lx_malloc_internal(&kheap, size);
+    mutex_unlock(&kheap.lock);
+
+    return r;
 }
 
 void*
-lxcalloc(size_t size) {
-    void* ptr = lxmalloc(size);
+lxcalloc(size_t n, size_t elem)
+{
+    size_t pd = n * elem;
+
+    // overflow detection
+    if (pd < elem || pd < n) {
+        return NULL;
+    }
+
+    void* ptr = lxmalloc(pd);
     if (!ptr) {
         return NULL;
     }
 
-    return memset(ptr, 0, size);
+    return memset(ptr, 0, pd);
 }
 
 void
-lxfree(void* ptr) {
+lxfree(void* ptr)
+{
     if (!ptr) {
         return;
     }
+    mutex_lock(&kheap.lock);
 
     uint8_t* chunk_ptr = (uint8_t*)ptr - WSIZE;
     uint32_t hdr = LW(chunk_ptr);
@@ -104,20 +132,20 @@ lxfree(void* ptr) {
 
     // make sure the ptr we are 'bout to free makes sense
     //   the size trick is stolen from glibc's malloc/malloc.c:4437 ;P
-    
+
     assert_msg(((uintptr_t)ptr < (uintptr_t)(-sz)) && !((uintptr_t)ptr & 0x3),
                "free(): invalid pointer");
-    
-    assert_msg(sz > WSIZE,
-               "free(): invalid size");
+
+    assert_msg(sz > WSIZE, "free(): invalid size");
 
     SW(chunk_ptr, hdr & ~M_ALLOCATED);
     SW(FPTR(chunk_ptr, sz), hdr & ~M_ALLOCATED);
     SW(next_hdr, LW(next_hdr) | M_PREV_FREE);
-    
+
     coalesce(chunk_ptr);
-}
 
+    mutex_unlock(&kheap.lock);
+}
 
 void*
 lx_malloc_internal(heap_context_t* heap, size_t size)
@@ -182,7 +210,7 @@ place_chunk(uint8_t* ptr, size_t size)
 
                         |
                         v
-                        
+
             | xxxx |                |
         */
         coalesce(n_hdrptr);
@@ -228,14 +256,13 @@ coalesce(uint8_t* chunk_ptr)
     return chunk_ptr;
 }
 
-
 void*
 lx_grow_heap(heap_context_t* heap, size_t sz)
 {
     void* start;
 
     // The "+ WSIZE" capture the overhead for epilogue marker
-    if (!(start = lxbrk(heap, sz + WSIZE))) {
+    if (!(start = lxsbrk(heap, sz + WSIZE, 0))) {
         return NULL;
     }
     sz = ROUNDUP(sz, BOUNDARY);