diff --git a/core/alloc.c b/core/alloc.c index 6b08a7c..d7414b6 100644 --- a/core/alloc.c +++ b/core/alloc.c @@ -1,6 +1,8 @@ #define pr_fmt(fmt) "[alloc]: " fmt //#define DEBUG #include "alloc.h" +#include "allocArea.h" +#include "assert.h" #include "errno.h" #include "irq.h" #include "kernel.h" @@ -11,8 +13,8 @@ #include "paging.h" #define IS_SELF_CONTAINED(desc) ((vaddr_t)((desc)->page) == (vaddr_t)(desc)) -// Slab will contains object from sizeof(void *) to PAGE_SIZE/2 by pow2 static struct slabDesc *slub; +static int allocInitialized = FALSE; static int allocSlab(struct slabDesc **desc, size_t sizeEl, size_t sizeSlab, int self_containing); @@ -20,14 +22,13 @@ static int allocSlabEntry(struct slabEntry **desc, size_t sizeEl, size_t sizeSla int selfContained); static int formatPage(struct slabEntry *desc, size_t size, size_t sizeSlab, int selfContained); static int freeFromSlab(void *ptr, struct slabEntry *slab); +static struct slabDesc *allocGetSlab(size_t size); static struct { size_t elementSize; size_t slabSize; unsigned char isSelf; -} initSlab[] = {{sizeof(struct slabDesc), PAGE_SIZE, 1}, - {sizeof(struct slabEntry), PAGE_SIZE, 1}, - {4, PAGE_SIZE, 0}, +} initSlab[] = {{4, PAGE_SIZE, 0}, {8, PAGE_SIZE, 0}, {16, PAGE_SIZE, 0}, {32, PAGE_SIZE, 0}, @@ -37,14 +38,25 @@ static struct { {1024, 2 * PAGE_SIZE, 0}, {2048, 3 * PAGE_SIZE, 0}, {4096, 4 * PAGE_SIZE, 0}, - {8192, 8 * PAGE_SIZE, 0}, - {16384, 12 * PAGE_SIZE, 0}, {0, 0, 0}}; -int allocSetup(void) +int allocSetup(size_t sizeOfArea, vaddr_t *areaAddr, vaddr_t *descAddr, vaddr_t *entryAddr) { list_init(slub); + assert(allocBookSlab(sizeof(struct slabDesc), PAGE_SIZE, TRUE) == 0); + *descAddr = (vaddr_t)allocGetSlab(sizeof(struct slabDesc)); + assert(allocBookSlab(sizeof(struct slabEntry), PAGE_SIZE, TRUE) == 0); + *entryAddr = (vaddr_t)allocGetSlab(sizeof(struct slabEntry)); + assert(allocBookSlab(sizeOfArea, PAGE_SIZE, TRUE) == 0); + *areaAddr = (vaddr_t)allocGetSlab(sizeOfArea); + allocInitialized = TRUE; + + return 0; +} + +int allocPopulate() +{ for (uint i = 0; initSlab[i].elementSize != 0; i++) { int ret; @@ -52,7 +64,7 @@ int allocSetup(void) initSlab[i].isSelf))) { if (ret == -EEXIST) continue; - pr_devel("Fail to allocBookSlab %d for %d \n", ret, (1U << i)); + pr_err("Fail to allocBookSlab %d for %d \n", ret, (1U << i)); return ret; } @@ -84,6 +96,7 @@ int allocBookSlab(size_t sizeEl, size_t sizeSlab, int selfContained) } if ((ret = allocSlab(&newSlab, sizeEl, sizeSlab, selfContained))) { + pr_devel("Failed to alloc Slab\n"); restore_IRQs(flags); return ret; } @@ -102,6 +115,7 @@ int allocBookSlab(size_t sizeEl, size_t sizeSlab, int selfContained) static int allocSlab(struct slabDesc **desc, size_t size, size_t sizeSlab, int selfContained) { uint nbPage, i; + vaddr_t alloc; pr_devel("%s for size %d is self %d\n", __func__, size, selfContained); @@ -111,21 +125,27 @@ static int allocSlab(struct slabDesc **desc, size_t size, size_t sizeSlab, int s return -ENOENT; } - nbPage = DIV_ROUND_UP(sizeSlab, PAGE_SIZE); - paddr_t alloc = allocPhyPage(nbPage); - if (alloc == (paddr_t)NULL) - return -ENOMEM; + nbPage = DIV_ROUND_UP(sizeSlab, PAGE_SIZE); + if (allocInitialized) { + alloc = areaAlloc(nbPage); + if (alloc == (paddr_t)NULL) + return -ENOMEM; + } else { + alloc = (vaddr_t)allocPhyPage(nbPage); + if (alloc == (paddr_t)NULL) + return -ENOMEM; - for (i = 0; i < nbPage; i++) { - if (pageMap((vaddr_t)alloc + i * PAGE_SIZE, alloc + i * PAGE_SIZE, PAGING_MEM_WRITE)) - goto free_page; + for (i = 0; i < nbPage; i++) { + if (pageMap(alloc + i * PAGE_SIZE, alloc + i * PAGE_SIZE, PAGING_MEM_WRITE)) + goto free_page; + } } if (selfContained) { *desc = (struct slabDesc *)alloc; ((*desc)->slab).freeEl = (char *)(*desc) + sizeof(struct slabDesc); } else { - *desc = malloc(sizeof(struct slabDesc)); + *desc = malloc(sizeof(struct slabDesc)); if (*desc == NULL) return -ENOMEM; (*desc)->slab.freeEl = (void *)alloc; @@ -151,7 +171,7 @@ free_page: static int allocSlabEntry(struct slabEntry **desc, size_t size, size_t sizeSlab, int selfContained) { - uint nbPage, i; + uint nbPage; pr_devel("%s for size %d is self %d\n", __func__, size, selfContained); @@ -162,20 +182,15 @@ static int allocSlabEntry(struct slabEntry **desc, size_t size, size_t sizeSlab, } nbPage = DIV_ROUND_UP(sizeSlab, PAGE_SIZE); - paddr_t alloc = allocPhyPage(nbPage); + vaddr_t alloc = areaAlloc(nbPage); if (alloc == (paddr_t)NULL) return -ENOMEM; - for (i = 0; i < nbPage; i++) { - if (pageMap((vaddr_t)alloc + i * PAGE_SIZE, alloc + i * PAGE_SIZE, PAGING_MEM_WRITE)) - goto free_page; - } - if (selfContained) { *desc = (struct slabEntry *)alloc; (*desc)->freeEl = (char *)(*desc) + sizeof(struct slabEntry); } else { - *desc = malloc(sizeof(struct slabEntry)); + *desc = malloc(sizeof(struct slabEntry)); if (*desc == NULL) return -ENOMEM; (*desc)->freeEl = (void *)alloc; @@ -188,11 +203,6 @@ static int allocSlabEntry(struct slabEntry **desc, size_t size, size_t sizeSlab, return formatPage((*desc), size, sizeSlab, selfContained); -free_page: - for (uint j = 0; j < i; j++) { - pageUnmap((vaddr_t)alloc + i * PAGE_SIZE); - } - return -ENOMEM; } @@ -227,24 +237,36 @@ static void *allocFromSlab(struct slabEntry *slab) return (void *)next; } +static struct slabDesc *allocGetSlab(size_t size) +{ + struct slabDesc *slab = NULL; + uint slubIdx; + + list_foreach(slub, slab, slubIdx) + { + if (size <= slab->size) + return slab; + } + + return NULL; +} + void *malloc(size_t size) { struct slabEntry *slabEntry; struct slabDesc *slab = NULL; - uint slubIdx; void *ret; int flags; int slabIdx; disable_IRQs(flags); - list_foreach(slub, slab, slubIdx) - { - if (size <= slab->size) - break; - } + if (size >= PAGE_SIZE){ + vaddr_t area = areaAlloc(DIV_ROUND_UP(size, PAGE_SIZE)); - if (!list_foreach_early_break(slub, slab, slubIdx)) { + return (void *)area; + } + if ((slab = allocGetSlab(size)) == NULL) { pr_devel("No slab found for %d\n", size); return NULL; } @@ -302,11 +324,7 @@ static int freeFromSlab(void *ptr, struct slabEntry *slab) return 0; } -void free(void *ptr) -{ - if (!ptr) - return; - +int freeSlabAllocated(void *ptr){ struct slabDesc *slab; int slabIdx; int flags; @@ -321,11 +339,21 @@ void free(void *ptr) { if (freeFromSlab(ptr, slabEntry)) { restore_IRQs(flags); - return; + return 0; } } } - restore_IRQs(flags); - pr_devel("free: slab not found\n"); + + return -1; +} + +void free(void *ptr) +{ + if (!ptr) + return; + if(!freeSlabAllocated(ptr)) + return; + if(areaFree((vaddr_t)ptr)) + pr_err("free: cannot found origin\n"); } diff --git a/core/alloc.h b/core/alloc.h index 7095988..176f7a1 100644 --- a/core/alloc.h +++ b/core/alloc.h @@ -5,8 +5,9 @@ /* * Initialize malloc system */ -int allocSetup(void); +int allocSetup(size_t sizeOfArea, vaddr_t *areaAddr, vaddr_t *descAddr, vaddr_t *entryAddr); +int allocPopulate(); /* * Allow malloc to allocate elements of this precise size. * Otherwise the allocation will be in the closest biggest pool. diff --git a/core/allocArea.c b/core/allocArea.c index 7713091..5c999ed 100644 --- a/core/allocArea.c +++ b/core/allocArea.c @@ -6,20 +6,29 @@ #include "mem.h" #include "stdarg.h" -struct memArea { - vaddr_t startAddr; - uint nbPages; - struct memArea *next; - struct memArea *prev; -}; static struct memArea *freeArea; static struct memArea *usedArea; -void areaInit(void) +static int areaMergeFreeArea(struct memArea *prev, struct memArea *next); + +void areaInit(vaddr_t firstMemUsed, vaddr_t lastUsed) { list_init(freeArea); list_init(usedArea); + + vaddr_t areaAddr, descAddr, entryAddr; + allocSetup(sizeof(struct memArea), &areaAddr, &descAddr, &entryAddr); + areaAdd(descAddr, PAGE_SIZE, FALSE); + if (entryAddr != descAddr) + areaAdd(entryAddr, PAGE_SIZE, FALSE); + if (areaAddr != descAddr && areaAddr != entryAddr) + areaAdd(areaAddr, PAGE_SIZE, FALSE); + + int nbPages = DIV_ROUND_UP((lastUsed - firstMemUsed), PAGE_SIZE); + areaAdd(ALIGN_DOWN(firstMemUsed, PAGE_SIZE), nbPages, FALSE); + areaAdd(ALIGN_DOWN(areaAddr + PAGE_SIZE, PAGE_SIZE), 300 , TRUE); + allocPopulate(); } struct memArea *areaFindFit(unsigned int nbPages) @@ -35,22 +44,22 @@ struct memArea *areaFindFit(unsigned int nbPages) return NULL; } -static void insertSorted(struct memArea *list, struct memArea *item) +static void insertSorted(struct memArea **list, struct memArea *item) { struct memArea *prev, *cur; int count; prev = NULL; - list_foreach(list, cur, count) + list_foreach(*list, cur, count) { if (cur->startAddr > item->startAddr) break; prev = cur; } if (prev) - list_insert_after(list, prev, item); + list_insert_after(*list, prev, item); else - list_add_tail(list, item); + list_add_tail(*list, item); } vaddr_t areaAlloc(unsigned int nbPages) @@ -63,13 +72,15 @@ vaddr_t areaAlloc(unsigned int nbPages) if (area->nbPages == nbPages) { list_delete(freeArea, area); - insertSorted(usedArea, area); + insertSorted(&usedArea, area); allocated = area; } struct memArea *newArea = (struct memArea *)malloc(sizeof(struct memArea)); - if (!newArea) + if (!newArea){ + pr_devel("Failed to allocated area of %d pages\n", nbPages); return (vaddr_t)NULL; + } // Avoid insertSorted(freeArea, newArea) call by modifying area @@ -79,14 +90,14 @@ vaddr_t areaAlloc(unsigned int nbPages) area->nbPages -= nbPages; area->startAddr += nbPages * PAGE_SIZE; - insertSorted(usedArea, newArea); + insertSorted(&usedArea, newArea); allocated = newArea; for (uint i = 0; i < nbPages; i++) { paddr_t page = allocPhyPage(1); if (page) { - pageMap(area->startAddr + i * PAGE_SIZE, page, PAGING_MEM_WRITE); + pageMap(newArea->startAddr + i * PAGE_SIZE, page, PAGING_MEM_WRITE); } else { // TODO assert(1); @@ -96,6 +107,36 @@ vaddr_t areaAlloc(unsigned int nbPages) return allocated->startAddr; } +int areaAdd(vaddr_t addr, uint nbPages, int isFree) +{ + struct memArea **area; + + struct memArea *newArea = (struct memArea *)malloc(sizeof(struct memArea)); + if (!newArea) + return (vaddr_t)NULL; + + newArea->nbPages = nbPages; + newArea->startAddr = addr; + + if (isFree) { + area = &freeArea; + } else { + area = &usedArea; + } + + insertSorted(area, newArea); + + if (isFree) { + if (newArea->prev) + areaMergeFreeArea(newArea->prev, *area); + + if (newArea->next) + areaMergeFreeArea(*area, newArea->next); + } + + return 0; +} + static int areaMergeFreeArea(struct memArea *prev, struct memArea *next) { if (prev->startAddr + prev->nbPages * PAGE_SIZE != next->startAddr) { @@ -134,7 +175,7 @@ int areaFree(vaddr_t addr) return -1; } list_delete(usedArea, area); - insertSorted(freeArea, area); + insertSorted(&freeArea, area); if (area->prev) areaMergeFreeArea(area->prev, area); diff --git a/core/allocArea.h b/core/allocArea.h index 0bea2cc..292190b 100644 --- a/core/allocArea.h +++ b/core/allocArea.h @@ -1,6 +1,16 @@ #pragma once #include "paging.h" +#include "stdarg.h" -void areaInit(void); +struct memArea { + vaddr_t startAddr; + uint nbPages; + + struct memArea *next; + struct memArea *prev; +}; + +void areaInit(vaddr_t firstMemUsed, vaddr_t lastUsed); vaddr_t areaAlloc(unsigned int nbPages); int areaFree(vaddr_t addr); +int areaAdd(vaddr_t addr, uint nbPages, int isFree); diff --git a/core/klibc.h b/core/klibc.h index ea1b89e..c4a5490 100644 --- a/core/klibc.h +++ b/core/klibc.h @@ -51,3 +51,4 @@ int vasprintf(char **strp, const char *fmt, va_list ap); #endif #define pr_info(fmt, ...) printf(pr_fmt(fmt), ##__VA_ARGS__) +#define pr_err(fmt, ...) {printf(pr_fmt(fmt), ##__VA_ARGS__); assert(0);} diff --git a/core/main.c b/core/main.c index 835d3c2..d6268be 100644 --- a/core/main.c +++ b/core/main.c @@ -1,4 +1,5 @@ #include "alloc.h" +#include "allocArea.h" #include "exception.h" #include "gdt.h" #include "idt.h" @@ -143,7 +144,8 @@ void kmain(unsigned long magic, unsigned long addr) serialSetup(115200); printf("Setting up allocation system\n"); - allocSetup(); + areaInit(firstUsedByMem, lastUsedByMem); + //allocSetup(); printf("Setting up thread system\n"); kthreadSetup(_stack_bottom, (_stack_top - _stack_bottom + 1)); diff --git a/custom_gdb_extension.py b/custom_gdb_extension.py index 3af1f4c..5ce128e 100644 --- a/custom_gdb_extension.py +++ b/custom_gdb_extension.py @@ -136,6 +136,92 @@ class PhyMemDescListDumpCmd(gdb.Command): print(self._phy_memDesc_lit_to_str(desc)) +class PrintStructC99Cmd(gdb.Command): + def __init__(self): + super(PrintStructC99Cmd, self).__init__( + "print_struct_c99", + gdb.COMMAND_USER, + ) + + def complete(self, text, word): + return gdb.COMPLETE_SYMBOL + + def get_count_heading(self, string): + for i, s in enumerate(string): + if s != ' ': + break + return i + + def extract_typename(self, string): + first_line = string.split('\n')[0] + return first_line.split('=')[1][:-1].strip() + + def invoke(self, arg, from_tty): + gdb.execute("set print pretty") + gdb.execute('set pagination off') + gdb.execute('set print repeats 0') + gdb.execute('set print elements unlimited') + ret_ptype = gdb.execute('ptype {}'.format(arg), to_string=True) + tname = self.extract_typename(ret_ptype) + print('{} {} = {{'.format(tname, arg)) + r = gdb.execute('p {}'.format(arg), to_string=True) + r = r.split('\n') + for rr in r[1:]: + if '=' not in rr: + print(rr) + continue + hs = self.get_count_heading(rr) + rr_s = rr.strip().split('=', 1) + rr_rval = rr_s[1].strip() + print(' ' * hs + '.' + rr_s[0] + '= ' + rr_rval) + +class ListDumpCmd(gdb.Command): + """Prints a linked list""" + + def __init__(self): + super(ListDumpCmd, self).__init__( + "list_dump", gdb.COMMAND_USER + ) + + def _print_list(self, val): + """Walk through the linked list. + + We will simply follow the 'next' pointers until we encounter the HEAD again + """ + idx = 0 + head = val + kthread_ptr = val + result = "" + while kthread_ptr != 0 and (idx == 0 or kthread_ptr != head): + result += gdb.execute('p *({}){}'.format(str(kthread_ptr.type),kthread_ptr), to_string=True) + kthread_ptr = kthread_ptr["next"] + idx += 1 + result = ("Found a Linked List with %d items:" % idx) + "\n"+ result + return result + + def complete(self, text, word): + # We expect the argument passed to be a symbol so fallback to the + # internal tab-completion handler for symbols + return gdb.COMPLETE_SYMBOL + + def invoke(self, args, from_tty): + # We can pass args here and use Python CLI utilities like argparse + # to do argument parsing + print("Args Passed: %s" % args) + if args: + ptr_val = gdb.parse_and_eval(args) + else: + ptr_val = gdb.parse_and_eval("currentThread") + try: + ptr_val["next"] + except: + print("Expected pointer argument with a next field") + return + + print(self._print_list(ptr_val)) + register_pretty_printer(None, CustomPrettyPrinterLocator(), replace=True) KthreadListDumpCmd() PhyMemDescListDumpCmd() +PrintStructC99Cmd() +ListDumpCmd() diff --git a/tests/test.c b/tests/test.c index 2dac77d..b1a11c1 100644 --- a/tests/test.c +++ b/tests/test.c @@ -109,6 +109,7 @@ static void testAlloc(void) void *alloc5 = testAllocNSet(1024); void *alloc6 = testAllocNSet(1024); void *alloc7 = testAllocNSet(4096); + void *alloc8 = testAllocNSet(8192); free(alloc1); free(alloc2); free(alloc3); @@ -116,6 +117,7 @@ static void testAlloc(void) free(alloc5); free(alloc6); free(alloc7); + free(alloc8); void *alloc11 = testAllocNSet(1024); void *alloc12 = testAllocNSet(1024); void *alloc13 = testAllocNSet(1024);