46bb1d3157
https://github.com/ozkl/soso + Much smaller than Linux; builds instantly + Supports graphics - No network support - Doesn't work on a cloud server (yet?)
258 lines
6.5 KiB
C
258 lines
6.5 KiB
C
#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) {
|
|
//Screen_PrintF("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();
|
|
|
|
//Screen_PrintF("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;
|
|
|
|
//Screen_PrintF("sbrk:2: remainingInThePage:%d\n", remainingInThePage);
|
|
|
|
if (nBytes > remainingInThePage)
|
|
{
|
|
int bytesNeededInNewPages = nBytes - remainingInThePage;
|
|
int neededNewPageCount = (bytesNeededInNewPages / PAGESIZE_4M) + 1;
|
|
|
|
//Screen_PrintF("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;
|
|
|
|
//Screen_PrintF("sbrk:4: remainingInThePage:%d\n", remainingInThePage);
|
|
|
|
if (-nBytes > remainingInThePage)
|
|
{
|
|
int bytesInPreviousPages = -nBytes - remainingInThePage;
|
|
int neededNewPageCount = (bytesInPreviousPages / PAGESIZE_4M) + 1;
|
|
|
|
//Screen_PrintF("sbrk:5: neededNewPageCount:%d\n", neededNewPageCount);
|
|
|
|
sbrkPage(process, -neededNewPageCount);
|
|
}
|
|
}
|
|
|
|
process->heapEnd += nBytes;
|
|
printkf("after: %x\n", process->heapEnd);
|
|
|
|
return previousBreak;
|
|
}
|
|
|
|
uint32 getKernelHeapUsed()
|
|
{
|
|
return gKernelHeapUsed;
|
|
}
|