Author: fireball
Date: Sun Sep  2 00:54:02 2007
New Revision: 28751
URL: 
http://svn.reactos.org/svn/reactos?rev=28751&view=rev
Log:
- Finish the memory map code, so it now actually creates a real memory map, with all
reserved, unusable pages marked
- Add a memory type enum and use it in memory descriptors
- Improvements in KiRosFrldrLpbToNtLpb() (separate the code into different functions,
bugfixes)
Modified:
    trunk/reactos/include/reactos/arc/arc.h
    trunk/reactos/ntoskrnl/ke/freeldr.c   (contents, props changed)
    trunk/reactos/ntoskrnl/mm/mminit.c
Modified: trunk/reactos/include/reactos/arc/arc.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/include/reactos/arc/arc.h?…
==============================================================================
--- trunk/reactos/include/reactos/arc/arc.h (original)
+++ trunk/reactos/include/reactos/arc/arc.h Sun Sep  2 00:54:02 2007
@@ -86,6 +86,27 @@
     LoaderMaximum
 } TYPE_OF_MEMORY;
+typedef enum _MEMORY_TYPE
+{
+    MemoryExceptionBlock,
+    MemorySystemBlock,
+    MemoryFree,
+    MemoryBad,
+    MemoryLoadedProgram,
+    MemoryFirmwareTemporary,
+    MemoryFirmwarePermanent,
+    MemoryFreeContiguous,
+    MemorySpecialMemory,
+    MemoryMaximum
+} MEMORY_TYPE;
+
+typedef struct _MEMORY_DESCRIPTOR
+{
+    MEMORY_TYPE MemoryType;
+    ULONG BasePage;
+    ULONG PageCount;
+} MEMORY_DESCRIPTOR, *PMEMORY_DESCRIPTOR;
+
 typedef struct _MEMORY_ALLOCATION_DESCRIPTOR
 {
     LIST_ENTRY ListEntry;
Modified: trunk/reactos/ntoskrnl/ke/freeldr.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/freeldr.c?rev=…
==============================================================================
--- trunk/reactos/ntoskrnl/ke/freeldr.c (original)
+++ trunk/reactos/ntoskrnl/ke/freeldr.c Sun Sep  2 00:54:02 2007
@@ -11,6 +11,12 @@
 #include <ntoskrnl.h>
 #define NDEBUG
 #include <debug.h>
+
+typedef struct _BIOS_MEMORY_DESCRIPTOR
+{
+    ULONG BlockBase;
+    ULONG BlockSize;
+} BIOS_MEMORY_DESCRIPTOR, *PBIOS_MEMORY_DESCRIPTOR;
 /* GLOBALS *******************************************************************/
@@ -39,7 +45,7 @@
 CHAR BldrNtHalPath[64];                                 // 0x025C
 CHAR BldrNtBootPath[64];                                // 0x029C
 LDR_DATA_TABLE_ENTRY BldrModules[64];                   // 0x02DC
-MEMORY_ALLOCATION_DESCRIPTOR BldrMemoryDescriptors[64]; // 0x14DC
+MEMORY_ALLOCATION_DESCRIPTOR BldrMemoryDescriptors[60]; // 0x14DC
 WCHAR BldrModuleStrings[64][260];                       // 0x19DC
 WCHAR BldrModuleStringsFull[64][260];                   // 0x9BDC
 NLS_DATA_BLOCK BldrNlsDataBlock;                        // 0x11DDC
@@ -49,6 +55,14 @@
 ARC_DISK_SIGNATURE BldrDiskInfo[32];                    // 0x1413C
                                                         // 0x1443C
+/* BIOS Memory Map */
+BIOS_MEMORY_DESCRIPTOR BiosMemoryDescriptors[16] = {{0}};
+PBIOS_MEMORY_DESCRIPTOR BiosMemoryDescriptorList = BiosMemoryDescriptors;
+
+/* ARC Memory Map */
+ULONG NumberDescriptors = 0;
+MEMORY_DESCRIPTOR MDArray[60] = {{0}};
+
 /* FUNCTIONS *****************************************************************/
 PMEMORY_ALLOCATION_DESCRIPTOR
@@ -56,8 +70,794 @@
 KiRosGetMdFromArray(VOID)
 {
     /* Return the next MD from the list, but make sure we don't overflow */
-    if (BldrCurrentMd > 64) KEBUGCHECK(0);
+    if (BldrCurrentMd > 60) KEBUGCHECK(0);
     return &BldrMemoryDescriptors[BldrCurrentMd++];
+}
+
+VOID
+NTAPI
+KiRosAddBiosBlock(ULONG Address,
+                  ULONG Size)
+{
+    PBIOS_MEMORY_DESCRIPTOR BiosBlock = BiosMemoryDescriptorList;
+
+    /* Loop our BIOS Memory Descriptor List */
+    while (BiosBlock->BlockSize > 0)
+    {
+        /* Check if we've found a matching head block */
+        if (Address + Size == BiosBlock->BlockBase)
+        {
+            /* Simply enlarge and rebase it */
+            BiosBlock->BlockBase = Address;
+            BiosBlock->BlockSize += Size;
+            break;
+        }
+
+        /* Check if we've found a matching tail block */
+        if (Address == (BiosBlock->BlockBase + BiosBlock->BlockSize))
+        {
+            /* Simply enlarge it */
+            BiosBlock->BlockSize += Size;
+            break;
+        }
+
+        /* Nothing suitable found, try the next block */
+        BiosBlock++;
+    }
+
+    /* No usable blocks found, found a free block instead */
+    if (!BiosBlock->BlockSize)
+    {
+        /* Write our data */
+        BiosBlock->BlockBase = Address;
+        BiosBlock->BlockSize = Size;
+
+        /* Create a new block and mark it as the end of the array */
+        BiosBlock++;
+        BiosBlock->BlockBase = BiosBlock->BlockSize = 0L;
+    }
+}
+
+VOID
+NTAPI
+KiRosBuildBiosMemoryMap(VOID)
+{
+    ULONG j;
+    ULONG BlockBegin, BlockEnd;
+
+    /* Loop the BIOS Memory Map */
+    for (j = 0; j < KeMemoryMapRangeCount; j++)
+    {
+        /* Get the start and end addresses */
+        BlockBegin = KeMemoryMap[j].BaseAddrLow;
+        BlockEnd = KeMemoryMap[j].BaseAddrLow + KeMemoryMap[j].LengthLow - 1;
+
+        /* Make sure this isn't a > 4GB descriptor */
+        if (!KeMemoryMap[j].BaseAddrHigh)
+        {
+            /* Make sure we don't overflow */
+            if (BlockEnd < BlockBegin) BlockEnd = 0xFFFFFFFF;
+
+            /* Check if this is free memory */
+            if (KeMemoryMap[j].Type == 1)
+            {
+                /* Add it to our BIOS descriptors */
+                KiRosAddBiosBlock(BlockBegin, BlockEnd - BlockBegin + 1);
+            }
+        }
+    }
+}
+
+NTSTATUS
+NTAPI
+KiRosAllocateArcDescriptor(IN ULONG PageBegin,
+                           IN ULONG PageEnd,
+                           IN MEMORY_TYPE MemoryType)
+{
+    ULONG i;
+
+    /* Loop all our descriptors */
+    for (i = 0; i < NumberDescriptors; i++)
+    {
+        /* Attempt to fing a free block that describes our region */
+        if ((MDArray[i].MemoryType == MemoryFree) &&
+            (MDArray[i].BasePage <= PageBegin) &&
+            (MDArray[i].BasePage + MDArray[i].PageCount > PageBegin) &&
+            (MDArray[i].BasePage + MDArray[i].PageCount >= PageEnd))
+        {
+            /* Found one! */
+            break;
+        }
+    }
+
+    /* Check if we found no free blocks, and fail if so */
+    if (i == NumberDescriptors) return ENOMEM;
+
+    /* Check if the block has our base address */
+    if (MDArray[i].BasePage == PageBegin)
+    {
+        /* Check if it also has our ending address */
+        if ((MDArray[i].BasePage + MDArray[i].PageCount) == PageEnd)
+        {
+            /* Then convert this region into our new memory type */
+            MDArray[i].MemoryType = MemoryType;
+        }
+        else
+        {
+            /* Otherwise, make sure we have enough descriptors */
+            if (NumberDescriptors == 60) return ENOMEM;
+
+            /* Cut this descriptor short */
+            MDArray[i].BasePage = PageEnd;
+            MDArray[i].PageCount -= (PageEnd - PageBegin);
+
+            /* And allocate a new descriptor for our memory range */
+            MDArray[NumberDescriptors].BasePage = PageBegin;
+            MDArray[NumberDescriptors].PageCount = PageEnd - PageBegin;
+            MDArray[NumberDescriptors].MemoryType = MemoryType;
+            NumberDescriptors++;
+        }
+    }
+    else if ((MDArray[i].BasePage + MDArray[i].PageCount) == PageEnd)
+    {
+        /* This block has our end address, make sure we have a free block */
+        if (NumberDescriptors == 60) return ENOMEM;
+
+        /* Rebase this descriptor */
+        MDArray[i].PageCount = PageBegin - MDArray[i].BasePage;
+
+        /* And allocate a new descriptor for our memory range */
+        MDArray[NumberDescriptors].BasePage = PageBegin;
+        MDArray[NumberDescriptors].PageCount = PageEnd - PageBegin;
+        MDArray[NumberDescriptors].MemoryType = MemoryType;
+        NumberDescriptors++;
+    }
+    else
+    {
+        /* We'll need two descriptors, make sure they're available */
+        if ((NumberDescriptors + 1) >= 60) return ENOMEM;
+
+        /* Allocate a free memory descriptor for what follows us */
+        MDArray[NumberDescriptors].BasePage = PageEnd;
+        MDArray[NumberDescriptors].PageCount = MDArray[i].PageCount -
+                                               (PageEnd - MDArray[i].BasePage);
+        MDArray[NumberDescriptors].MemoryType = MemoryFree;
+        NumberDescriptors++;
+
+        /* Cut down the current free descriptor */
+        MDArray[i].PageCount = PageBegin - MDArray[i].BasePage;
+
+        /* Allocate a new memory descriptor for our memory range */
+        MDArray[NumberDescriptors].BasePage = PageBegin;
+        MDArray[NumberDescriptors].PageCount = PageEnd - PageBegin;
+        MDArray[NumberDescriptors].MemoryType = MemoryType;
+        NumberDescriptors++;
+    }
+
+    /* Everything went well */
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+KiRosConfigureArcDescriptor(IN ULONG PageBegin,
+                            IN ULONG PageEnd,
+                            IN TYPE_OF_MEMORY MemoryType)
+{
+    ULONG i;
+    ULONG BlockBegin, BlockEnd;
+    MEMORY_TYPE BlockType;
+    BOOLEAN Combined = FALSE;
+
+    /* If this descriptor seems bogus, just return */
+    if (PageEnd <= PageBegin) return STATUS_SUCCESS;
+
+    /* Loop every ARC descriptor, trying to find one we can modify */
+    for (i = 0; i < NumberDescriptors; i++)
+    {
+        /* Get its settings */
+        BlockBegin = MDArray[i].BasePage;
+        BlockEnd = MDArray[i].BasePage + MDArray[i].PageCount;
+        BlockType = MDArray[i].MemoryType;
+
+        /* Check if we can fit inside this block */
+        if (BlockBegin < PageBegin)
+        {
+            /* Check if we are larger then it */
+            if ((BlockEnd > PageBegin) && (BlockEnd <= PageEnd))
+            {
+                /* Make it end where we start */
+                BlockEnd = PageBegin;
+            }
+
+            /* Check if it ends after we do */
+            if (BlockEnd > PageEnd)
+            {
+                /* Make sure we can allocate a descriptor */
+                if (NumberDescriptors == 60) return ENOMEM;
+
+                /* Create a descriptor for whatever memory we're not part of */
+                MDArray[NumberDescriptors].MemoryType = BlockType;
+                MDArray[NumberDescriptors].BasePage = PageEnd;
+                MDArray[NumberDescriptors].PageCount  = BlockEnd - PageEnd;
+                NumberDescriptors++;
+
+                /* The next block ending is now where we begin */
+                BlockEnd = PageBegin;
+            }
+        }
+        else
+        {
+            /* Check if the blog begins inside our range */
+            if (BlockBegin < PageEnd)
+            {
+                /* Check if it ends before we do */
+                if (BlockEnd < PageEnd)
+                {
+                    /* Then make it disappear */
+                    BlockEnd = BlockBegin;
+                }
+                else
+                {
+                    /* Otherwise make it start where we end */
+                    BlockBegin = PageEnd;
+                }
+            }
+        }
+
+        /* Check if the block matches us, and we haven't tried combining yet */
+        if ((BlockType == MemoryType) && !(Combined))
+        {
+            /* Check if it starts where we end */
+            if (BlockBegin == PageEnd)
+            {
+                /* Make it start with us, and combine us */
+                BlockBegin = PageBegin;
+                Combined = TRUE;
+            }
+            else if (BlockEnd == PageBegin)
+            {
+                /* Otherwise, it ends where we begin, combine its ending */
+                BlockEnd = PageEnd;
+                Combined = TRUE;
+            }
+        }
+
+        /* Check the original block data matches with what we came up with */
+        if ((MDArray[i].BasePage == BlockBegin) &&
+            (MDArray[i].PageCount == BlockEnd - BlockBegin))
+        {
+            /* Then skip it */
+            continue;
+        }
+
+        /* Otherwise, set our new settings for this block */
+        MDArray[i].BasePage  = BlockBegin;
+        MDArray[i].PageCount = BlockEnd - BlockBegin;
+
+        /* Check if we are killing the block */
+        if (BlockBegin == BlockEnd)
+        {
+            /* Delete this block and restart the loop properly */
+            NumberDescriptors--;
+            if (i < NumberDescriptors) MDArray[i] = MDArray[NumberDescriptors];
+            i--;
+        }
+    }
+
+    /* If we got here without combining, we need to allocate a new block */
+    if (!(Combined) && (MemoryType < LoaderMaximum))
+    {
+        /* Make sure there's enough descriptors */
+        if (NumberDescriptors == 60) return ENOMEM;
+
+        /* Allocate a new block with our data */
+        MDArray[NumberDescriptors].MemoryType = MemoryType;
+        MDArray[NumberDescriptors].BasePage = PageBegin;
+        MDArray[NumberDescriptors].PageCount  = PageEnd - PageBegin;
+        NumberDescriptors++;
+    }
+
+    /* Changes complete, return success */
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+KiRosBuildOsMemoryMap(VOID)
+{
+    PBIOS_MEMORY_DESCRIPTOR MdBlock;
+    ULONG BlockStart, BlockEnd, BiasedStart, BiasedEnd, PageStart, PageEnd;
+    NTSTATUS Status = STATUS_SUCCESS;
+    ULONG BiosPage = 0xA0;
+
+    /* Loop the BIOS Memory Descriptor List */
+    MdBlock = BiosMemoryDescriptorList;
+    while (MdBlock->BlockSize)
+    {
+        /* Get the statrt and end addresses */
+        BlockStart = MdBlock->BlockBase;
+        BlockEnd = BlockStart + MdBlock->BlockSize - 1;
+
+        /* Align them to page boundaries */
+        BiasedStart = BlockStart & (PAGE_SIZE - 1);
+        if (BiasedStart) BlockStart = BlockStart + PAGE_SIZE - BiasedStart;
+        BiasedEnd = (BlockEnd + 1) & (ULONG)(PAGE_SIZE - 1);
+        if (BiasedEnd) BlockEnd -= BiasedEnd;
+
+        /* Get the actual page numbers */
+        PageStart = BlockStart >> PAGE_SHIFT;
+        PageEnd = (BlockEnd + 1) >> PAGE_SHIFT;
+
+        /* If we're starting at page 0, then put the BIOS page at the end */
+        if (!PageStart) BiosPage = PageEnd;
+
+        /* Check if we did any alignment */
+        if (BiasedStart)
+        {
+            /* Mark that region as reserved */
+            Status = KiRosConfigureArcDescriptor(PageStart - 1,
+                                                 PageStart,
+                                                 MemorySpecialMemory);
+            if (Status != STATUS_SUCCESS) break;
+        }
+
+        /* Check if we did any alignment */
+        if (BiasedEnd)
+        {
+            /* Mark that region as reserved */
+            Status = KiRosConfigureArcDescriptor(PageEnd - 1,
+                                                 PageEnd,
+                                                 MemorySpecialMemory);
+            if (Status != STATUS_SUCCESS) break;
+
+            /* If the bios page was the last page, use the next one instead */
+            if (BiosPage == PageEnd) BiosPage += 1;
+        }
+
+        /* Check if the page is below the 16MB Memory hole */
+        if (PageEnd <= 0xFC0)
+        {
+            /* It is, mark the memory a free */
+            Status = KiRosConfigureArcDescriptor(PageStart,
+                                                 PageEnd,
+                                                 LoaderFree);
+        }
+        else if (PageStart >= 0x1000)
+        {
+            /* It's over 16MB, so that memory gets marked as reserve */
+            Status = KiRosConfigureArcDescriptor(PageStart,
+                                             PageEnd,
+                                             LoaderReserve);
+        }
+        else
+        {
+            /* Check if it starts below the memory hole */
+            if (PageStart < 0xFC0)
+            {
+                /* Mark that part as free */
+                Status = KiRosConfigureArcDescriptor(PageStart,
+                                                     0xFC0,
+                                                     MemoryFree);
+                if (Status != STATUS_SUCCESS) break;
+
+                /* And update the page start for the code below */
+                PageStart = 0xFC0;
+            }
+
+            /* Any code in the memory hole region ends up as reserve */
+            Status = KiRosConfigureArcDescriptor(PageStart,
+                                                 PageEnd,
+                                                 LoaderReserve);
+        }
+
+        /* If we failed, break out, otherwise, go to the next BIOS block */
+        if (Status != STATUS_SUCCESS) break;
+        MdBlock++;
+    }
+
+    /* If anything failed until now, return error code */
+    if (Status != STATUS_SUCCESS) return Status;
+
+    /* Set the top 16MB region as reserved */
+    Status = KiRosConfigureArcDescriptor(0xFC0, 0x1000, MemorySpecialMemory);
+    if (Status != STATUS_SUCCESS) return Status;
+
+    /* Setup the BIOS region as reserved */
+    KiRosConfigureArcDescriptor(0xA0, 0x100, LoaderMaximum);
+    KiRosConfigureArcDescriptor(BiosPage, 0x100, MemoryFirmwarePermanent);
+
+    /* Build an entry for the IVT */
+    Status = KiRosAllocateArcDescriptor(0, 1, MemoryFirmwarePermanent);
+    if (Status != STATUS_SUCCESS) return Status;
+
+    /* Build an entry for the KPCR (which we put in page 1) */
+    Status = KiRosAllocateArcDescriptor(1, 2, LoaderMemoryData);
+    if (Status != STATUS_SUCCESS) return Status;
+
+    /* Build an entry for the PDE and return the status */
+    Status = KiRosAllocateArcDescriptor(KeRosLoaderBlock->
+                                        PageDirectoryStart >> PAGE_SHIFT,
+                                        KeRosLoaderBlock->
+                                        PageDirectoryEnd >> PAGE_SHIFT,
+                                        LoaderMemoryData);
+    return Status;
+}
+
+VOID
+NTAPI
+KiRosBuildReservedMemoryMap(VOID)
+{
+    ULONG j;
+    ULONG BlockBegin, BlockEnd, BiasedPage;
+
+    /* Loop the BIOS Memory Map */
+    for (j = 0; j < KeMemoryMapRangeCount; j++)
+    {
+        /* Get the start and end addresses */
+        BlockBegin = KeMemoryMap[j].BaseAddrLow;
+        BlockEnd = BlockBegin + KeMemoryMap[j].LengthLow - 1;
+
+        /* Make sure it wasn't a > 4GB descriptor */
+        if (!KeMemoryMap[j].BaseAddrHigh)
+        {
+            /* Make sure it doesn't overflow */
+            if (BlockEnd < BlockBegin) BlockEnd = 0xFFFFFFFF;
+
+            /* Check if this was free memory */
+            if (KeMemoryMap[j].Type == 1)
+            {
+                /* Get the page-aligned addresses */
+                BiasedPage = BlockBegin & (PAGE_SIZE - 1);
+                BlockBegin >>= PAGE_SHIFT;
+                if (BiasedPage) BlockBegin++;
+                BlockEnd = (BlockEnd >> PAGE_SHIFT) + 1;
+
+                /* Check if the block is within the 16MB memory hole */
+                if ((BlockBegin < 0xFC0) && (BlockEnd >= 0xFC0))
+                {
+                    /* Don't allow it to cross this boundary */
+                    BlockBegin = 0xFC0;
+                }
+
+                /* Check if the boundary is across 16MB */
+                if ((BlockEnd > 0xFFF) && (BlockBegin <= 0xFFF))
+                {
+                    /* Don't let it cross */
+                    BlockEnd = 0xFFF;
+                }
+
+                /* Check if the block describes the memory hole */
+                if ((BlockBegin >= 0xFC0) && (BlockEnd <= 0xFFF))
+                {
+                    /* Set this region as temporary */
+                    KiRosConfigureArcDescriptor(BlockBegin,
+                                                BlockEnd,
+                                                MemoryFirmwareTemporary);
+                }
+            }
+            else
+            {
+                /* Get the page-aligned addresses */
+                BlockBegin >>= PAGE_SHIFT;
+                BiasedPage = (BlockEnd + 1) & (PAGE_SIZE - 1);
+                BlockEnd >>= PAGE_SHIFT;
+                if (BiasedPage) BlockEnd++;
+
+                /* Set this memory as reserved */
+                KiRosConfigureArcDescriptor(BlockBegin,
+                                            BlockEnd + 1,
+                                            MemorySpecialMemory);
+            }
+        }
+    }
+}
+
+VOID
+NTAPI
+KiRosInsertNtDescriptor(IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor)
+{
+    PLIST_ENTRY ListHead, PreviousEntry, NextEntry;
+    PMEMORY_ALLOCATION_DESCRIPTOR Descriptor = NULL, NextDescriptor = NULL;
+
+    /* Loop the memory descriptor list */
+    ListHead = &KeLoaderBlock->MemoryDescriptorListHead;
+    PreviousEntry = ListHead;
+    NextEntry = ListHead->Flink;
+    while (NextEntry != ListHead)
+    {
+        /* Get the current descriptor and check if it's below ours */
+        NextDescriptor = CONTAINING_RECORD(NextEntry,
+                                           MEMORY_ALLOCATION_DESCRIPTOR,
+                                           ListEntry);
+        if (NewDescriptor->BasePage < NextDescriptor->BasePage) break;
+
+        /* It isn't, save the previous entry and descriptor, and try again */
+        PreviousEntry = NextEntry;
+        Descriptor = NextDescriptor;
+        NextEntry = NextEntry->Flink;
+    }
+
+    /* So we found the right spot to insert. Is this free memory? */
+    if (NewDescriptor->MemoryType != LoaderFree)
+    {
+        /* It isn't, so insert us before the last descriptor */
+        InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry);
+    }
+    else
+    {
+        /* We're free memory. Check if the entry we found is also free memory */
+        if ((PreviousEntry != ListHead) &&
+            ((Descriptor->MemoryType == LoaderFree) ||
+             (Descriptor->MemoryType == LoaderReserve)) &&
+            ((Descriptor->BasePage + Descriptor->PageCount) ==
+              NewDescriptor->BasePage))
+        {
+            /* It's free memory, and we're right after it. Enlarge that block */
+            Descriptor->PageCount += NewDescriptor->PageCount;
+            NewDescriptor = Descriptor;
+        }
+        else
+        {
+            /* Our range scan't be combined, so just insert us separately */
+            InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry);
+        }
+
+        /* Check if we merged with an existing free memory block */
+        if ((NextEntry != ListHead) &&
+            ((NextDescriptor->MemoryType == LoaderFree) ||
+             (NextDescriptor->MemoryType == LoaderReserve)) &&
+            ((NewDescriptor->BasePage + NewDescriptor->PageCount) ==
+              NextDescriptor->BasePage))
+        {
+            /* Update our own block */
+            NewDescriptor->PageCount += NextDescriptor->PageCount;
+
+            /* Remove the next block */
+            RemoveEntryList(&NextDescriptor->ListEntry);
+        }
+    }
+}
+
+NTSTATUS
+NTAPI
+KiRosBuildNtDescriptor(IN PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor,
+                       IN MEMORY_TYPE MemoryType,
+                       IN ULONG BasePage,
+                       IN ULONG PageCount)
+{
+    PMEMORY_ALLOCATION_DESCRIPTOR Descriptor, NextDescriptor = NULL;
+    LONG Delta;
+    TYPE_OF_MEMORY CurrentType;
+    BOOLEAN UseNext;
+
+    /* Check how many pages we'll be consuming */
+    Delta = BasePage - MemoryDescriptor->BasePage;
+    if (!(Delta) && (PageCount == MemoryDescriptor->PageCount))
+    {
+        /* We can simply convert the current descriptor into our new type */
+        MemoryDescriptor->MemoryType = MemoryType;
+    }
+    else
+    {
+        /* Get the current memory type of the descriptor, and reserve it */
+        CurrentType = MemoryDescriptor->MemoryType;
+        MemoryDescriptor->MemoryType = LoaderSpecialMemory;
+
+        /* Check if we'll need another descriptor for what's left of memory */
+        UseNext = ((BasePage != MemoryDescriptor->BasePage) &&
+                   (Delta + PageCount != MemoryDescriptor->PageCount));
+
+        /* Get a descriptor */
+        Descriptor = KiRosGetMdFromArray();
+        if (!Descriptor) return STATUS_INSUFFICIENT_RESOURCES;
+
+        /* Check if we are using another descriptor */
+        if (UseNext)
+        {
+            /* Allocate that one too */
+            NextDescriptor = KiRosGetMdFromArray();
+            if (!NextDescriptor) return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        /* Build the descriptor we got */
+        Descriptor->MemoryType = MemoryType;
+        Descriptor->BasePage = BasePage;
+        Descriptor->PageCount = PageCount;
+
+        /* Check if we're starting at the same place as the old one */
+        if (BasePage == MemoryDescriptor->BasePage)
+        {
+            /* Simply decrease the old descriptor and rebase it */
+            MemoryDescriptor->BasePage += PageCount;
+            MemoryDescriptor->PageCount -= PageCount;
+            MemoryDescriptor->MemoryType = CurrentType;
+        }
+        else if (Delta + PageCount == MemoryDescriptor->PageCount)
+        {
+            /* We finish where the old one did, shorten it */
+            MemoryDescriptor->PageCount -= PageCount;
+            MemoryDescriptor->MemoryType = CurrentType;
+        }
+        else
+        {
+            /* We're inside the current block, mark our free region */
+            NextDescriptor->MemoryType = LoaderFree;
+            NextDescriptor->BasePage = BasePage + PageCount;
+            NextDescriptor->PageCount = MemoryDescriptor->PageCount -
+                                        (PageCount + Delta);
+
+            /* And cut down the current descriptor */
+            MemoryDescriptor->PageCount = Delta;
+            MemoryDescriptor->MemoryType = CurrentType;
+
+            /* Finally, insert our new free descriptor into the list */
+            KiRosInsertNtDescriptor(NextDescriptor);
+        }
+
+        /* Insert the descriptor we allocated */
+        KiRosInsertNtDescriptor(Descriptor);
+    }
+
+    /* Return success */
+    return STATUS_SUCCESS;
+}
+
+PMEMORY_ALLOCATION_DESCRIPTOR
+NTAPI
+KiRosFindNtDescriptor(IN ULONG BasePage)
+{
+    PMEMORY_ALLOCATION_DESCRIPTOR MdBlock = NULL;
+    PLIST_ENTRY NextEntry, ListHead;
+
+    /* Scan the memory descriptor list */
+    ListHead = &KeLoaderBlock->MemoryDescriptorListHead;
+    NextEntry = ListHead->Flink;
+    while (NextEntry != ListHead)
+    {
+        /* Get the current descriptor */
+        MdBlock = CONTAINING_RECORD(NextEntry,
+                                    MEMORY_ALLOCATION_DESCRIPTOR,
+                                    ListEntry);
+
+        /* Check if it can contain our memory range */
+        if ((MdBlock->BasePage <= BasePage) &&
+            (MdBlock->BasePage + MdBlock->PageCount > BasePage))
+        {
+            /* It can, break out */
+            break;
+        }
+
+        /* Go to the next descriptor */
+        NextEntry = NextEntry->Flink;
+    }
+
+    /* Return the descriptor we found, if any */
+    return MdBlock;
+}
+
+NTSTATUS
+NTAPI
+KiRosAllocateNtDescriptor(IN TYPE_OF_MEMORY MemoryType,
+                          IN ULONG BasePage,
+                          IN ULONG PageCount,
+                          IN ULONG Alignment,
+                          OUT PULONG ReturnedBase)
+{
+    PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
+    ULONG AlignedBase, AlignedLimit;
+    PMEMORY_ALLOCATION_DESCRIPTOR ActiveMdBlock;
+    ULONG ActiveAlignedBase = 0;
+    PLIST_ENTRY NextEntry, ListHead;
+
+    /* If no information was given, make some assumptions */
+    if (!Alignment) Alignment = 1;
+    if (!PageCount) PageCount = 1;
+
+    /* Start looking for a matching descvriptor */
+    do
+    {
+        /* Calculate the limit of the range */
+        AlignedLimit = PageCount + BasePage;
+
+        /* Find a descriptor that already contains our base address */
+        MdBlock = KiRosFindNtDescriptor(BasePage);
+        if (MdBlock)
+        {
+            /* If it contains our limit as well, break out early */
+            if ((MdBlock->PageCount + MdBlock->BasePage) > AlignedLimit) break;
+        }
+
+        /* Loop the memory list */
+        ActiveMdBlock = NULL;
+        ListHead = &KeLoaderBlock->MemoryDescriptorListHead;
+        NextEntry = ListHead->Flink;
+        while (NextEntry != ListHead)
+        {
+            /* Get the current descriptors */
+            MdBlock = CONTAINING_RECORD(NextEntry,
+                                        MEMORY_ALLOCATION_DESCRIPTOR,
+                                        ListEntry);
+
+            /* Align the base address and our limit */
+            AlignedBase = (MdBlock->BasePage + (Alignment - 1)) &~ Alignment;
+            AlignedLimit = MdBlock->PageCount -
+                           AlignedBase +
+                           MdBlock->BasePage;
+
+            /* Check if this is a free block that can satisfy us */
+            if ((MdBlock->MemoryType == LoaderFree) &&
+                (AlignedLimit <= MdBlock->PageCount) &&
+                (PageCount <= AlignedLimit))
+            {
+                /* It is, stop searching */
+                ActiveMdBlock = MdBlock;
+                ActiveAlignedBase = AlignedBase;
+                break;
+            }
+
+            /* Try the next block */
+            NextEntry = NextEntry->Flink;
+        }
+
+        /* See if we came up with an adequate block */
+        if (ActiveMdBlock)
+        {
+            /* Generate a descriptor in it */
+            *ReturnedBase = AlignedBase;
+            return KiRosBuildNtDescriptor(ActiveMdBlock,
+                                          MemoryType,
+                                          ActiveAlignedBase,
+                                          PageCount);
+        }
+    } while (TRUE);
+
+    /* We found a matching block, generate a descriptor with it */
+    *ReturnedBase = BasePage;
+    return KiRosBuildNtDescriptor(MdBlock, MemoryType, BasePage, PageCount);
+}
+
+NTSTATUS
+NTAPI
+KiRosBuildArcMemoryList(VOID)
+{
+    PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
+    MEMORY_DESCRIPTOR *Memory;
+    ULONG i;
+
+    /* Loop all BIOS Memory Descriptors */
+    for (i = 0; i < NumberDescriptors; i++)
+    {
+        /* Get the current descriptor */
+        Memory = &MDArray[i];
+
+        /* Allocate an NT Memory Descriptor */
+        Descriptor = KiRosGetMdFromArray();
+        if (!Descriptor) return ENOMEM;
+
+        /* Copy the memory type */
+        Descriptor->MemoryType = Memory->MemoryType;
+        if (Memory->MemoryType == MemoryFreeContiguous)
+        {
+            /* Convert this to free */
+            Descriptor->MemoryType = LoaderFree;
+        }
+        else if (Memory->MemoryType == MemorySpecialMemory)
+        {
+            /* Convert this to special memory */
+            Descriptor->MemoryType = LoaderSpecialMemory;
+        }
+
+        /* Copy the range data */
+        Descriptor->BasePage = Memory->BasePage;
+        Descriptor->PageCount = Memory->PageCount;
+
+        /* Insert the descriptor */
+        if (Descriptor->PageCount) KiRosInsertNtDescriptor(Descriptor);
+    }
+
+    /* All went well */
+    return STATUS_SUCCESS;
 }
 VOID
@@ -67,7 +867,6 @@
 {
     PLOADER_PARAMETER_BLOCK LoaderBlock;
     PLDR_DATA_TABLE_ENTRY LdrEntry;
-    PMEMORY_ALLOCATION_DESCRIPTOR MdEntry;
     PLOADER_MODULE RosEntry;
     ULONG i, j, ModSize;
     PVOID ModStart;
@@ -79,15 +878,16 @@
     WCHAR PathToDrivers[] = L"\\SystemRoot\\System32\\drivers\\";
     WCHAR PathToSystem32[] = L"\\SystemRoot\\System32\\";
     CHAR DriverNameLow[256];
+    ULONG Base;
     /* First get some kernel-loader globals */
     AcpiTableDetected = (RosLoaderBlock->Flags & MB_FLAGS_ACPI_TABLE) ? TRUE :
FALSE;
-    MmFreeLdrMemHigher = RosLoaderBlock->MemHigher;
-    MmFreeLdrPageDirectoryEnd = RosLoaderBlock->PageDirectoryEnd;
+       MmFreeLdrMemHigher = RosLoaderBlock->MemHigher;
+       MmFreeLdrPageDirectoryEnd = RosLoaderBlock->PageDirectoryEnd;
     if (!MmFreeLdrPageDirectoryEnd) MmFreeLdrPageDirectoryEnd = 0x40000;
     /* Set the NT Loader block and initialize it */
-    *NtLoaderBlock = LoaderBlock = &BldrLoaderBlock;
+    *NtLoaderBlock = KeLoaderBlock = LoaderBlock = &BldrLoaderBlock;
     RtlZeroMemory(LoaderBlock, sizeof(LOADER_PARAMETER_BLOCK));
     /* Set the NLS Data block */
@@ -105,63 +905,17 @@
     InitializeListHead(&LoaderBlock->BootDriverListHead);
InitializeListHead(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead);
-    /* Create one large blob of free memory */
-    MdEntry = KiRosGetMdFromArray();
-    MdEntry->MemoryType = LoaderFree;
-    MdEntry->BasePage = 0;
-    MdEntry->PageCount = MmFreeLdrMemHigher / 4;
-    InsertTailList(&LoaderBlock->MemoryDescriptorListHead,
&MdEntry->ListEntry);
-
-    /*
-     * FIXME: Instead of just "inserting" MDs into the list,
-     * we need to make then be "consumed" from the Free Descriptor.
-     * This will happen soon (and also ensure a sorted list).
-     */
-
-    /* Loop the BIOS Memory Map */
-    for (j = 0; j < KeMemoryMapRangeCount; j++)
-    {
-        /* Check if this is a reserved entry */
-        if (KeMemoryMap[j].Type == 2)
-        {
-            /* It is, build an entry for it */
-            MdEntry = KiRosGetMdFromArray();
-            MdEntry->MemoryType = LoaderSpecialMemory;
-            MdEntry->BasePage = KeMemoryMap[j].BaseAddrLow >> PAGE_SHIFT;
-            MdEntry->PageCount = (KeMemoryMap[j].LengthLow + PAGE_SIZE - 1) >>
PAGE_SHIFT;
-            InsertTailList(&LoaderBlock->MemoryDescriptorListHead,
-                           &MdEntry->ListEntry);
-        }
-    }
-
-    /* Page 0 is reserved: build an entry for it */
-    MdEntry = KiRosGetMdFromArray();
-    MdEntry->MemoryType = LoaderFirmwarePermanent;
-    MdEntry->BasePage = 0;
-    MdEntry->PageCount = 1;
-    InsertTailList(&LoaderBlock->MemoryDescriptorListHead,
&MdEntry->ListEntry);
-
-    /* Build an entry for the KPCR (which we put in page 1) */
-    MdEntry = KiRosGetMdFromArray();
-    MdEntry->MemoryType = LoaderMemoryData;
-    MdEntry->BasePage = 1;
-    MdEntry->PageCount = 1;
-    InsertTailList(&LoaderBlock->MemoryDescriptorListHead,
&MdEntry->ListEntry);
-
-    /* Build an entry for the PDE */
-    MdEntry = KiRosGetMdFromArray();
-    MdEntry->MemoryType = LoaderMemoryData;
-    MdEntry->BasePage = (ULONG_PTR)MmGetPageDirectory() >> PAGE_SHIFT;
-    MdEntry->PageCount = (MmFreeLdrPageDirectoryEnd -
-                          (ULONG_PTR)MmGetPageDirectory()) / PAGE_SIZE;
-    InsertTailList(&LoaderBlock->MemoryDescriptorListHead,
&MdEntry->ListEntry);
-
-    /* Mark Video ROM as reserved */
-    MdEntry = KiRosGetMdFromArray();
-    MdEntry->MemoryType = LoaderFirmwarePermanent;
-    MdEntry->BasePage = 0xA0000 >> PAGE_SHIFT;
-    MdEntry->PageCount = (0xE8000 - 0xA0000) / PAGE_SIZE;
-    InsertTailList(&LoaderBlock->MemoryDescriptorListHead,
&MdEntry->ListEntry);
+    /* Build the free memory map, which uses BIOS Descriptors */
+    KiRosBuildBiosMemoryMap();
+
+    /* Build entries for ReactOS memory ranges, which uses ARC Descriptors */
+    KiRosBuildOsMemoryMap();
+
+    /* Build entries for the reserved map, which uses ARC Descriptors */
+    KiRosBuildReservedMemoryMap();
+
+    /* Now convert the BIOS and ARC Descriptors into NT Memory Descirptors */
+    KiRosBuildArcMemoryList();
     /* Loop boot driver list */
     for (i = 0; i < RosLoaderBlock->ModsCount; i++)
@@ -180,12 +934,12 @@
             LoaderBlock->NlsData->AnsiCodePageData = ModStart;
             /* Create an MD for it */
-            MdEntry = KiRosGetMdFromArray();
-            MdEntry->MemoryType = LoaderNlsData;
-            MdEntry->BasePage = ((ULONG_PTR)ModStart &~ KSEG0_BASE) >>
PAGE_SHIFT;
-            MdEntry->PageCount = (ModSize + PAGE_SIZE - 1)>> PAGE_SHIFT;
-            InsertTailList(&LoaderBlock->MemoryDescriptorListHead,
-                           &MdEntry->ListEntry);
+            KiRosAllocateNtDescriptor(LoaderNlsData,
+                                      ((ULONG_PTR)ModStart &~ KSEG0_BASE) >>
+                                      PAGE_SHIFT,
+                                      (ModSize + PAGE_SIZE - 1)>> PAGE_SHIFT,
+                                      0,
+                                      &Base);
             continue;
         }
         else if (!_stricmp(DriverName, "oem.nls"))
@@ -195,12 +949,12 @@
             LoaderBlock->NlsData->OemCodePageData = ModStart;
             /* Create an MD for it */
-            MdEntry = KiRosGetMdFromArray();
-            MdEntry->MemoryType = LoaderNlsData;
-            MdEntry->BasePage = ((ULONG_PTR)ModStart &~ KSEG0_BASE) >>
PAGE_SHIFT;
-            MdEntry->PageCount = (ModSize + PAGE_SIZE - 1) >> PAGE_SHIFT;
-            InsertTailList(&LoaderBlock->MemoryDescriptorListHead,
-                           &MdEntry->ListEntry);
+            KiRosAllocateNtDescriptor(LoaderNlsData,
+                                      ((ULONG_PTR)ModStart &~ KSEG0_BASE) >>
+                                      PAGE_SHIFT,
+                                      (ModSize + PAGE_SIZE - 1)>> PAGE_SHIFT,
+                                      0,
+                                      &Base);
             continue;
         }
         else if (!_stricmp(DriverName, "casemap.nls"))
@@ -210,12 +964,12 @@
             LoaderBlock->NlsData->UnicodeCodePageData = ModStart;
             /* Create an MD for it */
-            MdEntry = KiRosGetMdFromArray();
-            MdEntry->MemoryType = LoaderNlsData;
-            MdEntry->BasePage = ((ULONG_PTR)ModStart &~ KSEG0_BASE) >>
PAGE_SHIFT;
-            MdEntry->PageCount = (ModSize + PAGE_SIZE - 1) >> PAGE_SHIFT;
-            InsertTailList(&LoaderBlock->MemoryDescriptorListHead,
-                           &MdEntry->ListEntry);
+            KiRosAllocateNtDescriptor(LoaderNlsData,
+                                      ((ULONG_PTR)ModStart &~ KSEG0_BASE) >>
+                                      PAGE_SHIFT,
+                                      (ModSize + PAGE_SIZE - 1)>> PAGE_SHIFT,
+                                      0,
+                                      &Base);
             continue;
         }
