*/
#define DEBUG 0
#include <acess.h>
-#include <mboot.h>
#include <mm_virt.h>
+#include <pmemmap.h>
+#include <hal_proc.h>
//#define USE_STACK 1
#define TRACE_ALLOCS 0 // Print trace messages on AllocPhys/DerefPhys
+static const int addrClasses[] = {0,16,20,24,32,64};
+static const int numAddrClasses = sizeof(addrClasses)/sizeof(addrClasses[0]);
// === IMPORTS ===
-extern char gKernelEnd[];
extern void Proc_PrintBacktrace(void);
// === PROTOTYPES ===
-void MM_Install(tMBoot_Info *MBoot);
+void MM_Install(int NPMemRanges, tPMemMapEnt *PMemRanges);
//tPAddr MM_AllocPhys(void);
//tPAddr MM_AllocPhysRange(int Pages, int MaxBits);
//void MM_RefPhys(tPAddr PAddr);
Uint64 giPhysAlloc = 0; // Number of allocated pages
Uint64 giPageCount = 0; // Total number of pages
Uint64 giLastPossibleFree = 0; // Last possible free page (before all pages are used)
+Uint64 giTotalMemorySize = 0; // Total number of allocatable pages
Uint32 gaSuperBitmap[1024]; // Blocks of 1024 Pages
Uint32 gaPageBitmap[1024*1024/32]; // Individual pages
#define REFENT_PER_PAGE (0x1000/sizeof(gaPageReferences[0]))
// === CODE ===
-void MM_Install(tMBoot_Info *MBoot)
+void MM_Install(int NPMemRanges, tPMemMapEnt *PMemRanges)
{
- Uint kernelPages, num;
Uint i;
Uint64 maxAddr = 0;
- tMBoot_Module *mods;
- tMBoot_MMapEnt *ent;
// --- Find largest address
- MBoot->MMapAddr |= KERNEL_BASE;
- ent = (void *)( MBoot->MMapAddr );
- while( (Uint)ent < MBoot->MMapAddr + MBoot->MMapLength )
+ for( i = 0; i < NPMemRanges; i ++ )
{
- // Adjust for size
- ent->Size += 4;
-
+ tPMemMapEnt *ent = &PMemRanges[i];
// If entry is RAM and is above `maxAddr`, change `maxAddr`
- if(ent->Type == 1 && ent->Base + ent->Length > maxAddr)
- maxAddr = ent->Base + ent->Length;
- // Go to next entry
- ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size );
+ if(ent->Type == PMEMTYPE_FREE || ent->Type == PMEMTYPE_USED)
+ {
+ if(ent->Start + ent->Length > maxAddr)
+ maxAddr = ent->Start + ent->Length;
+ giTotalMemorySize += ent->Length >> 12;
+ }
}
- if(maxAddr == 0) {
- giPageCount = (MBoot->HighMem >> 2) + 256; // HighMem is a kByte value
- }
- else {
- giPageCount = maxAddr >> 12;
- }
+ giPageCount = maxAddr >> 12;
giLastPossibleFree = giPageCount - 1;
memsetd(gaPageBitmap, 0xFFFFFFFF, giPageCount/32);
// Set up allocateable space
- ent = (void *)( MBoot->MMapAddr );
- while( (Uint)ent < MBoot->MMapAddr + MBoot->MMapLength )
- {
- memsetd( &gaPageBitmap[ent->Base/(4096*32)], 0, ent->Length/(4096*32) );
- ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size );
+ for( i = 0; i < NPMemRanges; i ++ )
+ {
+ tPMemMapEnt *ent = &PMemRanges[i];
+ if( ent->Type == PMEMTYPE_FREE )
+ {
+ Uint64 startpg = ent->Start / PAGE_SIZE;
+ Uint64 pgcount = ent->Length / PAGE_SIZE;
+ while( startpg % 32 && pgcount ) {
+ gaPageBitmap[startpg/32] &= ~(1U << (startpg%32));
+ startpg ++;
+ pgcount --;
+ }
+ memsetd( &gaPageBitmap[startpg/32], 0, pgcount/32 );
+ startpg += pgcount - pgcount%32;
+ pgcount -= pgcount - pgcount%32;
+ while(pgcount) {
+ gaPageBitmap[startpg/32] &= ~(1U << (startpg%32));
+ startpg ++;
+ pgcount --;
+ }
+ }
+ else if( ent->Type == PMEMTYPE_USED )
+ {
+ giPhysAlloc += ent->Length / PAGE_SIZE;
+ }
}
-
- // Get used page count (Kernel)
- kernelPages = (Uint)&gKernelEnd - KERNEL_BASE - 0x100000;
- kernelPages += 0xFFF; // Page Align
- kernelPages >>= 12;
- giPhysAlloc += kernelPages; // Add to used count
- // Fill page bitmap
- num = kernelPages/32;
- memsetd( &gaPageBitmap[0x100000/(4096*32)], -1, num );
- gaPageBitmap[ 0x100000/(4096*32) + num ] = (1 << (kernelPages & 31)) - 1;
-
// Fill Superpage bitmap
- num = kernelPages/(32*32);
- memsetd( &gaSuperBitmap[0x100000/(4096*32*32)], -1, num );
- gaSuperBitmap[ 0x100000/(4096*32*32) + num ] = (1 << ((kernelPages / 32) & 31)) - 1;
-
- // Mark Multiboot's pages as taken
- // - Structure
- MM_RefPhys( (Uint)MBoot - KERNEL_BASE );
- // - Module List
- for(i = (MBoot->ModuleCount*sizeof(tMBoot_Module)+0xFFF)>12; i--; )
- MM_RefPhys( MBoot->Modules + (i << 12) );
- // - Modules
- mods = (void*)(MBoot->Modules + KERNEL_BASE);
- for(i = 0; i < MBoot->ModuleCount; i++)
+ // - A set bit means that there are no free pages in this block of 32
+ for( i = 0; i < (giPageCount+31)/32; i ++ )
{
- num = (mods[i].End - mods[i].Start + 0xFFF) >> 12;
- while(num--)
- MM_RefPhys( (mods[i].Start & ~0xFFF) + (num<<12) );
+ if( gaPageBitmap[i] + 1 == 0 ) {
+ gaSuperBitmap[i/32] |= (1 << i%32);
+ }
}
-
+
gaPageReferences = (void*)MM_REFCOUNT_BASE;
Log_Log("PMem", "Physical memory set up (%lli pages of ~%lli MiB used)",
- giPhysAlloc, (giPageCount*4)/1024
+ giPhysAlloc, (giTotalMemorySize*PAGE_SIZE)/(1024*1024)
);
}
+void MM_DumpStatistics(void)
+{
+ int i, pg;
+ for( i = 1; i < numAddrClasses; i ++ )
+ {
+ int first = (i == 1 ? 0 : (1UL << (addrClasses[i-1] - 12)));
+ int last = (1UL << (addrClasses[i] - 12)) - 1;
+ int nFree = 0;
+ int nMultiRef = 0;
+ int totalRefs = 0;
+
+ if( last > giPageCount )
+ last = giPageCount;
+
+ int total = last - first + 1;
+
+ for( pg = first; pg < last; pg ++ )
+ {
+ if( !MM_GetPhysAddr(&gaPageReferences[pg]) || gaPageReferences[pg] == 0 ) {
+ nFree ++;
+ continue ;
+ }
+ totalRefs += gaPageReferences[pg];
+ if(gaPageReferences[pg] > 1)
+ nMultiRef ++;
+ }
+
+ int nUsed = (total - nFree);
+ Log_Log("MMPhys", "%ipbit - %i/%i used, %i reused, %i average reference count",
+ addrClasses[i], nUsed, total, nMultiRef,
+ nMultiRef ? (totalRefs-(nUsed - nMultiRef)) / nMultiRef : 0
+ );
+
+ if( last == giPageCount )
+ break;
+ }
+ Log_Log("MMPhys", "%lli/%lli total pages used, 0 - %i possible free range",
+ giPhysAlloc, giTotalMemorySize, giLastPossibleFree);
+}
+
/**
* \fn tPAddr MM_AllocPhys(void)
* \brief Allocates a physical page from the general pool
// Classful scan
#if 1
{
- const int addrClasses[] = {0,16,20,24,32,64};
- const int numAddrClasses = sizeof(addrClasses)/sizeof(addrClasses[0]);
int i;
int first, last;
for( i = numAddrClasses; i -- > 1; )
}
// Mark page used
- if( MM_GetPhysAddr( (tVAddr)&gaPageReferences[indx] ) )
+ if( MM_GetPhysAddr( &gaPageReferences[indx] ) )
gaPageReferences[indx] = 1;
gaPageBitmap[ indx>>5 ] |= 1 << (indx&31);
*/
tPAddr MM_AllocPhysRange(int Pages, int MaxBits)
{
- int a, b;
int i, idx, sidx;
tPAddr ret;
}
idx = sidx / 32;
sidx %= 32;
- b = idx % 32;
- a = idx / 32;
#if 0
LOG("a=%i, b=%i, idx=%i, sidx=%i", a, b, idx, sidx);
// Mark pages used
for( i = 0; i < Pages; i++ )
{
- if( MM_GetPhysAddr( (tVAddr)&gaPageReferences[idx*32+sidx] ) )
+ if( MM_GetPhysAddr( &gaPageReferences[idx*32+sidx] ) )
gaPageReferences[idx*32+sidx] = 1;
gaPageBitmap[ idx ] |= 1 << sidx;
sidx ++;
// Reference the page
if( gaPageReferences )
{
- if( MM_GetPhysAddr( (tVAddr)&gaPageReferences[PAddr] ) == 0 )
+ if( MM_GetPhysAddr( &gaPageReferences[PAddr] ) == 0 )
{
int i, base;
tVAddr addr = ((tVAddr)&gaPageReferences[PAddr]) & ~0xFFF;
giLastPossibleFree = PAddr;
// Dereference
- if( !MM_GetPhysAddr( (tVAddr)&gaPageReferences[PAddr] ) || (-- gaPageReferences[PAddr]) == 0 )
+ if( !MM_GetPhysAddr( &gaPageReferences[PAddr] ) || (-- gaPageReferences[PAddr]) == 0 )
{
#if TRACE_ALLOCS
Log_Debug("PMem", "MM_DerefPhys: Free'd %P (%i free)", PAddr<<12, giPageCount-giPhysAlloc);
if(gaPageBitmap[ PAddr / 32 ] == 0)
gaSuperBitmap[ PAddr >> 10 ] &= ~(1 << ((PAddr >> 5)&31));
- if( MM_GetPhysAddr( (tVAddr) &gaPageNodes[PAddr] ) )
+ if( MM_GetPhysAddr( &gaPageNodes[PAddr] ) )
{
gaPageNodes[PAddr] = NULL;
// TODO: Free Node Page when fully unused
// We don't care about non-ram pages
if(PAddr >= giPageCount) return -1;
- if( MM_GetPhysAddr( (tVAddr)&gaPageReferences[PAddr] ) == 0 )
+ if( MM_GetPhysAddr( &gaPageReferences[PAddr] ) == 0 )
return (gaPageBitmap[PAddr / 32] & (1 << PAddr%32)) ? 1 : 0;
// Check if it is freed
block_addr = (tVAddr) &gaPageNodes[PAddr];
block_addr &= ~(PAGE_SIZE-1);
- if( !MM_GetPhysAddr( block_addr ) )
+ if( !MM_GetPhysAddr( (void*)block_addr ) )
{
if( !MM_Allocate( block_addr ) ) {
Log_Warning("PMem", "Unable to allocate Node page");
if( MM_GetRefCount(PAddr) == 0 ) return 1;
PAddr /= PAGE_SIZE;
- if( !MM_GetPhysAddr( (tVAddr) &gaPageNodes[PAddr] ) ) {
+ if( !MM_GetPhysAddr( &gaPageNodes[PAddr] ) ) {
*Node = NULL;
return 0;
}