X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Kernel%2Farch%2Fx86_64%2Fmm_phys.c;h=92a38f2a1f627e4a937bebc6638d74911b41ef2e;hb=cb944fc8a944abe6921f7477cf73fc4b23e713a5;hp=dd8ddf660f0176fec163b765874699b4d48db0f8;hpb=9f407c493c33928e0f19b834699d9694036ca42e;p=tpg%2Facess2.git diff --git a/Kernel/arch/x86_64/mm_phys.c b/Kernel/arch/x86_64/mm_phys.c index dd8ddf66..92a38f2a 100644 --- a/Kernel/arch/x86_64/mm_phys.c +++ b/Kernel/arch/x86_64/mm_phys.c @@ -5,7 +5,7 @@ */ #include #include -//#include +#include enum eMMPhys_Ranges { @@ -17,11 +17,13 @@ enum eMMPhys_Ranges NUM_MM_PHYS_RANGES }; +// === IMPORTS === +extern void gKernelEnd; + // === GLOBALS === tSpinlock glPhysicalPages; Uint64 *gaSuperBitmap; // 1 bit = 64 Pages -Uint64 *gaPrimaryBitmap; // 1 bit = 64 Pages -Uint32 *gaiPageReferences; // Reference Counts +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 @@ -29,33 +31,152 @@ Uint64 giPhysRangeLast[NUM_MM_PHYS_RANGES]; // Last free page in each range Uint64 giMaxPhysPage = 0; // Maximum Physical page // === CODE === -void MM_InitPhys(tMBoot_Info *MBoot) +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 } /** @@ -72,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 ) @@ -85,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 @@ -148,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 @@ -157,15 +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++ ) { gaiPageReferences[addr] = 1; - gaPrimaryBitmap[addr>>6] |= 1 << (addr & 63); - if( gaPrimaryBitmap[addr>>6] == -1 ) - gaSuperBitmap[addr>>12] |= 1 << ((addr >> 6) & 64); if(addr >> 32) rangeID = MM_PHYS_MAX; else if(addr >> 24) rangeID = MM_PHYS_32BIT; @@ -174,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; } /** @@ -193,11 +337,18 @@ tPAddr MM_AllocPhys(void) */ void MM_RefPhys(tPAddr PAddr) { + int bIsFull, j; if( PAddr >> 12 > giMaxPhysPage ) return ; gaiPageReferences[ PAddr >> 12 ] ++; - gaPrimaryBitmap[PAddr >> 18] |= 1 << ((PAddr>>12) & 63); - if( gaPrimaryBitmap[PAddr >> 18] == -1 ) + 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); } @@ -210,7 +361,6 @@ void MM_DerefPhys(tPAddr PAddr) gaiPageReferences[ PAddr >> 12 ] --; if( gaiPageReferences[ PAddr >> 12 ] ) { - gaPrimaryBitmap[PAddr >> 18] &= ~(1 << ((PAddr >> 12) & 63)); gaSuperBitmap[PAddr >> 24] &= ~(1 << ((PAddr >> 18) & 64)); } }