///////////////////////////////////// // PUBLIC METHODS ///////////////////////////////////// // // Initialize() must be called during OS boot *BEFORE* paging // is enabled, so that physical memory can be accessed // directly. We consult the system's memory map to pick a // range of memory where we can situate the physical page // table, and initialize it. // // the reserveSize argument specifies how much physical // memory to set aside and return a PhysicalAddress to. // This is used by the MemoryManager to reserve an area // of contiguous physical memory for use in I/O operations. // // After Initialize()ation, the PhysicalPages module // assumes that its page table will be identity-mapped // into the kernel's virtual memory space. // internal static unsafe PhysicalAddress Initialize(ulong reserveSize) { Platform p = Platform.ThePlatform; UIntPtr lowerAddress = UIntPtr.Zero; UIntPtr upperAddress = UIntPtr.Zero; // NB: our initialization is currently naive; we // set up a table to describe all of physical memory, // even though there are holes in it for reserved // memory that we will never be able to use. // This makes indexing much easier, though. InitializeLock(); // Retrieve the highest RAM address MemoryManager.PhysicalMemoryLimits(out lowerAddress, out upperAddress); addressLimit = (ulong)upperAddress; DebugStub.WriteLine("Highest usable RAM address is 0x{0:x8}", __arglist(addressLimit)); // How much room do we need for the pageblock table? numBlocks = GetNumBlocks(addressLimit); ulong requiredSpace = (ulong)numBlocks * (ulong)sizeof(PageBlock); // Now we need to find a location in physical memory // where we can stick the physical pageblock table. ulong startAddr = LowerRAMBlackout; if (p.BootAllocatedMemorySize != 0) { if (startAddr > p.BootAllocatedMemory && startAddr < p.BootAllocatedMemory + p.BootAllocatedMemorySize) { startAddr = (ulong)p.BootAllocatedMemory + (ulong)p.BootAllocatedMemorySize; } } ulong physLocation = FindFreeBlockInSMAP(startAddr, requiredSpace); if (physLocation == 0) { // Failed to find a spot to park the physical page // table. This is fatal! Kernel.Panic("Couldn't find enough room to initialize hardware page table"); } // Initialize all the descriptor blocks as "free" (zeroed) physTable = (PageBlock*)physLocation; tableSize = requiredSpace; freeList = 0; // First descriptor for (uint i = 0; i < numBlocks; i++) { PageBlock* thisBlock = GetBlock(i); thisBlock->Initialize(); thisBlock->prevIdx = (i == 0) ? PageBlock.Sentinel : i - 1; thisBlock->nextIdx = (i == numBlocks - 1) ? PageBlock.Sentinel : i + 1; } // Mark the blackout area of low physical memory as used MarkRangeUsed(0, startAddr - 1); // Now mark the range of physical pages occupied by the // hardware table itself as being used! MarkRangeUsed((ulong)physTable, requiredSpace); // Mark any non-Free areas (according to SMAP) as in use SMAPINFO* smap = p.Smap; for (uint i = 0; i < p.SmapCount; i++) { if ((smap[i].type != (ulong)SMAPINFO.AddressType.Free) && ((smap[i].addr + smap[i].size) > startAddr) && (smap[i].addr < addressLimit)) { ulong unaccountedStart, unaccountedLength; if (smap[i].addr >= startAddr) { unaccountedStart = smap[i].addr; unaccountedLength = smap[i].size; } else { // Part of this memory window is already accounted for unaccountedStart = startAddr; unaccountedLength = smap[i].size - (startAddr - smap[i].addr); } MarkRangeUsed(unaccountedStart, unaccountedLength); } } // Mark out all the Platform special regions as busy if (p.MiniDumpLimit != 0) { ulong miniDumpSize = (ulong)p.MiniDumpLimit - (ulong)p.MiniDumpBase; MarkRangeUsed((ulong)p.MiniDumpBase, MemoryManager.PagePad(miniDumpSize)); } if (p.KernelDllSize != 0) { MarkRangeUsed((ulong)p.KernelDllBase, MemoryManager.PagePad((ulong)p.KernelDllSize)); } if (p.BootAllocatedMemorySize != 0) { MarkRangeUsed((ulong)p.BootAllocatedMemory, MemoryManager.PagePad((ulong)p.BootAllocatedMemorySize)); } // Last step: find an available area to situate the caller's // requested reserve-block, if any. PhysicalAddress reservedPtr = PhysicalAddress.Null; if (reserveSize != 0) { reservedPtr = new PhysicalAddress( FindFreeBlockInSMAP( MemoryManager.PagePad((ulong)physTable + tableSize), reserveSize)); if (reservedPtr == PhysicalAddress.Null) { Kernel.Panic("Couldn't find enough physically contiguous memory to reserve"); } if (reservedPtr.Value + reserveSize > 0xFFFFFF) { Kernel.Panic("Couldn't find enough physically contiguous memory below 0xFFFFFF for I/O memory"); } } // Mark the reserved block as used. It's up to the caller // to administer its use. MarkRangeUsed(reservedPtr.Value, reserveSize); CheckConsistency(); DebugStub.WriteLine("PhysicalPages initialized at 0x{0:x8} - 0x{1:x8} with {2} physical pages available.", __arglist(reservedPtr.Value, reservedPtr.Value + reserveSize, GetFreePageCount())); return reservedPtr; }