// 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; //assume 1mb 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 ((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->flags = MM_PB_AVAIL; } else //first_pageblock already set up, add on segment { pageblock *pb = first_pageblock; for (;;) { if (pb->flags == MM_PB_NP) break; else pb++; } pb->base = maps[a].base.lowdword; pb->length = maps[a].limit.lowdword / 4096; pb->flags = MM_PB_AVAIL; } } } } if (first_pageblock == 0) { printf("ERROR! NO INITIAL PAGE BLOCK COULD BE CREATED."); asm("cli"); asm("hlt"); } } void mm_init_pageblockpage(pageblock *pbp) { pageblock *pb = pbp; int a; for (a=0; a<512; a++) { pb->base = 0; pb->length = 0; pb->flags = MM_PB_NP; if (a<511) pb->link = (dword)pb + sizeof(pageblock); else pb->link = 0; pb++; } } void *mm_palloc(dword numpages) { pageblock *pb = first_pageblock; dword freeentries = mm_freeentries(); if (freeentries < 2) { if(mm_new_pageblock_page() == 0) return 0; } pageblock *newentry = mm_nextpageblockentry(); for (;;) { if ((pb->flags == 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->flags = MM_PB_USED; return pb; } else //subtract out allocated number of pages from length { newentry->base = pb->base; newentry->length = numpages; newentry->flags = MM_PB_USED; pb->base += (numpages * 4096); pb->length -= numpages; return (void *)newentry->base; } } dword mm_freeentries() { pageblock *pb = first_pageblock; dword counter = 0; for (;;) { if (pb->flags == MM_PB_NP) counter++; if (pb->link == 0) return counter; pb = (pageblock *) pb->link; } } pageblock *mm_new_pageblock_page() { pageblock *pb = first_pageblock; for (;;) { if ((pb->flags == 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) { pageblock *pb = first_pageblock; dword tofree = (dword) ptr; for (;;) { if ((pb->base == tofree) && (pb->flags == MM_PB_USED)) { pb->flags = MM_PB_AVAIL; //found block, mark available / coalesce it pageblock *pbc = first_pageblock; for (;;) { if (pbc->flags == MM_PB_AVAIL) { if ((pbc->base + (pbc->length * 4096)) == pb->base) //pbc ends where pb starts { pbc->length += pb->length; //extend pbc's length by pb's length pb->flags = MM_PB_NP; //mark pb as an unused entry return 0; } if ((pb->base + (pb->length * 4096)) == pbc->base) //pb ends where pb starts { pb->length += pbc->length; pbc->flags = MM_PB_NP; return 0; } } if (pbc->link == 0) //no entry found to consolidate... return 0; pbc = (pageblock *) pbc->link; //next entry to test } } 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->flags == 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->flags == MM_PB_AVAIL) amount += (pb->length)*4096; if (pb->link == 0) return amount; pb = (pageblock *) pb->link; } }