#include #include #include #include #include #include #include #define MALLOC_MAGIC 0x616c6c6f63686472 /* "allochdr" */ #define DESCLEN 8 typedef struct Allocation Allocation; struct Allocation { uint64_t magic; uint64_t len; Allocation *next, *prev; void *stacktrace[4]; char desc[DESCLEN]; }; static Allocation *malloc_last = NULL; static size_t page_amt(size_t bytes) { return (bytes + PAGE_SIZE - 1) / PAGE_SIZE; } void mem_debugprint(void) { size_t count = 0, bytes = 0, pages = 0; kprintf("[kern] current allocations:\n"); for (Allocation *iter = malloc_last; iter; iter = iter->prev) { kprintf( "%08p %6dB %.8s ", ((void*)iter) + sizeof(Allocation), iter->len - sizeof(Allocation), iter->desc ); for (size_t i = 0; i < 4; i++) { kprintf(" k/%08x", iter->stacktrace[i]); } kprintf("\n"); count++; bytes += iter->len; pages += page_amt(iter->len); } kprintf( "%d in total, %d bytes, %d pages = %dB used\n", count, bytes, pages, pages*PAGE_SIZE ); } static void kmalloc_sanity(const void *addr) { assert(addr); const Allocation *hdr = addr - sizeof(Allocation); assert(hdr->magic == MALLOC_MAGIC); if (hdr->next) assert(hdr->next->prev == hdr); if (hdr->prev) assert(hdr->prev->next == hdr); } void * kmalloc(size_t len, const char *desc) { Allocation *hdr; void *addr; if (KMALLOC_MAX < len) { panic_invalid_state(); } len += sizeof(Allocation); assert(len <= PAGE_SIZE); hdr = page_alloc(page_amt(len)); hdr->magic = MALLOC_MAGIC; hdr->len = len; memset(hdr->desc, ' ', DESCLEN); if (desc) { for (int i = 0; i < DESCLEN; i++) { if (desc[i] == '\0') break; hdr->desc[i] = desc[i]; } } hdr->next = NULL; hdr->prev = malloc_last; if (hdr->prev) { assert(!hdr->prev->next); hdr->prev->next = hdr; } for (size_t i = 0; i < 4; i++) hdr->stacktrace[i] = debug_caller(i); malloc_last = hdr; addr = (void*)hdr + sizeof(Allocation); #ifndef NDEBUG memset(addr, 0xCC, len); #endif kmalloc_sanity(addr); return addr; } void kfree(void *ptr) { Allocation *hdr; size_t len; if (ptr == NULL) return; kmalloc_sanity(ptr); hdr = ptr - sizeof(Allocation); len = hdr->len; if (hdr->next) hdr->next->prev = hdr->prev; if (hdr->prev) hdr->prev->next = hdr->next; if (malloc_last == hdr) malloc_last = hdr->prev; #ifndef NDEBUG memset(hdr, 0xC0, len); #else hdr->magic = ~MALLOC_MAGIC; /* (hopefully) detect double frees */ #endif page_free(hdr, page_amt(len)); }