// mm.c // Author: Josh Holtrop // Created: 09/01/03 // Modified: 07/12/04 #include "kernel.h" #include "mm/mm.h" #include "multiboot.h" #include "hos_defines.h" extern mb_info_t mb_info_block; extern mb_mmap_t mb_mmap[MAX_MMAP]; extern u32_t mmap_entries; extern mb_module_t mb_modules[MAX_MODULES]; u32_t mm_totalmem; u32_t mm_megabytes; u32_t mm_freepages; u32_t mm_first_free_byte; byte page_bitmap[MM_BITMAP_SIZE]; //used to store a bit for each page that is used, 0 if available //0x20000*(8 bits/byte)=0x100000 pages in 4gb total //This function initializes the memory manager's linked list, filling it with the // memory areas returned by bios interrupt 0x8E20 void mm_init() { u32_t a; for (a = 0; a < MM_BITMAP_SIZE; a++) //mark all pages used { page_bitmap[a] = 0xFF; } for (a = 0; a < mmap_entries; a++) //free BIOS #1 areas { if (mb_mmap[a].type == 1) // (1) mem free to OS { mm_totalmem += mb_mmap[a].length; u32_t freethis = mb_mmap[a].base; u32_t limit = mb_mmap[a].base + mb_mmap[a].length - 4096; while (freethis <= limit) { if (freethis >= PHYS_LOAD) //above physical kernel load point mm_pfree(freethis); freethis += 4096; } } } mm_preserven(PHYS_LOAD, ((u32_t)&_end - (u32_t)&start) >> 12); //reserve kernel memory int i; for (i = 0; i < mb_info_block.mods_count; i++) //reserve module memory { mm_preserven(mb_modules[i].mod_start - VIRT_OFFSET, (mb_modules[i].mod_end - mb_modules[i].mod_start) >> 12); } if (mm_totalmem % 0x100000) mm_megabytes = (mm_totalmem >> 20) + 1; else mm_megabytes = mm_totalmem >> 20; } // This function frees a certain number of pages starting at the address // specified in base for a length of pages pages void mm_pfreen(u32_t base, u32_t pages) { //convert pages to max address for (pages = base + (pages << 12); base < pages; base += 4096) mm_pfree(base); } // This function frees a single page void mm_pfree(u32_t base) { // u32_t pageNumber = base >> 12; // >>12 == /4096 u32_t byteNumber = base >> 15; //pageNumber >> 3; //pageNumber/8 u32_t bitNumber = (base >> 12) & 0x07; //pageNumber % 8; page_bitmap[byteNumber] = page_bitmap[byteNumber] & ((0x01 << bitNumber) ^ 0xFF); mm_freepages++; if (byteNumber < mm_first_free_byte) mm_first_free_byte = byteNumber; } // This function reserves a certain number of pages starting at the address // specified in base for a length of pages pages void mm_preserven(u32_t base, u32_t pages) { //convert pages to max address for (pages = base + (pages << 12); base < pages; base += 4096) mm_preserve(base); } // This function reserves a single page void mm_preserve(u32_t base) { // u32_t pageNumber = base >> 12; // >>12 == /4096 u32_t byteNumber = base >> 15; //pageNumber >> 3; //pageNumber/8 u32_t bitNumber = (base >> 12) & 0x07; //pageNumber % 8; page_bitmap[byteNumber] = page_bitmap[byteNumber] | (0x01 << bitNumber); mm_freepages--; } // This function allocates a single page, returning its physical address u32_t mm_palloc() { u32_t bite; for (bite = mm_first_free_byte; bite < MM_BITMAP_SIZE; bite++) { if (page_bitmap[bite] != 0xFF) //there is an available page within this 8-page region { int bit; for (bit = 0; bit < 8; bit++) { if (!(page_bitmap[bite] & (1 << bit))) //this bite/bit combination is available { mm_first_free_byte = bite; //start searching from here next time mm_freepages--; page_bitmap[bite] = page_bitmap[bite] | (1 << bit); //set page as used return ((bite << 15) | (bit << 12)); } } } } return 0; //no free page } // This function reports the number of bytes of free physical memory u32_t mm_getFreeMem() { return mm_freepages << 12; } u32_t mm_getFreePages() { return mm_freepages; } u32_t mm_getTotalMem() { return mm_totalmem; } u32_t mm_getTotalMegs() { return mm_megabytes; }