* @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);
/*
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
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);
// 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)
|
v
-
+
| xxxx | |
*/
coalesce(n_hdrptr);
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);