X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=KernelLand%2FKernel%2Farch%2Fx86%2Fmm_phys.c;h=7a28940fd9466a871fcdded12e508bca5bf65d88;hb=2128ba2e057733b58e21138b003a5b5195a7624c;hp=49d7a1a7635ff115d5eb0e498b5df7eedcf5b2c9;hpb=3878dff5a723481be5e01f24c0e1bbeee4de738c;p=tpg%2Facess2.git diff --git a/KernelLand/Kernel/arch/x86/mm_phys.c b/KernelLand/Kernel/arch/x86/mm_phys.c index 49d7a1a7..7a28940f 100644 --- a/KernelLand/Kernel/arch/x86/mm_phys.c +++ b/KernelLand/Kernel/arch/x86/mm_phys.c @@ -4,8 +4,11 @@ */ #define DEBUG 0 #include -#include #include +#include +#include +#include +#include //#define USE_STACK 1 #define TRACE_ALLOCS 0 // Print trace messages on AllocPhys/DerefPhys @@ -13,12 +16,8 @@ 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); @@ -39,114 +38,130 @@ void **gaPageNodes = (void*)MM_PAGENODE_BASE; #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( Uint 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) + if(ent->Type == PMEMTYPE_FREE || ent->Type == PMEMTYPE_USED) { - if(ent->Base + ent->Length > maxAddr) - maxAddr = ent->Base + ent->Length; + if(ent->Start + ent->Length > maxAddr) + maxAddr = ent->Start + ent->Length; giTotalMemorySize += ent->Length >> 12; } - // Go to next entry - ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size ); } + LOG("giTotalMemorySize = %lli KiB", giTotalMemorySize*4); + LOG("maxAddr = 0x%X", maxAddr); - if(maxAddr == 0) { - giPageCount = (MBoot->HighMem >> 2) + 256; // HighMem is a kByte value + // Clip to 32-bits + if( maxAddr > (1ULL << 32) ) { + maxAddr = (1ULL << 32); } - else { - giPageCount = maxAddr >> 12; - } - giLastPossibleFree = giPageCount - 1; + 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( 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 ++; + 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 ) + { + // TODO: Clip? + 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( Uint 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_Debug("PMem", "maxAddr = %P", maxAddr); Log_Log("PMem", "Physical memory set up (%lli pages of ~%lli MiB used)", - giPhysAlloc, (giTotalMemorySize*4)/1024 + 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); @@ -154,12 +169,45 @@ void MM_DumpStatistics(void) 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; + } } /** @@ -168,7 +216,6 @@ void MM_DumpStatistics(void) */ tPAddr MM_AllocPhys(void) { - // int a, b, c; int indx = -1; tPAddr ret; @@ -177,7 +224,6 @@ tPAddr MM_AllocPhys(void) Mutex_Acquire( &glPhysAlloc ); // Classful scan - #if 1 { int i; int first, last; @@ -218,52 +264,6 @@ tPAddr MM_AllocPhys(void) // 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<= 0 ) - giLastPossibleFree = indx; - #endif if( indx < 0 ) { Mutex_Release( &glPhysAlloc ); @@ -286,7 +286,7 @@ tPAddr MM_AllocPhys(void) } // Mark page used - if( MM_GetPhysAddr( (tVAddr)&gaPageReferences[indx] ) ) + if( MM_GetPhysAddr( &gaPageReferences[indx] ) ) gaPageReferences[indx] = 1; gaPageBitmap[ indx>>5 ] |= 1 << (indx&31); @@ -302,8 +302,8 @@ tPAddr MM_AllocPhys(void) // 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); @@ -321,7 +321,6 @@ tPAddr MM_AllocPhys(void) */ tPAddr MM_AllocPhysRange(int Pages, int MaxBits) { - int a, b; int i, idx, sidx; tPAddr ret; @@ -346,31 +345,6 @@ tPAddr MM_AllocPhysRange(int Pages, int MaxBits) } 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 ) @@ -422,7 +396,7 @@ tPAddr MM_AllocPhysRange(int Pages, int MaxBits) // 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 ++; @@ -455,6 +429,8 @@ void MM_RefPhys(tPAddr PAddr) // 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; @@ -464,22 +440,38 @@ void MM_RefPhys(tPAddr PAddr) // 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; } } @@ -510,12 +502,16 @@ void MM_DerefPhys(tPAddr PAddr) // 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; } @@ -526,7 +522,7 @@ void MM_DerefPhys(tPAddr PAddr) 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); @@ -538,7 +534,7 @@ void MM_DerefPhys(tPAddr PAddr) 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 @@ -556,11 +552,11 @@ int MM_GetRefCount(tPAddr PAddr) { // 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 @@ -569,22 +565,19 @@ int MM_GetRefCount(tPAddr 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); + 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; @@ -597,7 +590,7 @@ int MM_GetPageNode(tPAddr PAddr, void **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; }