@@ -232,12 +986,12 @@
             LoaderBlock->SetupLdrBlock = NULL;
             /* Create an MD for it */
-            MdEntry = KiRosGetMdFromArray();
-            MdEntry->MemoryType = LoaderRegistryData;
-            MdEntry->BasePage = ((ULONG_PTR)ModStart &~ KSEG0_BASE) >>
PAGE_SHIFT;
-            MdEntry->PageCount = (ModSize + PAGE_SIZE - 1) >> PAGE_SHIFT;
-            InsertTailList(&LoaderBlock->MemoryDescriptorListHead,
-                           &MdEntry->ListEntry);
+            KiRosAllocateNtDescriptor(LoaderRegistryData,
+                                      ((ULONG_PTR)ModStart &~ KSEG0_BASE) >>
+                                      PAGE_SHIFT,
+                                      (ModSize + PAGE_SIZE - 1)>> PAGE_SHIFT,
+                                      0,
+                                      &Base);
             continue;
         }
@@ -246,13 +1000,11 @@
             !(_stricmp(DriverName, "hardware.hiv")))
         {
             /* Create an MD for it */
-            ModStart = RVA(ModStart, KSEG0_BASE);
-            MdEntry = KiRosGetMdFromArray();
-            MdEntry->MemoryType = LoaderRegistryData;
-            MdEntry->BasePage = ((ULONG_PTR)ModStart &~ KSEG0_BASE) >>
PAGE_SHIFT;
-            MdEntry->PageCount = (ModSize + PAGE_SIZE - 1) >> PAGE_SHIFT;
-            InsertTailList(&LoaderBlock->MemoryDescriptorListHead,
-                           &MdEntry->ListEntry);
+            KiRosAllocateNtDescriptor(LoaderRegistryData,
+                                      (ULONG_PTR)ModStart >> PAGE_SHIFT,
+                                      (ModSize + PAGE_SIZE - 1)>> PAGE_SHIFT,
+                                      0,
+                                      &Base);
             continue;
         }
