Пример #1
0
        /////////////////////////////////////
        // 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;
        }