X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Kernel%2Farch%2Fx86_64%2Fmm_phys.c;h=92a38f2a1f627e4a937bebc6638d74911b41ef2e;hb=cb944fc8a944abe6921f7477cf73fc4b23e713a5;hp=c64e1e03acea7dd0139a17039caac2d94324a7d4;hpb=33bcf4b3feb0e5e4548548bf3d2a50c52ffb6115;p=tpg%2Facess2.git diff --git a/Kernel/arch/x86_64/mm_phys.c b/Kernel/arch/x86_64/mm_phys.c index c64e1e03..92a38f2a 100644 --- a/Kernel/arch/x86_64/mm_phys.c +++ b/Kernel/arch/x86_64/mm_phys.c @@ -4,7 +4,8 @@ * Physical Memory Manager */ #include -//#include +#include +#include enum eMMPhys_Ranges { @@ -16,18 +17,166 @@ enum eMMPhys_Ranges NUM_MM_PHYS_RANGES }; +// === IMPORTS === +extern void gKernelEnd; + // === GLOBALS === tSpinlock glPhysicalPages; Uint64 *gaSuperBitmap; // 1 bit = 64 Pages -Uint64 *gaPrimaryBitmap; // 1 bit = 1 Page +Uint32 *gaiPageReferences = (void*)MM_PAGE_COUNTS; // Reference Counts tPAddr giFirstFreePage; // First possibly free page Uint64 giPhysRangeFree[NUM_MM_PHYS_RANGES]; // Number of free pages in each range Uint64 giPhysRangeFirst[NUM_MM_PHYS_RANGES]; // First free page in each range Uint64 giPhysRangeLast[NUM_MM_PHYS_RANGES]; // Last free page in each range +Uint64 giMaxPhysPage = 0; // Maximum Physical page // === CODE === -void MM_InitPhys() +void MM_InitPhys_Multiboot(tMBoot_Info *MBoot) { + tMBoot_MMapEnt *mmapStart; + tMBoot_MMapEnt *ent; + Uint64 maxAddr = 0; + int numPages; + int superPages; + + Log("MM_InitPhys_Multiboot: (MBoot=%p)", MBoot); + + // Scan the physical memory map + // Looking for the top of physical memory + mmapStart = (void *)( KERNEL_BASE | MBoot->MMapAddr ); + Log(" MM_InitPhys_Multiboot: mmapStart = %p", mmapStart); + ent = mmapStart; + while( (Uint)ent < (Uint)mmapStart + MBoot->MMapLength ) + { + // Adjust for the size of the entry + ent->Size += 4; + Log(" MM_InitPhys_Multiboot: ent={Type:%i,Base:0x%x,Length:%x", + ent->Type, ent->Base, ent->Length); + + // 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 ); + } + + // Did we find a valid end? + if(maxAddr == 0) { + // No, darn, let's just use the HighMem hack + giMaxPhysPage = (MBoot->HighMem >> 2) + 256; // HighMem is a kByte value + } + else { + // Goodie, goodie gumdrops + giMaxPhysPage = maxAddr >> 12; + } + Log(" MM_InitPhys_Multiboot: giMaxPhysPage = 0x%x", giMaxPhysPage); + + // Find a contigous section of memory to hold it in + // - Starting from the end of the kernel + // - We also need a region for the super bitmap + superPages = ((giMaxPhysPage+64*8-1)/(64*8) + 0xFFF) >> 12; + numPages = (giMaxPhysPage + 7) * sizeof(*gaiPageReferences); + numPages = (numPages + 0xFFF) >> 12; + Log(" MM_InitPhys_Multiboot: numPages = %i", numPages); + if(maxAddr == 0) + { + // Ok, naieve allocation, just put it after the kernel + tVAddr vaddr = MM_PAGE_COUNTS; + tPAddr paddr = (tPAddr)&gKernelEnd - KERNEL_BASE; + while(numPages --) + { + MM_Map(vaddr, paddr); + vaddr += 0x1000; + paddr += 0x1000; + } + // Allocate the super bitmap + gaSuperBitmap = (void*) MM_MapHWPages( + paddr, + ((giMaxPhysPage+64*8-1)/(64*8) + 0xFFF) >> 12 + ); + } + // Scan for a nice range + else + { + int todo = numPages + superPages; + tPAddr paddr = 0; + tVAddr vaddr = MM_PAGE_COUNTS; + // Scan! + for( + ent = mmapStart; + (Uint)ent < (Uint)mmapStart + MBoot->MMapLength; + ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size ) + ) + { + int avail; + + // RAM only please + if( ent->Type != 1 ) + continue; + + // Let's not put it below the kernel, shall we? + if( ent->Base + ent->Size < (tPAddr)&gKernelEnd ) + continue; + + // Check if the kernel is in this range + if( ent->Base < (tPAddr)&gKernelEnd - KERNEL_BASE && ent->Base + ent->Size > (tPAddr)&gKernelEnd ) + { + avail = (ent->Size-((tPAddr)&gKernelEnd-KERNEL_BASE-ent->Base)) >> 12; + paddr = (tPAddr)&gKernelEnd - KERNEL_BASE; + } + // No? then we can use all of the block + else + { + avail = ent->Size >> 12; + paddr = ent->Base; + } + + // Map + // - Counts + if( todo ) { + int i, max; + max = todo < avail ? todo : avail; + for( i = 0; i < max; i ++ ) + { + MM_Map(vaddr, paddr); + todo --; + vaddr += 0x1000; + paddr += 0x1000; + } + // Alter the destination address when needed + if(todo == superPages) + vaddr = MM_PAGE_SUPBMP; + } + else + break; + } + } + + // Fill the bitmaps + // - initialise to one, then clear the avaliable areas + memset(gaSuperBitmap, -1, (giMaxPhysPage+64*8-1)/(64*8)); + memset(gaiPageReferences, -1, giMaxPhysPage*sizeof(*gaiPageReferences)); + // - Clear all Type=1 areas + for( + ent = mmapStart; + (Uint)ent < (Uint)mmapStart + MBoot->MMapLength; + ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size ) + ) + { + // Check if the type is RAM + if(ent->Type != 1) continue; + // Clear the range + memset( + &gaiPageReferences[ ent->Base >> 12 ], + 0, + (ent->Size>>12)*sizeof(*gaiPageReferences) + ); + } + + // Reference the used pages + // - Kernel + // - Reference Counts and Bitmap } /** @@ -44,6 +193,8 @@ tPAddr MM_AllocPhysRange(int Num, int Bits) int rangeID; int nFree = 0, i; + Log("MM_AllocPhysRange: (Num=%i,Bits=%i)", Num, Bits); + if( Bits <= 0 ) // Speedup for the common case rangeID = MM_PHYS_MAX; else if( Bits > 32 ) @@ -57,17 +208,23 @@ tPAddr MM_AllocPhysRange(int Num, int Bits) else rangeID = MM_PHYS_16BIT; + Log(" MM_AllocPhysRange: rangeID = %i", rangeID); + LOCK(&glPhysicalPages); + Log(" MM_AllocPhysRange: i has lock"); // Check if the range actually has any free pages while(giPhysRangeFree[rangeID] == 0 && rangeID) rangeID --; + Log(" MM_AllocPhysRange: rangeID = %i", rangeID); + // What the? Oh, man. No free pages if(giPhysRangeFree[rangeID] == 0) { RELEASE(&glPhysicalPages); // TODO: Page out // ATM. Just Warning + Warning(" MM_AllocPhysRange: Out of free pages"); Log_Warning("Arch", "Out of memory (unable to fulfil request for %i pages), zero remaining", Num @@ -92,14 +249,14 @@ tPAddr MM_AllocPhysRange(int Num, int Bits) continue; } // Check page block (64 pages) - if( gaPrimaryBitmap[addr >> 6] == -1) { + if( gaSuperBitmap[addr >> (6+6)] & (1 << (addr>>6)&63)) { nFree = 0; addr += 1 << (12+6); addr &= (1 << (12+6)) - 1; continue; } // Check individual page - if( gaPrimaryBitmap[addr >> 6] & (1 << (addr&63)) ) { + if( gaiPageReferences[addr] ) { nFree = 0; addr ++; continue; @@ -120,6 +277,7 @@ tPAddr MM_AllocPhysRange(int Num, int Bits) // until a free range is found) nFree = 1; addr = giPhysRangeLast[ rangeID ]; + // TODO RELEASE(&glPhysicalPages); // TODO: Page out // ATM. Just Warning @@ -129,14 +287,13 @@ tPAddr MM_AllocPhysRange(int Num, int Bits) ); return 0; } + Log(" MM_AllocPhysRange: nFree = %i, addr = 0x%08x", nFree, addr); // Mark pages as allocated addr -= Num; for( i = 0; i < Num; i++ ) { - gaPrimaryBitmap[addr>>6] |= 1 << (addr & 63); - if( gaPrimaryBitmap[addr>>6] == -1 ) - gaSuperBitmap[addr>>12] |= 1 << ((addr >> 6) & 64); + gaiPageReferences[addr] = 1; if(addr >> 32) rangeID = MM_PHYS_MAX; else if(addr >> 24) rangeID = MM_PHYS_32BIT; @@ -145,9 +302,25 @@ tPAddr MM_AllocPhysRange(int Num, int Bits) else if(addr >> 0) rangeID = MM_PHYS_16BIT; giPhysRangeFree[ rangeID ] --; } + // Fill super bitmap + Num += addr & (64-1); + addr &= ~(64-1); + Num = (Num + (64-1)) & ~(64-1); + for( i = 0; i < Num/64; i++ ) + { + int j, bFull = 1; + for( j = 0; j < 64; j ++ ) { + if( gaiPageReferences[addr+i*64+j] ) { + bFull = 0; + break; + } + } + if( bFull ) + gaSuperBitmap[addr>>12] |= 1 << ((addr >> 6) & 64); + } RELEASE(&glPhysicalPages); - return addr; + return addr << 12; } /** @@ -158,3 +331,36 @@ tPAddr MM_AllocPhys(void) { return MM_AllocPhysRange(1, -1); } + +/** + * \brief Reference a physical page + */ +void MM_RefPhys(tPAddr PAddr) +{ + int bIsFull, j; + if( PAddr >> 12 > giMaxPhysPage ) return ; + gaiPageReferences[ PAddr >> 12 ] ++; + + bIsFull = 1; + for( j = 0; j < 64; j++ ) { + if( gaiPageReferences[ PAddr >> 12 ] == 0 ) { + bIsFull = 0; + break; + } + } + if( bIsFull ) + gaSuperBitmap[PAddr >> 24] |= 1 << ((PAddr >> 18) & 64); +} + +/** + * \brief Dereference a physical page + */ +void MM_DerefPhys(tPAddr PAddr) +{ + if( PAddr >> 12 > giMaxPhysPage ) return ; + gaiPageReferences[ PAddr >> 12 ] --; + if( gaiPageReferences[ PAddr >> 12 ] ) + { + gaSuperBitmap[PAddr >> 24] &= ~(1 << ((PAddr >> 18) & 64)); + } +}