@@ -260,32 +1012,32 @@
         if (!(_stricmp(DriverName, "ntoskrnl.exe")))
         {
             /* Create an MD for it */
-            MdEntry = KiRosGetMdFromArray();
-            MdEntry->MemoryType = LoaderSystemCode;
-            MdEntry->BasePage = ((ULONG_PTR)ModStart &~ KSEG0_BASE) >>
PAGE_SHIFT;
-            MdEntry->PageCount = (ModSize + PAGE_SIZE - 1) >> PAGE_SHIFT;
-            InsertTailList(&LoaderBlock->MemoryDescriptorListHead,
-                           &MdEntry->ListEntry);
+            KiRosAllocateNtDescriptor(LoaderSystemCode,
+                                      ((ULONG_PTR)ModStart &~ KSEG0_BASE) >>
+                                      PAGE_SHIFT,
+                                      (ModSize + PAGE_SIZE - 1)>> PAGE_SHIFT,
+                                      0,
+                                      &Base);
         }
         else if (!(_stricmp(DriverName, "hal.dll")))
         {
             /* Create an MD for the HAL */
-            MdEntry = KiRosGetMdFromArray();
-            MdEntry->MemoryType = LoaderHalCode;
-            MdEntry->BasePage = ((ULONG_PTR)ModStart &~ KSEG0_BASE) >>
PAGE_SHIFT;
-            MdEntry->PageCount = (ModSize + PAGE_SIZE - 1) >> PAGE_SHIFT;
-            InsertTailList(&LoaderBlock->MemoryDescriptorListHead,
-                           &MdEntry->ListEntry);
+            KiRosAllocateNtDescriptor(LoaderHalCode,
+                                      ((ULONG_PTR)ModStart &~ KSEG0_BASE) >>
+                                      PAGE_SHIFT,
+                                      (ModSize + PAGE_SIZE - 1)>> PAGE_SHIFT,
+                                      0,
+                                      &Base);
         }
         else
         {
             /* Create an MD for any driver */
-            MdEntry = KiRosGetMdFromArray();
-            MdEntry->MemoryType = LoaderBootDriver;
-            MdEntry->BasePage = ((ULONG_PTR)ModStart &~ KSEG0_BASE) >>
PAGE_SHIFT;
-            MdEntry->PageCount = (ModSize + PAGE_SIZE - 1) >> PAGE_SHIFT;
-            InsertTailList(&LoaderBlock->MemoryDescriptorListHead,
-                           &MdEntry->ListEntry);
+            KiRosAllocateNtDescriptor(LoaderBootDriver,
+                                      ((ULONG_PTR)ModStart &~ KSEG0_BASE) >>
+                                      PAGE_SHIFT,
+                                      (ModSize + PAGE_SIZE - 1)>> PAGE_SHIFT,
+                                      0,
+                                      &Base);
         }
         /* Lowercase the drivername so we can check its extension later */
