#include <mm_virt.h>
#include <pmemmap.h>
#include <hal_proc.h>
+#include <semaphore.h>
+#include <debug_hooks.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 void Proc_PrintBacktrace(void);
-
// === PROTOTYPES ===
void MM_Install(int NPMemRanges, tPMemMapEnt *PMemRanges);
//tPAddr MM_AllocPhys(void);
// === CODE ===
void MM_Install(int NPMemRanges, tPMemMapEnt *PMemRanges)
{
- Uint i;
Uint64 maxAddr = 0;
// --- Find largest address
- for( i = 0; i < NPMemRanges; i ++ )
+ for( Uint i = 0; i < NPMemRanges; i ++ )
{
tPMemMapEnt *ent = &PMemRanges[i];
// If entry is RAM and is above `maxAddr`, change `maxAddr`
giTotalMemorySize += ent->Length >> 12;
}
}
+ LOG("giTotalMemorySize = %lli KiB", giTotalMemorySize*4);
+ LOG("maxAddr = 0x%X", maxAddr);
+
+ // Clip to 32-bits
+ if( maxAddr > (1ULL << 32) ) {
+ maxAddr = (1ULL << 32);
+ }
giPageCount = maxAddr >> 12;
giLastPossibleFree = giPageCount - 1;
-
memsetd(gaPageBitmap, 0xFFFFFFFF, giPageCount/32);
// Set up allocateable space
- for( i = 0; i < NPMemRanges; i ++ )
+ for( Uint 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;
+ // Ignore start addresses >32 bits
+ if( startpg > (1 << 20) )
+ continue ;
+ // Clip lengths to 32-bit address space
+ if( startpg + pgcount > (1<<20) )
+ pgcount = (1<<20) - startpg;
+
while( startpg % 32 && pgcount ) {
gaPageBitmap[startpg/32] &= ~(1U << (startpg%32));
startpg ++;
}
else if( ent->Type == PMEMTYPE_USED )
{
+ // TODO: Clip?
giPhysAlloc += ent->Length / PAGE_SIZE;
}
}
// Fill Superpage bitmap
// - A set bit means that there are no free pages in this block of 32
- for( i = 0; i < (giPageCount+31)/32; i ++ )
+ for( Uint i = 0; i < (giPageCount+31)/32; i ++ )
{
if( gaPageBitmap[i] + 1 == 0 ) {
gaSuperBitmap[i/32] |= (1 << i%32);
gaPageReferences = (void*)MM_REFCOUNT_BASE;
+ Log_Debug("PMem", "maxAddr = %P", maxAddr);
Log_Log("PMem", "Physical memory set up (%lli pages of ~%lli MiB used)",
giPhysAlloc, (giTotalMemorySize*PAGE_SIZE)/(1024*1024)
);
void MM_DumpStatistics(void)
{
- int i, pg;
- for( i = 1; i < numAddrClasses; i ++ )
+ for( int i = 1; i < numAddrClasses; i ++ )
{
- int first = (i == 1 ? 0 : (1UL << (addrClasses[i-1] - 12)));
- int last = (1UL << (addrClasses[i] - 12)) - 1;
+ const int first = (i == 1 ? 0 : (1UL << (addrClasses[i-1] - 12)));
+ const int last = MIN( (1UL << (addrClasses[i] - 12)) - 1, giPageCount );
+ const int total = last - first + 1;
+
int nFree = 0;
int nMultiRef = 0;
int totalRefs = 0;
-
- if( last > giPageCount )
- last = giPageCount;
+ bool refpage_valid = !!MM_GetPhysAddr(&gaPageReferences[first]);
- int total = last - first + 1;
-
- for( pg = first; pg < last; pg ++ )
+ for( Uint pg = first; pg < last; pg ++ )
{
- if( !MM_GetPhysAddr(&gaPageReferences[pg]) || gaPageReferences[pg] == 0 ) {
+ // Free chunk
+ if( gaPageBitmap[pg/32] == 0 )
+ {
+ int count = 32 - pg%32;
+ nFree += count;
+ pg += count - 1;
+ continue ;
+ }
+
+ // Single free
+ if( !(gaPageBitmap[pg/32] & (1 << pg%32)) )
+ {
nFree ++;
continue ;
}
- totalRefs += gaPageReferences[pg];
- if(gaPageReferences[pg] > 1)
+
+ // Check if reference page is valid
+ if( pg % (PAGE_SIZE/sizeof(gaPageReferences[0])) == 0 ) {
+ refpage_valid = !!MM_GetPhysAddr(&gaPageReferences[pg]);
+ }
+
+ //
+ if( refpage_valid && gaPageReferences[pg] > 1 ) {
+ totalRefs += gaPageReferences[pg];
nMultiRef ++;
+ }
+ else
+ totalRefs ++;
}
int nUsed = (total - nFree);
addrClasses[i], nUsed, total, nMultiRef,
nMultiRef ? (totalRefs-(nUsed - nMultiRef)) / nMultiRef : 0
);
+ // TODO: Calculate fragentation of physical memory.
+ // > Somehow support defragmenting?
if( last == giPageCount )
break;
}
Log_Log("MMPhys", "%lli/%lli total pages used, 0 - %i possible free range",
giPhysAlloc, giTotalMemorySize, giLastPossibleFree);
+
+ int startpage = 0;
+ int last_refcnt = 0;
+ void *last_node = NULL;
+ for( int pg = 0; pg < giPageCount; pg ++ )
+ {
+ bool output = 0;
+ int refcount = 0;
+ void *node = NULL;
+ if( !(gaPageBitmap[pg/32] & (1 << pg%32)) )
+ {
+ // free
+ output = 1;
+ }
+ else
+ {
+ refcount = MM_GetPhysAddr(&gaPageReferences[pg]) ? gaPageReferences[pg] : 1;
+ node = MM_GetPhysAddr(&gaPageNodes[pg]) ? gaPageNodes[pg] : NULL;
+
+ if( last_refcnt != refcount || last_node != node )
+ output = 1;
+ }
+ if( output || pg == giPageCount-1 )
+ {
+ if( last_refcnt > 0 )
+ Debug("0x%4x+%i: node=%p refcount=%i", pg-startpage, last_node, last_refcnt);
+ startpage = pg;
+ }
+ last_refcnt = refcount;
+ last_node = node;
+ }
}
/**
*/
tPAddr MM_AllocPhys(void)
{
- // int a, b, c;
int indx = -1;
tPAddr ret;
Mutex_Acquire( &glPhysAlloc );
// Classful scan
- #if 1
{
int i;
int first, last;
// Out of memory?
if( i <= 1 ) indx = -1;
}
- #elif 0
- // Find free page
- // Scan downwards
- LOG("giLastPossibleFree = %i", giLastPossibleFree);
- for( indx = giLastPossibleFree; indx >= 0; )
- {
- if( gaSuperBitmap[indx>>10] == -1 ) {
- indx -= 1024;
- continue;
- }
-
- if( gaPageBitmap[indx>>5] == -1 ) {
- indx -= 32;
- continue;
- }
-
- if( gaPageBitmap[indx>>5] & (1 << (indx&31)) ) {
- indx --;
- continue;
- }
- break;
- }
- if( indx >= 0 )
- giLastPossibleFree = indx;
- LOG("indx = %i", indx);
- #else
- c = giLastPossibleFree % 32;
- b = (giLastPossibleFree / 32) % 32;
- a = giLastPossibleFree / 1024;
-
- LOG("a=%i,b=%i,c=%i", a, b, c);
- for( ; gaSuperBitmap[a] == -1 && a >= 0; a-- );
- if(a < 0) {
- Mutex_Release( &glPhysAlloc );
- Warning("MM_AllocPhys - OUT OF MEMORY (Called by %p) - %lli/%lli used",
- __builtin_return_address(0), giPhysAlloc, giPageCount);
- LEAVE('i', 0);
- return 0;
- }
- for( ; gaSuperBitmap[a] & (1<<b); b-- );
- for( ; gaPageBitmap[a*32+b] & (1<<c); c-- );
- LOG("a=%i,b=%i,c=%i", a, b, c);
- indx = (a << 10) | (b << 5) | c;
- if( indx >= 0 )
- giLastPossibleFree = indx;
- #endif
if( indx < 0 ) {
Mutex_Release( &glPhysAlloc );
}
// Mark page used
- if( MM_GetPhysAddr( (tVAddr)&gaPageReferences[indx] ) )
+ if( MM_GetPhysAddr( &gaPageReferences[indx] ) )
gaPageReferences[indx] = 1;
gaPageBitmap[ indx>>5 ] |= 1 << (indx&31);
// Release Spinlock
Mutex_Release( &glPhysAlloc );
-
- LEAVE('X', ret);
+ LEAVE('P', ret);
+
#if TRACE_ALLOCS
if( now() > 4000 ) {
Log_Debug("PMem", "MM_AllocPhys: RETURN %P (%i free)", ret, giPageCount-giPhysAlloc);
*/
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);
-
- // Find free page
- for( ; gaSuperBitmap[a] == -1 && a --; ) b = 31;
- if(a < 0) {
- Mutex_Release( &glPhysAlloc );
- Warning("MM_AllocPhysRange - OUT OF MEMORY (Called by %p)", __builtin_return_address(0));
- LEAVE('i', 0);
- return 0;
- }
- LOG("a = %i", a);
- for( ; gaSuperBitmap[a] & (1 << b); b-- ) sidx = 31;
- LOG("b = %i", b);
- idx = a * 32 + b;
- for( ; gaPageBitmap[idx] & (1 << sidx); sidx-- )
- LOG("gaPageBitmap[%i] = 0x%08x", idx, gaPageBitmap[idx]);
-
- LOG("idx = %i, sidx = %i", idx, sidx);
- #else
-
- #endif
// Check if the gap is large enough
while( idx >= 0 )
// 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 ++;
// Get page number
PAddr >>= 12;
+ //if( PAddr == 0x15FA000/PAGE_SIZE ) Debug("%p refed %P", __builtin_return_address(0), PAddr*PAGE_SIZE);
+
// We don't care about non-ram pages
if(PAddr >= giPageCount) return;
// 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;
-// Log_Debug("PMem", "MM_RefPhys: Allocating info for %X", PAddr);
+ Uint base = PAddr & ~(1024-1);
Mutex_Release( &glPhysAlloc );
- if( MM_Allocate( addr ) == 0 ) {
+ // No infinite recursion, AllocPhys doesn't need the reference array
+ // TODO: Race condition? (racy on populating)
+ if( MM_Allocate( &gaPageReferences[base] ) == 0 )
+ {
Log_KernelPanic("PMem",
"MM_RefPhys: Out of physical memory allocating info for %X",
PAddr*PAGE_SIZE
);
+ for(;;);
}
Mutex_Acquire( &glPhysAlloc );
+ // TODO: Solve race condition. (see below)
+ // [1] See unallocated
+ // Release lock
+ // [2] Acquire lock
+ // See unallocated
+ // Release lock
+ // Allocate
+ // [1] Allocate
+ // Acquire lock
+ // Populate
+ // Release lock
+ // [2] Acquire lock
+ // Populate (clobbering)
- base = PAddr & ~(1024-1);
- for( i = 0; i < 1024; i ++ ) {
+ // Fill references from allocated bitmap
+ for( int i = 0; i < 1024; i ++ )
+ {
gaPageReferences[base + i] = (gaPageBitmap[(base+i)/32] & (1 << (base+i)%32)) ? 1 : 0;
}
}
// Get page number
PAddr >>= 12;
+ //if( PAddr == 0x196000/PAGE_SIZE ) Debug("%p derefed %P", __builtin_return_address(0), PAddr*PAGE_SIZE);
+
// We don't care about non-ram pages
if(PAddr >= giPageCount) return;
// Check if it is freed
if( !(gaPageBitmap[PAddr / 32] & (1 << PAddr%32)) ) {
- Log_Warning("MMVirt", "MM_DerefPhys - Non-referenced memory dereferenced");
+ Log_Warning("MMVirt", "MM_DerefPhys - Non-referenced memory (%P) dereferenced",
+ PAddr * PAGE_SIZE);
+ Proc_PrintBacktrace();
return;
}
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
{
// Get page number
PAddr >>= 12;
-
+
// 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
int MM_SetPageNode(tPAddr PAddr, void *Node)
{
- tVAddr block_addr;
-
if( MM_GetRefCount(PAddr) == 0 ) return 1;
PAddr /= PAGE_SIZE;
- block_addr = (tVAddr) &gaPageNodes[PAddr];
- block_addr &= ~(PAGE_SIZE-1);
+ void *page_ptr = (void*)( (tVAddr)&gaPageNodes[PAddr] & ~(PAGE_SIZE-1) );
- if( !MM_GetPhysAddr( block_addr ) )
+ if( !MM_GetPhysAddr( page_ptr ) )
{
- if( !MM_Allocate( block_addr ) ) {
+ if( !MM_Allocate( page_ptr ) ) {
Log_Warning("PMem", "Unable to allocate Node page");
return -1;
}
- memset( (void*)block_addr, 0, PAGE_SIZE );
+ memset( page_ptr, 0, PAGE_SIZE );
}
gaPageNodes[PAddr] = Node;
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;
}