// 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; } }