@@ -361,7 +1113,9 @@
     /* Save the number of pages the kernel images take */
     LoaderBlock->Extension->LoaderPagesSpanned =
-        MmFreeLdrLastKrnlPhysAddr - MmFreeLdrFirstKrnlPhysAddr;
+        PAGE_ROUND_UP(KeRosLoaderBlock->
+                      ModsAddr[KeRosLoaderBlock->ModsCount - 1].ModEnd) -
+        KeRosLoaderBlock->ModsAddr[0].ModStart;
     LoaderBlock->Extension->LoaderPagesSpanned /= PAGE_SIZE;
     /* Now setup the setup block if we have one */
@@ -452,16 +1206,15 @@
     /* Save pointer to ROS Block */
     KeRosLoaderBlock = LoaderBlock;
-
-    /* Save memory manager data */
     MmFreeLdrLastKernelAddress = PAGE_ROUND_UP(KeRosLoaderBlock->
                                                ModsAddr[KeRosLoaderBlock->
                                                         ModsCount - 1].
-                                                ModEnd);
+                                               ModEnd);
     MmFreeLdrFirstKrnlPhysAddr = KeRosLoaderBlock->ModsAddr[0].ModStart -
                                  KSEG0_BASE;
     MmFreeLdrLastKrnlPhysAddr = MmFreeLdrLastKernelAddress - KSEG0_BASE;
+    /* Save memory manager data */
     KeMemoryMapRangeCount = 0;
     if (LoaderBlock->Flags & MB_FLAGS_MMAP_INFO)
     {
Propchange: trunk/reactos/ntoskrnl/ke/freeldr.c
------------------------------------------------------------------------------
--- svn:needs-lock (original)
+++ svn:needs-lock (removed)
@@ -1,1 +1,0 @@
-*
Modified: trunk/reactos/ntoskrnl/mm/mminit.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/mminit.c?rev=2…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/mminit.c (original)
+++ trunk/reactos/ntoskrnl/mm/mminit.c Sun Sep  2 00:54:02 2007
@@ -326,7 +326,8 @@
    "MemoryData        ", // not used
    "NlsData           ", // used
    "SpecialMemory     ", // == Bad
-   "BBTMemory         " // == Bad
+   "BBTMemory         ",
+   "LoaderReserve     "// == Bad
 };
 VOID