258 lines
5.6 KiB
C
258 lines
5.6 KiB
C
// mm.c
|
|
// 09/01/03 Josh Holtrop
|
|
|
|
// 0x368000 is first available byte (this is right after the kernel @ 1mb and the initrd @ 2mb, 1440kb.
|
|
|
|
|
|
pageblock *first_pageblock = (pageblock *) 0;
|
|
dword mm_totalmem = 0x100000; //start counting from 1mb
|
|
dword mm_highestAddress = 0;
|
|
|
|
void mm_init()
|
|
{
|
|
dword *memmap_entries = (dword *) 0x9040A;
|
|
memmap_entry *maps = (memmap_entry *) 0x92000;
|
|
dword a;
|
|
for (a=0;a<(*memmap_entries);a++)
|
|
{
|
|
if (maps[a].attributes == 1) // (1) mem free to OS
|
|
{
|
|
mm_totalmem += maps[a].limit.lowdword;
|
|
if (mm_highestAddress < (maps[a].base.lowdword + maps[a].limit.lowdword))
|
|
mm_highestAddress = maps[a].base.lowdword + maps[a].limit.lowdword;
|
|
if ((maps[a].base.lowdword + maps[a].limit.lowdword) > (FREERAM_START+8192)) //goes past where we start freeram
|
|
{
|
|
if (maps[a].base.lowdword < FREERAM_START)
|
|
{
|
|
maps[a].limit.lowdword = maps[a].limit.lowdword - (FREERAM_START - maps[a].base.lowdword);
|
|
maps[a].base.lowdword = FREERAM_START; //block at least 4kb, starts >= FREERAM_START
|
|
}
|
|
if (first_pageblock == 0) //no pageblock page set up yet, so set it up here
|
|
{
|
|
first_pageblock = (pageblock *) maps[a].base.lowdword;
|
|
maps[a].base.lowdword += 4096;
|
|
maps[a].limit.lowdword -= 4096;
|
|
mm_init_pageblockpage(first_pageblock);
|
|
first_pageblock->base = maps[a].base.lowdword;
|
|
first_pageblock->length = maps[a].limit.lowdword / 4096;
|
|
first_pageblock->pid = MM_PB_AVAIL;
|
|
}
|
|
else //first_pageblock already set up, add on segment
|
|
{
|
|
pageblock *pb = first_pageblock;
|
|
for (;;)
|
|
{
|
|
if (pb->pid == MM_PB_NP)
|
|
break;
|
|
else
|
|
pb++;
|
|
}
|
|
pb->base = maps[a].base.lowdword;
|
|
pb->length = maps[a].limit.lowdword / 4096;
|
|
pb->pid = MM_PB_AVAIL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (first_pageblock == 0)
|
|
{
|
|
printf("ERROR! NO INITIAL PAGE BLOCK CREATED.");
|
|
asm("cli");
|
|
asm("hlt");
|
|
for (;;)
|
|
;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void mm_init_pageblockpage(pageblock *pbp)
|
|
{
|
|
int a;
|
|
for (a=0; a<256; a++) // 256 pageblock entries * 16 bytes per page block entry = 4096 bytes (1 page of pageblock entries)
|
|
{
|
|
pbp[a].base = 0;
|
|
pbp[a].length = 0;
|
|
pbp[a].pid = MM_PB_NP;
|
|
if (a<255)
|
|
pbp[a].link = (dword)(&pbp[a+1]);
|
|
else
|
|
pbp[a].link = 0;
|
|
}
|
|
}
|
|
|
|
|
|
void *mm_palloc(dword numpages, dword proc_pid)
|
|
{
|
|
if (proc_pid < PID_KERNEL)
|
|
return 0;
|
|
pageblock *pb = first_pageblock;
|
|
if (mm_freeentries() < 2)
|
|
{
|
|
if(mm_new_pageblock_page() == 0)
|
|
return 0;
|
|
}
|
|
pageblock *newentry = mm_nextpageblockentry();
|
|
for (;;)
|
|
{
|
|
if ((pb->pid == MM_PB_AVAIL) && (pb->length >= numpages))
|
|
break;
|
|
if (pb->link == 0)
|
|
return 0;
|
|
pb = (pageblock *)pb->link;
|
|
}
|
|
if (pb->length == numpages) //dont need a new entry, just mark this one as used :)
|
|
{
|
|
pb->pid = proc_pid;
|
|
return (void *)pb->base;
|
|
}
|
|
else //subtract out allocated number of pages from length
|
|
{
|
|
newentry->base = pb->base;
|
|
newentry->length = numpages;
|
|
newentry->pid = proc_pid;
|
|
pb->base += (numpages * 4096);
|
|
pb->length -= numpages;
|
|
return (void *)newentry->base;
|
|
}
|
|
}
|
|
|
|
|
|
dword mm_freeentries()
|
|
{
|
|
pageblock *pb = first_pageblock;
|
|
dword counter = 0;
|
|
for (;;)
|
|
{
|
|
if (pb->pid == MM_PB_NP)
|
|
counter++;
|
|
if (pb->link == 0)
|
|
return counter;
|
|
pb = (pageblock *) pb->link;
|
|
}
|
|
}
|
|
|
|
|
|
pageblock *mm_new_pageblock_page() //as of 09/26/03 this method leaks 4kb main memory per call, unrecoverable
|
|
{
|
|
pageblock *pb = first_pageblock;
|
|
for (;;)
|
|
{
|
|
if ((pb->pid == MM_PB_AVAIL) && (pb->length > 1))
|
|
{
|
|
pageblock *retval = (pageblock *)pb->base;
|
|
pb->base += 4096;
|
|
pb->length--;
|
|
mm_init_pageblockpage(retval); //zeros out, links new pageblock page
|
|
mm_lastpageblockentry()->link = (dword)retval; //set up link to new pageblock page
|
|
return retval;
|
|
}
|
|
pb = (pageblock *) pb->link;
|
|
if (pb == 0)
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
int mm_pfree(void *ptr)
|
|
{
|
|
if (ptr == 0)
|
|
return 2;
|
|
pageblock *pb = first_pageblock;
|
|
dword tofree = (dword) ptr;
|
|
for (;;)
|
|
{
|
|
if (pb->base == tofree) // && (pb->pid == MM_PB_USED))
|
|
{
|
|
pb->pid = MM_PB_AVAIL; //found block, mark available / coalesce it
|
|
mm_coalesce(pb);
|
|
return 0;
|
|
}
|
|
if (pb->link == 0)
|
|
return 1;
|
|
pb = (pageblock *) pb->link;
|
|
}
|
|
}
|
|
|
|
|
|
pageblock *mm_lastpageblockentry()
|
|
{
|
|
pageblock *pb = first_pageblock;
|
|
for (;;)
|
|
{
|
|
if (pb->link == 0)
|
|
return pb;
|
|
pb = (pageblock *)pb->link;
|
|
}
|
|
}
|
|
|
|
|
|
pageblock *mm_nextpageblockentry()
|
|
{
|
|
pageblock *pb = first_pageblock;
|
|
for (;;)
|
|
{
|
|
if (pb->pid == MM_PB_NP)
|
|
return pb;
|
|
if (pb->link == 0)
|
|
return 0;
|
|
pb = (pageblock *)pb->link;
|
|
}
|
|
}
|
|
|
|
|
|
dword mm_freemem()
|
|
{
|
|
dword amount = 0;
|
|
pageblock *pb = first_pageblock;
|
|
for (;;)
|
|
{
|
|
if (pb->pid == MM_PB_AVAIL)
|
|
amount += (pb->length)*4096;
|
|
if (pb->link == 0)
|
|
return amount;
|
|
pb = (pageblock *) pb->link;
|
|
}
|
|
}
|
|
|
|
|
|
void mm_coalesce(pageblock *pb)
|
|
{
|
|
pageblock *pbc = first_pageblock;
|
|
for (;;)
|
|
{
|
|
if (pbc->pid == pb->pid) //pid fields must match, both same process, both avail, or both not present
|
|
{
|
|
if ((pbc->base + (pbc->length * 4096)) == pb->base) //pbc ends where pb starts
|
|
{
|
|
pbc->length += pb->length;
|
|
pb->pid = MM_PB_NP;
|
|
mm_coalesce(pbc); //recursion: checks for any more page blocks to coalesce if one found
|
|
return; //exit this recursion...
|
|
}
|
|
if ((pb->base + (pb->length * 4096)) == pbc->base) //pb ends where pbc starts
|
|
{
|
|
pb->length += pbc->length;
|
|
pbc->pid = MM_PB_NP;
|
|
mm_coalesce(pb);
|
|
return;
|
|
}
|
|
}
|
|
if (pbc->link == 0)
|
|
return;
|
|
pbc = (pageblock *)pbc->link;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|