// // Allocates and commits a new range of memory. // internal UIntPtr Allocate(UIntPtr numPages, Process process, uint extra, PageType type, ProtectionDomain inDomain) { DebugStub.Assert(numPages > 0); UIntPtr mapAddr = UIntPtr.Zero; bool iflag = Lock(); // Within our lock, figure out where we're going to stick the newly // mapped memory, and mark it used. try { mapAddr = ReserveInternal(numPages, process, extra, type); if (mapAddr == UIntPtr.Zero) { DebugStub.Assert(false, "Failed to find a mapping point for new memory"); return(mapAddr); } } finally { Unlock(iflag); } UIntPtr limitAddr = mapAddr + MemoryManager.BytesFromPages(numPages); // Now actually map pages to the chosen region. if (!MemoryManager.CommitAndMapRange(mapAddr, limitAddr, inDomain)) { // yikes; failure return(UIntPtr.Zero); } allocatedCount++; allocatedBytes += (ulong)MemoryManager.BytesFromPages(numPages); if (process != null) { process.Allocated(MemoryManager.BytesFromPages(numPages)); } return(mapAddr); }
///////////////////////////////////// // PUBLIC METHODS ///////////////////////////////////// // // The range of memory turned over to a VirtualMemoryRange structure // must not have *any* mapped pages in it to start out with // // A VirtualMemoryRange can build a pagetable that *describes* // more memory than it *manages* (this supports some kernel GC // oddities). In that case, pages out-of-range are marked // as PageType.Unknown. Obviously, allocation requests are never // satisfied with out-of-bounds data. // internal unsafe VirtualMemoryRange_struct( UIntPtr baseAddr, UIntPtr limitAddr, UIntPtr descrBaseAddr, UIntPtr descrLimitAddr, ProtectionDomain inDomain) { DebugStub.Assert(MemoryManager.IsPageAligned(baseAddr)); DebugStub.Assert(MemoryManager.IsPageAligned(limitAddr)); DebugStub.Assert(MemoryManager.IsPageAligned(descrBaseAddr)); DebugStub.Assert(MemoryManager.IsPageAligned(descrLimitAddr)); // The descriptive range can't be smaller than the managed range DebugStub.Assert(descrLimitAddr >= limitAddr); DebugStub.Assert(descrBaseAddr <= baseAddr); descrBase = descrBaseAddr; descrLimit = descrLimitAddr; rangeBase = baseAddr; rangeLimit = limitAddr; rangeLock = new SpinLock(SpinLock.Types.VirtualMemoryRange); describedPages = MemoryManager.PagesFromBytes(descrLimit - descrBase); // Figure out how many pages we need for a page description table UIntPtr pageTableSize = MemoryManager.PagePad(describedPages * sizeof(uint)); dataStart = baseAddr + pageTableSize; nextAlloc = dataStart; // Commit and prepare the page table pageTable = (uint *)baseAddr; bool success = MemoryManager.CommitAndMapRange( baseAddr, baseAddr + pageTableSize, inDomain); if (!success) { Kernel.Panic("Couldn't get pages to create a new VirtualMemoryRange page table"); } allocatedBytes = 0; allocatedCount = 0; freedBytes = 0; freedCount = 0; // Describe the pages outside our range as Unknown if (descrBase < rangeBase) { SetRange(descrBase, rangeBase, MemoryManager.PageUnknown); } if (descrLimit > rangeLimit) { SetRange(rangeLimit, descrLimit, MemoryManager.PageUnknown); } // The page-table pages themselves are in use by the System SetRange((UIntPtr)pageTable, (UIntPtr)pageTable + pageTableSize, MemoryManager.KernelPageNonGC); // Describe pages in-range as Free SetRange(dataStart, rangeLimit, MemoryManager.PageFree); #if DEBUG // Check that our data range is pristine for (UIntPtr stepAddr = dataStart; stepAddr < rangeLimit; stepAddr += MemoryManager.PageSize) { DebugStub.Assert(!VMManager.IsPageMapped(stepAddr)); } #endif }