hos/kernel/mm/mm.c

159 lines
3.8 KiB
C

// 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)
{
pages = base + (pages << 12); //convert #pages to #bytes
for (; 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)
{
pages = base + (pages << 12); //convert #pages to #bytes
for (; 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;
}