Esempio n. 1
0
        private static unsafe ulong FindFreeBlockInSMAP(ulong startAddr, ulong requiredSpace)
        {
            SMAPINFO *smap = Platform.ThePlatform.Smap;

            for (uint i = 0; i < Platform.ThePlatform.SmapCount; i++) {
                if (smap[i].type == (ulong)SMAPINFO.AddressType.Free &&
                    smap[i].addr + smap[i].size > startAddr) {

                    ulong usableSize, usableStart;

                    if (smap[i].addr < startAddr) {
                        usableSize = smap[i].size - (startAddr - smap[i].addr);
                        usableStart = startAddr;
                    }
                    else {
                        usableSize = smap[i].size;
                        usableStart = smap[i].addr;
                    }

                    if (usableSize >= requiredSpace) {
                        return usableStart;
                    }
                }
            }

            return 0;
        }
Esempio n. 2
0
        //
        // Calculate the size of physical memory from the boottime
        // information -- SHOULD ONLY BE CALLED FROM INITIALIZE
        //
        internal unsafe static void PhysicalMemoryLimits(out UIntPtr lowerAddress,
                                                         out UIntPtr upperAddress)
        {
            Platform p = Platform.ThePlatform;
            uint     i;

            int  cpuId = p.ApicId;
            uint j;

            DebugStub.WriteLine("MemoryManager.Initialize: Memory Map: Apic ID {0}\n",
                                __arglist(cpuId));

            UIntPtr baseSmapAddress = UIntPtr.MaxValue;
            UIntPtr maxSmapAddress  = UIntPtr.Zero;

            // First pass over SMAP, find the highest RAM address
            unsafe {
                SMAPINFO *smap = (SMAPINFO *)p.Smap;
                for (i = 0; i < p.SmapCount; i++)
                {
                    uint smapType = (uint)smap[i].type;
                    if (smapType != SMAPINFO.AddressTypeFree &&
                        smapType != SMAPINFO.AddressTypeKernelStack)
                    {
                        continue;
                    }

                    if (smap[i].addr < baseSmapAddress)
                    {
                        baseSmapAddress = smap[i].addr;
                    }
                    if ((smap[i].addr + smap[i].size) > maxSmapAddress)
                    {
                        maxSmapAddress = smap[i].addr + smap[i].size;
                    }

                    DebugStub.WriteLine("{0}: {1,8:x8} - {2,8:x8}, type={3,8:x8}",
                                        __arglist(i, smap[i].addr, smap[i].addr + smap[i].size, smap[i].type));

                    unchecked {
                        Tracing.Log(Tracing.Debug,
                                    "   [{0,8:x8}..{1,8:x8}] = {2,8:x8}",
                                    (UIntPtr)(uint)smap[i].addr,
                                    (UIntPtr)(uint)(smap[i].addr + smap[i].size),
                                    (UIntPtr)(uint)smap[i].type);
                    }
                }
            }

            lowerAddress = baseSmapAddress;
            upperAddress = maxSmapAddress;

            // Verify kernel and boot memory are corretly reporting within the SMAP range
            // it is a hal error to configure this otherwise.

            //DebugStub.Assert(p.KernelDllBase + p.KernelDllSize <= upperAddress);
            //DebugStub.Assert(p.BootAllocatedMemory + p.BootAllocatedMemorySize <= upperAddress);
        }
Esempio n. 3
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;
        }