#include <mboot.h>
#include <mm_virt.h>
-#define USE_STACK 1
+//#define USE_STACK 1
+#define TRACE_ALLOCS 0 // Print trace messages on AllocPhys/DerefPhys
-#define REFERENCE_BASE 0xE0400000
// === IMPORTS ===
extern void gKernelEnd;
+extern void Proc_PrintBacktrace(void);
// === PROTOTYPES ===
-tPAddr MM_AllocPhys();
-tPAddr MM_AllocPhysRange(int Pages, int MaxBits);
-void MM_RefPhys(tPAddr Addr);
-void MM_DerefPhys(tPAddr Addr);
+void MM_Install(tMBoot_Info *MBoot);
+//tPAddr MM_AllocPhys(void);
+//tPAddr MM_AllocPhysRange(int Pages, int MaxBits);
+//void MM_RefPhys(tPAddr PAddr);
+//void MM_DerefPhys(tPAddr PAddr);
+// int MM_GetRefCount(tPAddr PAddr);
// === GLOBALS ===
+tMutex glPhysAlloc;
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)
Uint32 gaSuperBitmap[1024]; // Blocks of 1024 Pages
Uint32 gaPageBitmap[1024*1024/32]; // Individual pages
-Uint32 *gaPageReferences;
+ int *gaPageReferences;
+void **gaPageNodes = (void*)MM_PAGENODE_BASE;
+#define REFENT_PER_PAGE (0x1000/sizeof(gaPageReferences[0]))
// === CODE ===
void MM_Install(tMBoot_Info *MBoot)
ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size );
}
- // Get used page count
+ // Get used page count (Kernel)
kernelPages = (Uint)&gKernelEnd - KERNEL_BASE - 0x100000;
kernelPages += 0xFFF; // Page Align
kernelPages >>= 12;
while(num--)
MM_RefPhys( (mods[i].Start & ~0xFFF) + (num<<12) );
}
-
- // Allocate References
- //LOG("Reference Pages %i", (giPageCount*4+0xFFF)>>12);
- for(num = 0; num < (giPageCount*4+0xFFF)>>12; num++)
- {
- MM_Allocate( REFERENCE_BASE + (num<<12) );
- }
-
- //LOG("Filling");
- // Fill references
- gaPageReferences = (void*)REFERENCE_BASE;
- memsetd(gaPageReferences, 1, kernelPages);
- for( num = kernelPages; num < giPageCount; num++ )
- {
- gaPageReferences[num] = (gaPageBitmap[ num / 32 ] >> (num&31)) & 1;
- }
+
+ gaPageReferences = (void*)MM_REFCOUNT_BASE;
+
+ Log_Log("PMem", "Physical memory set up");
}
/**
- * \fn tPAddr MM_AllocPhys()
+ * \fn tPAddr MM_AllocPhys(void)
* \brief Allocates a physical page from the general pool
*/
-tPAddr MM_AllocPhys()
+tPAddr MM_AllocPhys(void)
{
// int a, b, c;
- int indx;
+ int indx = -1;
tPAddr ret;
ENTER("");
- LOCK( &giPhysAlloc );
+ Mutex_Acquire( &glPhysAlloc );
+ // 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; )
+ {
+ first = 1 << (addrClasses[i-1] - 12);
+ last = (1 << (addrClasses[i] - 12)) - 1;
+ // Range is above the last free page
+ if( first > giLastPossibleFree )
+ continue;
+ // Last possible free page is in the range
+ if( last > giLastPossibleFree )
+ last = giLastPossibleFree;
+
+ // Scan the range
+ for( indx = first; indx < last; )
+ {
+ 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 < last ) break;
+
+ giLastPossibleFree = first; // Well, we couldn't find any in this range
+ }
+ // Out of memory?
+ if( i <= 1 ) indx = -1;
+ }
+ #elif 0
// Find free page
// Scan downwards
- #if 1
LOG("giLastPossibleFree = %i", giLastPossibleFree);
for( indx = giLastPossibleFree; indx >= 0; )
{
indx -= 1024;
continue;
}
+
if( gaPageBitmap[indx>>5] == -1 ) {
indx -= 32;
continue;
}
break;
}
+ if( indx >= 0 )
+ giLastPossibleFree = indx;
LOG("indx = %i", indx);
#else
c = giLastPossibleFree % 32;
LOG("a=%i,b=%i,c=%i", a, b, c);
for( ; gaSuperBitmap[a] == -1 && a >= 0; a-- );
if(a < 0) {
- RELEASE( &giPhysAlloc );
- Warning("MM_AllocPhys - OUT OF MEMORY (Called by %p)", __builtin_return_address(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( ; 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 );
+ Warning("MM_AllocPhys - OUT OF MEMORY (Called by %p) - %lli/%lli used (indx = %x)",
+ __builtin_return_address(0), giPhysAlloc, giPageCount, indx);
+ Log_Debug("PMem", "giLastPossibleFree = %lli", giLastPossibleFree);
+ LEAVE('i', 0);
+ return 0;
+ }
+
+ if( indx > 0xFFFFF ) {
+ Panic("The fuck? Too many pages! (indx = 0x%x)", indx);
+ }
+
+ if( indx >= giPageCount ) {
+ Mutex_Release( &glPhysAlloc );
+ Log_Error("PMem", "MM_AllocPhys - indx(%i) > giPageCount(%i)", indx, giPageCount);
+ LEAVE('i', 0);
+ return 0;
+ }
+
// Mark page used
- if(gaPageReferences)
- gaPageReferences[ indx ] = 1;
+ if( MM_GetPhysAddr( (tVAddr)&gaPageReferences[indx] ) )
+ gaPageReferences[indx] = 1;
gaPageBitmap[ indx>>5 ] |= 1 << (indx&31);
+ giPhysAlloc ++;
// Get address
ret = indx << 12;
- giLastPossibleFree = indx;
// Mark used block
- if(gaPageBitmap[ indx>>5 ] == -1)
+ if(gaPageBitmap[ indx>>5 ] == -1) {
gaSuperBitmap[indx>>10] |= 1 << ((indx>>5)&31);
+ }
// Release Spinlock
- RELEASE( &giPhysAlloc );
+ Mutex_Release( &glPhysAlloc );
LEAVE('X', ret);
- //Log("MM_AllocPhys: RETURN 0x%x", ret);
+ #if TRACE_ALLOCS
+ if( now() > 4000 ) {
+ Log_Debug("PMem", "MM_AllocPhys: RETURN %P (%i free)", ret, giPageCount-giPhysAlloc);
+ Proc_PrintBacktrace();
+ }
+ #endif
return ret;
}
int i, idx, sidx;
tPAddr ret;
+ ENTER("iPages iMaxBits", Pages, MaxBits);
+
// Sanity Checks
- if(MaxBits < 0) return 0;
+ if(MaxBits < 0) {
+ LEAVE('i', 0);
+ return 0;
+ }
if(MaxBits > PHYS_BITS) MaxBits = PHYS_BITS;
// Lock
- LOCK( &giPhysAlloc );
+ Mutex_Acquire( &glPhysAlloc );
// Set up search state
if( giLastPossibleFree > ((tPAddr)1 << (MaxBits-12)) ) {
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 --; );
+ for( ; gaSuperBitmap[a] == -1 && a --; ) b = 31;
if(a < 0) {
- RELEASE( &giPhysAlloc );
+ Mutex_Release( &glPhysAlloc );
Warning("MM_AllocPhysRange - OUT OF MEMORY (Called by %p)", __builtin_return_address(0));
+ LEAVE('i', 0);
return 0;
}
- for( ; gaSuperBitmap[a] & (1 << b); b-- );
+ 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-- );
+ 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 )
// Check if an address was found
if( idx < 0 ) {
- RELEASE( &giPhysAlloc );
+ Mutex_Release( &glPhysAlloc );
Warning("MM_AllocPhysRange - OUT OF MEMORY (Called by %p)", __builtin_return_address(0));
+ LEAVE('i', 0);
+ return 0;
}
// Mark pages used
for( i = 0; i < Pages; i++ )
{
- if(gaPageReferences)
+ if( MM_GetPhysAddr( (tVAddr)&gaPageReferences[idx*32+sidx] ) )
gaPageReferences[idx*32+sidx] = 1;
gaPageBitmap[ idx ] |= 1 << sidx;
sidx ++;
- if(sidx == 32) { sidx = 0; idx ++; }
+ giPhysAlloc ++;
+ if(sidx == 32) { sidx = 0; idx ++; }
}
// Get address
if(gaPageBitmap[ idx ] == -1) gaSuperBitmap[idx/32] |= 1 << (idx%32);
// Release Spinlock
- RELEASE( &giPhysAlloc );
+ Mutex_Release( &glPhysAlloc );
+ LEAVE('X', ret);
+ #if TRACE_ALLOCS
+ Log_Debug("PMem", "MM_AllocPhysRange: RETURN 0x%llx-0x%llx (%i free)",
+ ret, ret + (1<<Pages)-1, giPageCount-giPhysAlloc);
+ #endif
return ret;
}
/**
- * \fn void MM_RefPhys(tPAddr Addr)
+ * \fn void MM_RefPhys(tPAddr PAddr)
*/
-void MM_RefPhys(tPAddr Addr)
+void MM_RefPhys(tPAddr PAddr)
{
// Get page number
- Addr >>= 12;
-
+ PAddr >>= 12;
+
// We don't care about non-ram pages
- if(Addr >= giPageCount) return;
+ if(PAddr >= giPageCount) return;
// Lock Structures
- LOCK( &giPhysAlloc );
+ Mutex_Acquire( &glPhysAlloc );
// Reference the page
- if(gaPageReferences)
- gaPageReferences[ Addr ] ++;
+ if( gaPageReferences )
+ {
+ if( MM_GetPhysAddr( (tVAddr)&gaPageReferences[PAddr] ) == 0 )
+ {
+ int i, base;
+ tVAddr addr = ((tVAddr)&gaPageReferences[PAddr]) & ~0xFFF;
+// Log_Debug("PMem", "MM_RefPhys: Allocating info for %X", PAddr);
+ Mutex_Release( &glPhysAlloc );
+ if( MM_Allocate( addr ) == 0 ) {
+ Log_KernelPanic("PMem", "MM_RefPhys: Out of physical memory allocating info for %X", PAddr*PAGE_SIZE);
+ }
+ Mutex_Acquire( &glPhysAlloc );
+
+ base = PAddr & ~(1024-1);
+ for( i = 0; i < 1024; i ++ ) {
+ gaPageReferences[base + i] = (gaPageBitmap[(base+i)/32] & (1 << (base+i)%32)) ? 1 : 0;
+ }
+ }
+ gaPageReferences[ PAddr ] ++;
+ }
// Mark as used
- gaPageBitmap[ Addr / 32 ] |= 1 << (Addr&31);
+ gaPageBitmap[ PAddr / 32 ] |= 1 << (PAddr&31);
// Mark used block
- if(gaPageBitmap[ Addr / 32 ] == -1) gaSuperBitmap[Addr/1024] |= 1 << ((Addr/32)&31);
+ if(gaPageBitmap[ PAddr / 32 ] == -1)
+ gaSuperBitmap[PAddr/1024] |= 1 << ((PAddr/32)&31);
// Release Spinlock
- RELEASE( &giPhysAlloc );
+ Mutex_Release( &glPhysAlloc );
}
/**
- * \fn void MM_DerefPhys(Uint32 Addr)
+ * \fn void MM_DerefPhys(tPAddr PAddr)
+ * \brief Dereferences a physical page
*/
-void MM_DerefPhys(tPAddr Addr)
+void MM_DerefPhys(tPAddr PAddr)
{
// Get page number
- Addr >>= 12;
-
+ PAddr >>= 12;
+
// We don't care about non-ram pages
- if(Addr >= giPageCount) return;
+ if(PAddr >= giPageCount) return;
// Check if it is freed
- if(gaPageReferences[ Addr ] == 0) {
- Warning("MM_DerefPhys - Non-referenced memory dereferenced");
+ if( !(gaPageBitmap[PAddr / 32] & (1 << PAddr%32)) ) {
+ Log_Warning("MMVirt", "MM_DerefPhys - Non-referenced memory dereferenced");
return;
}
// Lock Structures
- LOCK( &giPhysAlloc );
+ Mutex_Acquire( &glPhysAlloc );
+ if( giLastPossibleFree < PAddr )
+ giLastPossibleFree = PAddr;
+
// Dereference
- gaPageReferences[ Addr ] --;
-
- // Mark as free in bitmaps
- if( gaPageReferences[ Addr ] == 0 )
+ if( !MM_GetPhysAddr( (tVAddr)&gaPageReferences[PAddr] ) || (-- gaPageReferences[PAddr]) == 0 )
{
- //LOG("Freed 0x%x by %p\n", Addr<<12, __builtin_return_address(0));
- gaPageBitmap[ Addr / 32 ] &= ~(1 << (Addr&31));
- if(gaPageReferences[ Addr ] == 0)
- gaSuperBitmap[ Addr >> 10 ] &= ~(1 << ((Addr >> 5)&31));
+ #if TRACE_ALLOCS
+ Log_Debug("PMem", "MM_DerefPhys: Free'd %P (%i free)", PAddr<<12, giPageCount-giPhysAlloc);
+ Proc_PrintBacktrace();
+ #endif
+ //LOG("Freed 0x%x by %p\n", PAddr<<12, __builtin_return_address(0));
+ giPhysAlloc --;
+ gaPageBitmap[ PAddr / 32 ] &= ~(1 << (PAddr&31));
+ if(gaPageBitmap[ PAddr / 32 ] == 0)
+ gaSuperBitmap[ PAddr >> 10 ] &= ~(1 << ((PAddr >> 5)&31));
+
+ if( MM_GetPhysAddr( (tVAddr) &gaPageNodes[PAddr] ) )
+ {
+ gaPageNodes[PAddr] = NULL;
+ // TODO: Free Node Page when fully unused
+ }
}
-
+
// Release spinlock
- RELEASE( &giPhysAlloc );
+ Mutex_Release( &glPhysAlloc );
}
/**
* \fn int MM_GetRefCount(tPAddr Addr)
*/
-int MM_GetRefCount(tPAddr Addr)
+int MM_GetRefCount(tPAddr PAddr)
{
// Get page number
- Addr >>= 12;
+ PAddr >>= 12;
// We don't care about non-ram pages
- if(Addr >= giPageCount) return -1;
+ if(PAddr >= giPageCount) return -1;
+
+ if( MM_GetPhysAddr( (tVAddr)&gaPageReferences[PAddr] ) == 0 )
+ return (gaPageBitmap[PAddr / 32] & (1 << PAddr%32)) ? 1 : 0;
// Check if it is freed
- return gaPageReferences[ Addr ];
+ return gaPageReferences[ PAddr ];
}
+
+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);
+
+ if( !MM_GetPhysAddr( block_addr ) )
+ {
+ if( !MM_Allocate( block_addr ) ) {
+ Log_Warning("PMem", "Unable to allocate Node page");
+ return -1;
+ }
+ memset( (void*)block_addr, 0, PAGE_SIZE );
+ }
+
+ gaPageNodes[PAddr] = Node;
+// Log("gaPageNodes[0x%x] = %p", PAddr, Node);
+ return 0;
+}
+
+int MM_GetPageNode(tPAddr PAddr, void **Node)
+{
+ if( MM_GetRefCount(PAddr) == 0 ) return 1;
+
+ PAddr /= PAGE_SIZE;
+ if( !MM_GetPhysAddr( (tVAddr) &gaPageNodes[PAddr] ) ) {
+ *Node = NULL;
+ return 0;
+ }
+ *Node = gaPageNodes[PAddr];
+ return 0;
+}
+