diff options
Diffstat (limited to 'tools/iso/kernel.soso/alloc.c')
-rw-r--r-- | tools/iso/kernel.soso/alloc.c | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/tools/iso/kernel.soso/alloc.c b/tools/iso/kernel.soso/alloc.c new file mode 100644 index 00000000..6e81b13c --- /dev/null +++ b/tools/iso/kernel.soso/alloc.c @@ -0,0 +1,226 @@ +#include "common.h" +#include "screen.h" +#include "alloc.h" +#include "vmm.h" +#include "process.h" +#include "debugprint.h" + +#define KMALLOC_MINSIZE 16 + +extern uint32 *gKernelPageDirectory; + +static char *gKernelHeap = NULL; +static uint32 gKernelHeapUsed = 0; + + +void initializeKernelHeap() { + gKernelHeap = (char *) KERN_HEAP_BEGIN; + + ksbrkPage(1); +} + +void *ksbrkPage(int n) { + struct MallocHeader *chunk; + char *p_addr; + int i; + + if ((gKernelHeap + (n * PAGESIZE_4M)) > (char *) KERN_HEAP_END) { + //printkf("ERROR: ksbrk(): no virtual memory left for kernel heap !\n"); + return (char *) -1; + } + + chunk = (struct MallocHeader *) gKernelHeap; + + for (i = 0; i < n; i++) { + p_addr = getPageFrame4M(); + + //printkf("DEBUG: ksbrkPage(): got 4M on physical %x\n", p_addr); + + if ((int)(p_addr) < 0) { + PANIC("PANIC: ksbrkPage(): no free page frame available !"); + return (char *) -1; + } + + addPageToPd(gKernelPageDirectory, gKernelHeap, p_addr, 0); //add PG_USER to allow user programs to read kernel heap + + gKernelHeap += PAGESIZE_4M; + } + + chunk->size = PAGESIZE_4M * n; + chunk->used = 0; + + return chunk; +} + +void *kmalloc(uint32 size) { + if (size==0) + return 0; + + unsigned long realsize; + struct MallocHeader *chunk, *other; + + if ((realsize = sizeof(struct MallocHeader) + size) < KMALLOC_MINSIZE) { + realsize = KMALLOC_MINSIZE; + } + + chunk = (struct MallocHeader *) KERN_HEAP_BEGIN; + while (chunk->used || chunk->size < realsize) { + if (chunk->size == 0) { + printkf("\nPANIC: kmalloc(): corrupted chunk on %x with null size (heap %x) !\nSystem halted\n", chunk, gKernelHeap); + + PANIC("kmalloc()"); + + return 0; + } + + chunk = (struct MallocHeader *)((char *)chunk + chunk->size); + + if (chunk == (struct MallocHeader *) gKernelHeap) { + if ((int)(ksbrkPage((realsize / PAGESIZE_4M) + 1)) < 0) { + PANIC("kmalloc(): no memory left for kernel !\nSystem halted\n"); + + return 0; + } + } + else if (chunk > (struct MallocHeader *) gKernelHeap) { + printkf("\nPANIC: kmalloc(): chunk on %x while heap limit is on %x !\nSystem halted\n", chunk, gKernelHeap); + + PANIC("kmalloc()"); + + return 0; + } + } + + + if (chunk->size - realsize < KMALLOC_MINSIZE) { + chunk->used = 1; + } + else { + other = (struct MallocHeader *)((char *) chunk + realsize); + other->size = chunk->size - realsize; + other->used = 0; + + chunk->size = realsize; + chunk->used = 1; + } + + gKernelHeapUsed += realsize; + + return (char *) chunk + sizeof(struct MallocHeader); +} + +void kfree(void *v_addr) { + if (v_addr==(void*)0) + return; + + struct MallocHeader *chunk, *other; + + chunk = (struct MallocHeader *)((uint32)v_addr - sizeof(struct MallocHeader)); + chunk->used = 0; + + gKernelHeapUsed -= chunk->size; + + //Merge free block with next free block + while ((other = (struct MallocHeader *)((char *)chunk + chunk->size)) + && other < (struct MallocHeader *)gKernelHeap + && other->used == 0) { + chunk->size += other->size; + } +} + +static void sbrkPage(Process* process, int pageCount) { + if (pageCount > 0) { + for (int i = 0; i < pageCount; ++i) { + if ((process->heapNextUnallocatedPageBegin + PAGESIZE_4M) > (char*)USER_OFFSET_END) { + return; + } + + char * p_addr = getPageFrame4M(); + + if ((int)(p_addr) < 0) { + //PANIC("sbrkPage(): no free page frame available !"); + return; + } + + addPageToPd(process->pd, process->heapNextUnallocatedPageBegin, p_addr, PG_USER); + + process->heapNextUnallocatedPageBegin += PAGESIZE_4M; + } + } + else if (pageCount < 0) { + pageCount *= -1; + + for (int i = 0; i < pageCount; ++i) { + if (process->heapNextUnallocatedPageBegin - PAGESIZE_4M >= process->heapBegin) { + process->heapNextUnallocatedPageBegin -= PAGESIZE_4M; + + //This also releases the page frame + removePageFromPd(process->pd, process->heapNextUnallocatedPageBegin, TRUE); + } + } + } +} + +void initializeProcessHeap(Process* process) { + process->heapBegin = (char*) USER_OFFSET; + process->heapEnd = process->heapBegin; + process->heapNextUnallocatedPageBegin = process->heapBegin; + + //Userland programs (their code, data,..) start from USER_OFFSET + //So we should leave some space for them by moving heap pointer. + //As a result userspace malloc functions start from a forward point (+ USER_EXE_IMAGE). + + sbrk(process, USER_EXE_IMAGE); +} + +void *sbrk(Process* process, int nBytes) { + printkf("sbrk:1: pid:%d nBytes:%d\n", process->pid, nBytes); + + char* previousBreak = process->heapEnd; + printkf("before: %x\n", previousBreak); + + if (nBytes > 0) { + int remainingInThePage = process->heapNextUnallocatedPageBegin - process->heapEnd; + + //printkf("sbrk:2: remainingInThePage:%d\n", remainingInThePage); + + if (nBytes > remainingInThePage) { + int bytesNeededInNewPages = nBytes - remainingInThePage; + int neededNewPageCount = (bytesNeededInNewPages / PAGESIZE_4M) + 1; + + //printkf("sbrk:3: neededNewPageCount:%d\n", neededNewPageCount); + + uint32 freePages = getFreePageCount(); + if ((uint32)neededNewPageCount + 1 > freePages) { + return (void*)-1; + } + + sbrkPage(process, neededNewPageCount); + } + } + else if (nBytes < 0) { + char* currentPageBegin = process->heapNextUnallocatedPageBegin - PAGESIZE_4M; + + int remainingInThePage = process->heapEnd - currentPageBegin; + + //printkf("sbrk:4: remainingInThePage:%d\n", remainingInThePage); + + if (-nBytes > remainingInThePage) { + int bytesInPreviousPages = -nBytes - remainingInThePage; + int neededNewPageCount = (bytesInPreviousPages / PAGESIZE_4M) + 1; + + //printkf("sbrk:5: neededNewPageCount:%d\n", neededNewPageCount); + + sbrkPage(process, -neededNewPageCount); + } + } + + process->heapEnd += nBytes; + printkf("after: %x\n", process->heapEnd); + + return previousBreak; +} + +uint32 getKernelHeapUsed() { + return gKernelHeapUsed; +} |