[FREELDR]
authorTimo Kreuzer <timo.kreuzer@reactos.org>
Fri, 23 Sep 2011 17:35:45 +0000 (17:35 +0000)
committerTimo Kreuzer <timo.kreuzer@reactos.org>
Fri, 23 Sep 2011 17:35:45 +0000 (17:35 +0000)
Fix some bugs in the code that deals with memory descriptors:
ArcGetMemoryDescriptor was enumerating the bios generated entries first and then the static entries. The latter were conflicting with the former and took precedence when initializing the page lookup table. The problem was, that MmFindLocationForPageLookupTable would use the highest range of pages available. If that range would be conflicting with a following static descriptor, the static would have been ignored. It only worked because on x86 the highest bios descriptor has enough free pages, before it conflicts with a static entry (page 0xfff, marked as unusable), so that the page lookup table could be created.

MmGetAddressablePageCountIncludingHoles enumerated all memory descriptors to find MmLowestPhysicalPage, but it was only counting FreeMemory, thus skipping all other memory ranges. This only worked, due to the previous bug, so that the bios pages shown first took precedence over the following static descriptors. Without the former bug MmLowestPhysicalPage would be 0x100 which would tigger in the next bug:
MmAreMemoryPagesAvailable took the passed address range and looked up all pages in the lookup table to see whether all are free. Now the function didn't check, whether the passed address was below MmLowestPhysicalPage and in case it was, happily accessed the memory below the lookup table. This would result in hal being loaded at 0x40000 overwriting the loader itself.

This is all fixe by implementing a new way of creating the memory map. First there is a static memory map, which has enough free entries to add dynamic ranges. Then AddMemoryDescriptor will allow you to add a new range,
while the already existing ranges will take precedence and the new ranges will be properly split and inserted, so that the resulting map does not contain any overlapping regions and is sorted from low to high pages. The static memory descriptor exists in the architecture specific file.
The code that enumerates the bios information now uses this function to add the ranges on top of the static descriptor.
More cleanup work to follow.

svn path=/trunk/; revision=53816

reactos/boot/freeldr/freeldr/arch/arm/macharm.c
reactos/boot/freeldr/freeldr/arch/i386/pcmem.c
reactos/boot/freeldr/freeldr/arch/i386/xboxmem.c
reactos/boot/freeldr/freeldr/debug.c
reactos/boot/freeldr/freeldr/include/arch/i386/machxbox.h
reactos/boot/freeldr/freeldr/include/arch/pc/machpc.h
reactos/boot/freeldr/freeldr/include/arch/pc/x86common.h
reactos/boot/freeldr/freeldr/include/machine.h
reactos/boot/freeldr/freeldr/mm/meminit.c

index 5359123..49a38b0 100644 (file)
@@ -143,12 +143,25 @@ ArmHwDetect(VOID)
     return RootNode;
 }
 
-PBIOS_MEMORY_MAP
-ArmMemGetMemoryMap(OUT PULONG MaxMemoryMapSize)
+MEMORY_DESCRIPTOR ArmMemoryMap[32];
+
+PMEMORY_DESCRIPTOR
+ArmMemGetMemoryMap(OUT ULONG *MemoryMapSize)
 {
+    ASSERT(ArmBoardBlock->MemoryMapEntryCount <= 32);
+
     /* Return whatever the board returned to us (CS0 Base + Size and FLASH0) */
-    *MaxMemoryMapSize = ArmBoardBlock->MemoryMapEntryCount;
-    return ArmBoardBlock->MemoryMap;
+    for (i = 0; i < ArmBoardBlock->MemoryMapEntryCount; i++)
+    {
+        ArmMemoryMap[i].BasePage = ArmBoardBlock->MemoryMap[i].BaseAddress / PAGE_SIZE;
+        ArmMemoryMap[i].PageCount = ArmBoardBlock->MemoryMap[i].Length / PAGE_SIZE;
+        if (ArmBoardBlock->MemoryMap[i].Type == BiosMemoryUsable)
+            ArmMemoryMap[i].MemoryType = MemoryFree;
+        else
+            ArmMemoryMap[i].MemoryType = MemoryFirmwarePermanent;
+    }
+
+    return ArmBoardBlock->MemoryMapEntryCount;
 }
 
 VOID
index 568c54a..c9fb769 100644 (file)
@@ -21,6 +21,7 @@
  */
 
 #include <freeldr.h>
+#include <arch/pc/x86common.h>
 
 #define NDEBUG
 #include <debug.h>
 DBG_DEFAULT_CHANNEL(MEMORY);
 
 #define MAX_BIOS_DESCRIPTORS 32
+#define FREELDR_BASE_PAGE  (FREELDR_BASE / PAGE_SIZE)
+#define FILEBUF_BASE_PAGE  (FILESYSBUFFER / PAGE_SIZE)
+#define DISKBUF_BASE_PAGE  (DISKREADBUFFER / PAGE_SIZE)
+#define STACK_BASE_PAGE    (DISKBUF_BASE_PAGE + 1)
+#define STACK_END_PAGE     (STACK32ADDR / PAGE_SIZE)
+#define BIOSBUF_BASE_PAGE  (BIOSCALLBUFFER / PAGE_SIZE)
+
+#define FREELDR_PAGE_COUNT (FILEBUF_BASE_PAGE - FREELDR_BASE_PAGE)
+#define FILEBUF_PAGE_COUNT (DISKBUF_BASE_PAGE - FILEBUF_BASE_PAGE)
+#define DISKBUF_PAGE_COUNT (1)
+#define STACK_PAGE_COUNT   (STACK_END_PAGE - STACK_BASE_PAGE)
+#define BIOSBUF_PAGE_COUNT (0xA0 - BIOSBUF_BASE_PAGE)
 
 BIOS_MEMORY_MAP PcBiosMemoryMap[MAX_BIOS_DESCRIPTORS];
 ULONG PcBiosMapCount;
 
+MEMORY_DESCRIPTOR PcMemoryMap[MAX_BIOS_DESCRIPTORS + 1] =
+{
+ { MemoryFirmwarePermanent, 0x00,               1 }, // realmode int vectors
+ { MemoryFirmwareTemporary, 0x01,               FREELDR_BASE_PAGE - 1 }, // freeldr stack + cmdline
+ { MemoryLoadedProgram,     FREELDR_BASE_PAGE,  FREELDR_PAGE_COUNT }, // freeldr image
+ { MemoryFirmwareTemporary, FILEBUF_BASE_PAGE,  FILEBUF_PAGE_COUNT }, // File system read buffer. FILESYSBUFFER
+ { MemoryFirmwareTemporary, DISKBUF_BASE_PAGE,  DISKBUF_PAGE_COUNT }, // Disk read buffer for int 13h. DISKREADBUFFER
+ { MemorySpecialMemory,     STACK_BASE_PAGE,    STACK_PAGE_COUNT }, // prot mode stack.
+ { MemoryFirmwareTemporary, BIOSBUF_BASE_PAGE,  BIOSBUF_PAGE_COUNT }, // BIOSCALLBUFFER
+ { MemoryFirmwarePermanent, 0xA0,               0x60 }, // ROM / Video
+ { MemorySpecialMemory,     0xFFF,              1 }, // unusable memory
+ { MemorySpecialMemory,     MAXULONG_PTR,       0 }, // end of map
+};
+
+ULONG
+AddMemoryDescriptor(
+    IN OUT PMEMORY_DESCRIPTOR List,
+    IN ULONG MaxCount,
+    IN PFN_NUMBER BasePage,
+    IN PFN_NUMBER PageCount,
+    IN MEMORY_TYPE MemoryType);
+
 static
 BOOLEAN
 GetExtendedMemoryConfiguration(ULONG* pMemoryAtOneMB /* in KB */, ULONG* pMemoryAtSixteenMB /* in 64KB */)
@@ -153,11 +188,14 @@ PcMemGetConventionalMemorySize(VOID)
   return (ULONG)Regs.w.ax;
 }
 
-static ULONG
-PcMemGetBiosMemoryMap(PBIOS_MEMORY_MAP BiosMemoryMap, ULONG MaxMemoryMapSize)
+static
+ULONG
+PcMemGetBiosMemoryMap(PMEMORY_DESCRIPTOR MemoryMap, ULONG MaxMemoryMapSize)
 {
   REGS Regs;
-  ULONG MapCount;
+  ULONG MapCount = 0;
+  ULONGLONG RealBaseAddress, RealSize;
+  ASSERT(PcBiosMapCount == 0);
 
   TRACE("GetBiosMemoryMap()\n");
 
@@ -181,7 +219,7 @@ PcMemGetBiosMemoryMap(PBIOS_MEMORY_MAP BiosMemoryMap, ULONG MaxMemoryMapSize)
    */
   Regs.x.ebx = 0x00000000;
 
-  for (MapCount = 0; MapCount < MaxMemoryMapSize; MapCount++)
+  while (PcBiosMapCount < MAX_BIOS_DESCRIPTORS)
     {
       /* Setup the registers for the BIOS call */
       Regs.x.eax = 0x0000E820;
@@ -192,7 +230,7 @@ PcMemGetBiosMemoryMap(PBIOS_MEMORY_MAP BiosMemoryMap, ULONG MaxMemoryMapSize)
       Regs.w.di = BIOSCALLBUFOFFSET;
       Int386(0x15, &Regs, &Regs);
 
-      TRACE("Memory Map Entry %d\n", MapCount);
+      TRACE("Memory Map Entry %d\n", PcBiosMapCount);
       TRACE("Int15h AX=E820h\n");
       TRACE("EAX = 0x%x\n", Regs.x.eax);
       TRACE("EBX = 0x%x\n", Regs.x.ebx);
@@ -206,15 +244,40 @@ PcMemGetBiosMemoryMap(PBIOS_MEMORY_MAP BiosMemoryMap, ULONG MaxMemoryMapSize)
           break;
         }
 
-      /* Copy data to caller's buffer */
-      RtlCopyMemory(&BiosMemoryMap[MapCount], (PVOID)BIOSCALLBUFFER, Regs.x.ecx);
+      /* Copy data to global buffer */
+      RtlCopyMemory(&PcBiosMemoryMap[PcBiosMapCount], (PVOID)BIOSCALLBUFFER, Regs.x.ecx);
 
-      TRACE("BaseAddress: 0x%p\n", (PVOID)(ULONG_PTR)BiosMemoryMap[MapCount].BaseAddress);
-      TRACE("Length: 0x%p\n", (PVOID)(ULONG_PTR)BiosMemoryMap[MapCount].Length);
-      TRACE("Type: 0x%x\n", BiosMemoryMap[MapCount].Type);
-      TRACE("Reserved: 0x%x\n", BiosMemoryMap[MapCount].Reserved);
+      TRACE("BaseAddress: 0x%p\n", (PVOID)(ULONG_PTR)PcBiosMemoryMap[PcBiosMapCount].BaseAddress);
+      TRACE("Length: 0x%p\n", (PVOID)(ULONG_PTR)PcBiosMemoryMap[PcBiosMapCount].Length);
+      TRACE("Type: 0x%x\n", PcBiosMemoryMap[PcBiosMapCount].Type);
+      TRACE("Reserved: 0x%x\n", PcBiosMemoryMap[PcBiosMapCount].Reserved);
       TRACE("\n");
 
+      /* Align up base of memory area */
+      RealBaseAddress = ROUND_UP(PcBiosMemoryMap[PcBiosMapCount].BaseAddress, MM_PAGE_SIZE);
+      RealSize = PcBiosMemoryMap[PcBiosMapCount].Length -
+                 (RealBaseAddress - PcBiosMemoryMap[PcBiosMapCount].BaseAddress);
+
+      /* Check if we can add this descriptor */
+      if ((RealSize >= MM_PAGE_SIZE) && (MapCount < MaxMemoryMapSize))
+      {
+        MEMORY_TYPE MemoryType;
+
+        if (PcBiosMemoryMap[PcBiosMapCount].Type == BiosMemoryUsable)
+          MemoryType = MemoryFree;
+        else
+          MemoryType = MemoryFirmwarePermanent;
+
+        /* Add the descriptor */
+        MapCount = AddMemoryDescriptor(PcMemoryMap,
+                                       MAX_BIOS_DESCRIPTORS,
+                                       RealBaseAddress / MM_PAGE_SIZE,
+                                       RealSize / MM_PAGE_SIZE,
+                                       MemoryType);
+      }
+
+      PcBiosMapCount++;
+
       /* If the continuation value is zero or the
        * carry flag is set then this was
        * the last entry so we're done */
@@ -229,46 +292,59 @@ PcMemGetBiosMemoryMap(PBIOS_MEMORY_MAP BiosMemoryMap, ULONG MaxMemoryMapSize)
   return MapCount;
 }
 
-PBIOS_MEMORY_MAP
+
+PMEMORY_DESCRIPTOR
 PcMemGetMemoryMap(ULONG *MemoryMapSize)
 {
-  ULONG EntryCount;
+  ULONG i, EntryCount;
   ULONG ExtendedMemorySizeAtOneMB;
   ULONG ExtendedMemorySizeAtSixteenMB;
 
-  EntryCount = PcMemGetBiosMemoryMap(PcBiosMemoryMap, MAX_BIOS_DESCRIPTORS);
-  PcBiosMapCount = EntryCount;
+  EntryCount = PcMemGetBiosMemoryMap(PcMemoryMap, MAX_BIOS_DESCRIPTORS);
 
   /* If the BIOS didn't provide a memory map, synthesize one */
   if (0 == EntryCount)
     {
       GetExtendedMemoryConfiguration(&ExtendedMemorySizeAtOneMB, &ExtendedMemorySizeAtSixteenMB);
 
-                                  /* Conventional memory */
-      PcBiosMemoryMap[EntryCount].BaseAddress = 0;
-      PcBiosMemoryMap[EntryCount].Length = PcMemGetConventionalMemorySize() * 1024;
-      PcBiosMemoryMap[EntryCount].Type = BiosMemoryUsable;
-      EntryCount++;
-
-      /* Extended memory at 1MB */
-      PcBiosMemoryMap[EntryCount].BaseAddress = 1024 * 1024;
-      PcBiosMemoryMap[EntryCount].Length = ExtendedMemorySizeAtOneMB * 1024;
-      PcBiosMemoryMap[EntryCount].Type = BiosMemoryUsable;
+      /* Conventional memory */
+      AddMemoryDescriptor(PcMemoryMap,
+                          MAX_BIOS_DESCRIPTORS,
+                          0,
+                          PcMemGetConventionalMemorySize() * 1024 / PAGE_SIZE,
+                          MemoryFree);
+
+      /* Extended memory */
+      EntryCount = AddMemoryDescriptor(PcMemoryMap,
+                          MAX_BIOS_DESCRIPTORS,
+                          1024 * 1024 / PAGE_SIZE,
+                          ExtendedMemorySizeAtOneMB * 1024 / PAGE_SIZE,
+                          MemoryFree);
       EntryCount++;
 
       if (ExtendedMemorySizeAtSixteenMB != 0)
       {
         /* Extended memory at 16MB */
-        PcBiosMemoryMap[EntryCount].BaseAddress = 0x1000000;
-        PcBiosMemoryMap[EntryCount].Length = ExtendedMemorySizeAtSixteenMB * 64 * 1024;
-        PcBiosMemoryMap[EntryCount].Type = BiosMemoryUsable;
-        EntryCount++;
+        EntryCount = AddMemoryDescriptor(PcMemoryMap,
+                          MAX_BIOS_DESCRIPTORS,
+                          0x1000000 / PAGE_SIZE,
+                          ExtendedMemorySizeAtSixteenMB * 64 * 1024 / PAGE_SIZE,
+                          MemoryFree);
       }
     }
 
+    TRACE("Dumping resulting memory map:\n");
+    for (i = 0; i < EntryCount; i++)
+    {
+        TRACE("BasePage=0x%lx, PageCount=0x%lx, Type=%s\n",
+              PcMemoryMap[i].BasePage,
+              PcMemoryMap[i].PageCount,
+              MmGetSystemMemoryMapTypeString(PcMemoryMap[i].MemoryType));
+    }
+
   *MemoryMapSize = EntryCount;
 
-  return PcBiosMemoryMap;
+  return PcMemoryMap;
 }
 
 /* EOF */
index f2e5e4a..33e9923 100644 (file)
@@ -75,21 +75,21 @@ XboxMemInit(VOID)
   AvailableMemoryMb = InstalledMemoryMb;
 }
 
-BIOS_MEMORY_MAP BiosMemoryMap[2];
+MEMORY_DESCRIPTOR BiosMemoryMap[2];
 
-PBIOS_MEMORY_MAP
+PMEMORY_DESCRIPTOR
 XboxMemGetMemoryMap(ULONG *MemoryMapSize)
 {
   /* Synthesize memory map */
       /* Available RAM block */
-      BiosMemoryMap[0].BaseAddress = 0;
-      BiosMemoryMap[0].Length = AvailableMemoryMb * 1024 * 1024;
-      BiosMemoryMap[0].Type = BiosMemoryUsable;
+      BiosMemoryMap[0].BasePage = 0;
+      BiosMemoryMap[0].PageCount = AvailableMemoryMb * 1024 * 1024 / MM_PAGE_SIZE;
+      BiosMemoryMap[0].MemoryType = MemoryFree;
 
       /* Video memory */
-      BiosMemoryMap[1].BaseAddress = AvailableMemoryMb * 1024 * 1024;
-      BiosMemoryMap[1].Length = (InstalledMemoryMb - AvailableMemoryMb) * 1024 * 1024;
-      BiosMemoryMap[1].Type = BiosMemoryReserved;
+      BiosMemoryMap[1].BasePage = AvailableMemoryMb * 1024 * 1024 / MM_PAGE_SIZE;
+      BiosMemoryMap[1].PageCount = (InstalledMemoryMb - AvailableMemoryMb) * 1024 * 1024 / MM_PAGE_SIZE;
+      BiosMemoryMap[1].MemoryType = MemoryFirmwarePermanent;
 
   *MemoryMapSize = 2;
   return BiosMemoryMap;
index 67c73bd..93b5edd 100644 (file)
@@ -26,7 +26,7 @@
 //#define DEBUG_ALL
 //#define DEBUG_INIFILE
 //#define DEBUG_REACTOS
-//#define DEBUG_CUSTOM
+#define DEBUG_CUSTOM
 #define DEBUG_NONE
 
 #if defined (DEBUG_ALL)
@@ -38,7 +38,7 @@ ULONG   DebugPrintMask = DPRINT_INIFILE;
 #elif defined (DEBUG_REACTOS)
 ULONG   DebugPrintMask = DPRINT_REACTOS | DPRINT_REGISTRY;
 #elif defined (DEBUG_CUSTOM)
-ULONG   DebugPrintMask = DPRINT_WARNING | DPRINT_WINDOWS;
+ULONG   DebugPrintMask = DPRINT_WARNING | DPRINT_MEMORY;
 #else //#elif defined (DEBUG_NONE)
 ULONG   DebugPrintMask = 0;
 #endif
index b7ec507..2daa37d 100644 (file)
@@ -49,7 +49,7 @@ VOID XboxPrepareForReactOS(IN BOOLEAN Setup);
 
 VOID XboxMemInit(VOID);
 PVOID XboxMemReserveMemory(ULONG MbToReserve);
-PBIOS_MEMORY_MAP XboxMemGetMemoryMap(ULONG *MemoryMapSize);
+PMEMORY_DESCRIPTOR XboxMemGetMemoryMap(ULONG *MemoryMapSize);
 
 BOOLEAN XboxDiskReadLogicalSectors(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer);
 BOOLEAN XboxDiskGetPartitionEntry(UCHAR DriveNumber, ULONG PartitionNumber, PPARTITION_TABLE_ENTRY PartitionTableEntry);
index 0a8b4dd..9fb6914 100644 (file)
@@ -46,7 +46,7 @@ VOID PcVideoSync(VOID);
 VOID PcVideoPrepareForReactOS(IN BOOLEAN Setup);
 VOID PcPrepareForReactOS(IN BOOLEAN Setup);
 
-PBIOS_MEMORY_MAP PcMemGetMemoryMap(ULONG *MemoryMapSize);
+PMEMORY_DESCRIPTOR PcMemGetMemoryMap(ULONG *MemoryMapSize);
 
 BOOLEAN PcDiskGetBootPath(char *BootPath, unsigned Size);
 BOOLEAN PcDiskReadLogicalSectors(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer);
index c8b94f7..4cdc80e 100644 (file)
 #define BSS_START           HEX(6F00)
 #define FREELDR_BASE        HEX(F800)
 #define FREELDR_PE_BASE    HEX(10000)
+#define FILESYSBUFFER      HEX(80000) /* Buffer to store file system data (e.g. cluster buffer for FAT) */
+#define DISKREADBUFFER     HEX(90000) /* Buffer to store data read in from the disk via the BIOS */
 #define STACK32ADDR        HEX(98000) /* The 32-bit stack top will be at 9000:8000, or 0xA8000 */
 #define STACK64ADDR           HEX(98000) /* The 64-bit stack top will be at 98000 */
 #define BIOSCALLBUFFER     HEX(98000) /* Buffer to store temporary data for any Int386() call */
-#define FILESYSBUFFER      HEX(80000) /* Buffer to store file system data (e.g. cluster buffer for FAT) */
-#define DISKREADBUFFER     HEX(90000) /* Buffer to store data read in from the disk via the BIOS */
 #define DISKREADBUFFER_SIZE 512
 
 #define BIOSCALLBUFSEGMENT (BIOSCALLBUFFER/16) /* Buffer to store temporary data for any Int386() call */
index 7235eb1..ce083f7 100644 (file)
@@ -1,5 +1,4 @@
-/* $Id$
- *
+/* 
  *  FreeLoader
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -59,7 +58,7 @@ typedef struct tagMACHVTBL
   VOID (*PrepareForReactOS)(IN BOOLEAN Setup);
 
   MEMORY_DESCRIPTOR* (*GetMemoryDescriptor)(MEMORY_DESCRIPTOR* Current);
-  PBIOS_MEMORY_MAP (*GetMemoryMap)(PULONG MemoryMapSize);
+  PMEMORY_DESCRIPTOR (*GetMemoryMap)(PULONG MaxMemoryMapSize);
 
   BOOLEAN (*DiskGetBootPath)(char *BootPath, unsigned Size);
   BOOLEAN (*DiskReadLogicalSectors)(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer);
index bb7efae..24283ae 100644 (file)
@@ -53,211 +53,106 @@ ULONG             LastFreePageHint = 0;
 ULONG MmLowestPhysicalPage = 0xFFFFFFFF;
 ULONG MmHighestPhysicalPage = 0;
 
+PMEMORY_DESCRIPTOR BiosMemoryMap;
+ULONG BiosMemoryMapEntryCount;
+
 extern ULONG_PTR       MmHeapPointer;
 extern ULONG_PTR       MmHeapStart;
 
-typedef struct
-{
-    MEMORY_DESCRIPTOR m;
-    ULONG Index;
-    BOOLEAN GeneratedDescriptor;
-} MEMORY_DESCRIPTOR_INT;
-static const MEMORY_DESCRIPTOR_INT MemoryDescriptors[] =
-{
-#if defined (__i386__) || defined (_M_AMD64)
-    { { MemoryFirmwarePermanent, 0x00, 1 }, 0, }, // realmode int vectors
-    { { MemoryFirmwareTemporary, 0x01, 7 }, 1, }, // freeldr stack + cmdline
-    { { MemoryLoadedProgram, 0x08, 0x70 }, 2, }, // freeldr image (roughly max. 0x64 pages)
-    { { MemorySpecialMemory, 0x78, 8 }, 3, }, // prot mode stack. BIOSCALLBUFFER
-    { { MemoryFirmwareTemporary, 0x80, 0x10 }, 4, }, // File system read buffer. FILESYSBUFFER
-    { { MemoryFirmwareTemporary, 0x90, 0x10 }, 5, }, // Disk read buffer for int 13h. DISKREADBUFFER
-    { { MemoryFirmwarePermanent, 0xA0, 0x60 }, 6, }, // ROM / Video
-    { { MemorySpecialMemory, 0xFFF, 1 }, 7, }, // unusable memory
-#elif __arm__ // This needs to be done per-platform specific way
-
-#endif
-};
-
-static
-VOID MmFixupSystemMemoryMap(PBIOS_MEMORY_MAP BiosMemoryMap, ULONG* MapCount)
-{
-       int             Index;
-       int             Index2;
-       ULONGLONG BaseAddressOffset;
-
-       // Loop through each entry in the array
-       for (Index=0; Index<*MapCount; Index++)
-       {
-               // Correct all the addresses to be aligned on page boundaries
-               BaseAddressOffset = ROUND_UP(BiosMemoryMap[Index].BaseAddress, MM_PAGE_SIZE) - BiosMemoryMap[Index].BaseAddress;
-               BiosMemoryMap[Index].BaseAddress += BaseAddressOffset;
-               if (BiosMemoryMap[Index].Length < BaseAddressOffset)
-               {
-                       BiosMemoryMap[Index].Length = 0;
-               }
-               else
-               {
-                       BiosMemoryMap[Index].Length -= BaseAddressOffset;
-               }
-               BiosMemoryMap[Index].Length = ROUND_DOWN(BiosMemoryMap[Index].Length, MM_PAGE_SIZE);
-
-               // If the entry type isn't usable then remove
-               // it from the memory map (this will help reduce
-               // the size of our lookup table)
-               // If the length is less than a full page then
-               // get rid of it also.
-               if (BiosMemoryMap[Index].Type != BiosMemoryUsable ||
-                       BiosMemoryMap[Index].Length < MM_PAGE_SIZE)
-               {
-                       // Slide every entry after this down one
-                       for (Index2=Index; Index2<(*MapCount - 1); Index2++)
-                       {
-                               BiosMemoryMap[Index2] = BiosMemoryMap[Index2 + 1];
-                       }
-                       (*MapCount)--;
-                       Index--;
-               }
-       }
-}
-
-const MEMORY_DESCRIPTOR*
-ArcGetMemoryDescriptor(const MEMORY_DESCRIPTOR* Current)
+ULONG
+AddMemoryDescriptor(
+    IN OUT PMEMORY_DESCRIPTOR List,
+    IN ULONG MaxCount,
+    IN PFN_NUMBER BasePage,
+    IN PFN_NUMBER PageCount,
+    IN MEMORY_TYPE MemoryType)
 {
-    MEMORY_DESCRIPTOR_INT* CurrentDescriptor;
-    PBIOS_MEMORY_MAP BiosMemoryMap;
-    static ULONG BiosMemoryMapEntryCount;
-    static MEMORY_DESCRIPTOR_INT BiosMemoryDescriptors[32];
-    static BOOLEAN MemoryMapInitialized = FALSE;
-    ULONG i, j;
+    ULONG i, c;
+    PFN_NUMBER NextBase;
+    TRACE("AddMemoryDescriptor(0x%lx-0x%lx [0x%lx pages])\n",
+          BasePage, BasePage + PageCount, PageCount);
 
-    //
-    // Check if it is the first time we're called
-    //
-    if (!MemoryMapInitialized)
+    /* Scan through all existing descriptors */
+    for (i = 0, c = 0; (c < MaxCount) && (List[c].PageCount != 0); c++)
     {
-        //
-        // Get the machine generated memory map
-        //
-        BiosMemoryMap = MachVtbl.GetMemoryMap(&BiosMemoryMapEntryCount);
+        /* Count entries completely below the new range */
+        if (List[i].BasePage + List[i].PageCount <= BasePage) i++;
+    }
 
-        //
-        // Fix entries that are not page aligned
-        //
-        MmFixupSystemMemoryMap(BiosMemoryMap, &BiosMemoryMapEntryCount);
+    /* Check if the list is full */
+    if (c >= MaxCount) return c;
 
-        //
-        // Copy the entries to our structure
-        //
-        for (i = 0, j = 0; i < BiosMemoryMapEntryCount; i++)
-        {
-            //
-            // Is it suitable memory?
-            //
-            if (BiosMemoryMap[i].Type != BiosMemoryUsable)
-            {
-                //
-                // No. Process next descriptor
-                //
-                continue;
-            }
+    /* Is there an existing descriptor starting before the new range */
+    while ((i < c) && (List[i].BasePage <= BasePage))
+    {
+        /* The end of the existing one is the minimum for the new range */
+        NextBase = List[i].BasePage + List[i].PageCount;
 
-            //
-            // Copy this memory descriptor
-            //
-            BiosMemoryDescriptors[j].m.MemoryType = MemoryFree;
-            BiosMemoryDescriptors[j].m.BasePage = (ULONG)(BiosMemoryMap[i].BaseAddress / MM_PAGE_SIZE);
-            BiosMemoryDescriptors[j].m.PageCount = (ULONG)(BiosMemoryMap[i].Length / MM_PAGE_SIZE);
-            BiosMemoryDescriptors[j].Index = j;
-            BiosMemoryDescriptors[j].GeneratedDescriptor = TRUE;
-            j++;
-        }
+        /* Bail out, if everything is trimmed away */
+        if ((BasePage + PageCount) <= NextBase) return c;
 
-        //
-        // Remember how much descriptors we found
-        //
-        BiosMemoryMapEntryCount = j;
+        /* Trim the naew range at the lower end */
+        PageCount -= (NextBase - BasePage);
+        BasePage = NextBase;
 
-        //
-        // Mark memory map as already retrieved and initialized
-        //
-        MemoryMapInitialized = TRUE;
+        /* Go to the next entry and repeat */
+        i++;
     }
 
-    CurrentDescriptor = CONTAINING_RECORD(Current, MEMORY_DESCRIPTOR_INT, m);
+    ASSERT(PageCount > 0);
 
-    if (Current == NULL)
+    /* Are there still entries above? */
+    if (i < c)
     {
-        //
-        // First descriptor requested
-        //
-        if (BiosMemoryMapEntryCount > 0)
-        {
-            //
-            // Return first generated memory descriptor
-            //
-            return &BiosMemoryDescriptors[0].m;
-        }
-        else if (sizeof(MemoryDescriptors) > 0)
-        {
-            //
-            // Return first fixed memory descriptor
-            //
-            return &MemoryDescriptors[0].m;
-        }
-        else
+        /* Shift the following entries one up */
+        RtlMoveMemory(&List[i+1], &List[i], (c - i) * sizeof(List[0]));
+
+        /* Insert the new range */
+        List[i].BasePage = BasePage;
+        List[i].PageCount = min(PageCount, List[i+1].BasePage - BasePage);
+        List[i].MemoryType = MemoryType;
+        c++;
+
+        TRACE("Inserting at i=%ld: (0x%lx:0x%lx)\n",
+              i, List[i].BasePage, List[i].PageCount);
+
+        /* Check if the range was trimmed */
+        if (PageCount > List[i].PageCount)
         {
-            //
-            // Strange case, we have no memory descriptor
-            //
-            return NULL;
+            /* Recursively process the trimmed part */
+            c = AddMemoryDescriptor(List,
+                                    MaxCount,
+                                    BasePage + List[i].PageCount,
+                                    PageCount - List[i].PageCount,
+                                    MemoryType);
         }
     }
-    else if (CurrentDescriptor->GeneratedDescriptor)
+    else
     {
-        //
-        // Current entry is a generated descriptor
-        //
-        if (CurrentDescriptor->Index + 1 < BiosMemoryMapEntryCount)
-        {
-            //
-            // Return next generated descriptor
-            //
-            return &BiosMemoryDescriptors[CurrentDescriptor->Index + 1].m;
-        }
-        else if (sizeof(MemoryDescriptors) > 0)
-        {
-            //
-            // Return first fixed memory descriptor
-            //
-            return &MemoryDescriptors[0].m;
-        }
-        else
-        {
-            //
-            // No fixed memory descriptor; end of memory map
-            //
-            return NULL;
-        }
+        /* We can simply add the range here */
+        TRACE("Adding i=%ld: (0x%lx:0x%lx)\n", i, BasePage, PageCount);
+        List[i].BasePage = BasePage;
+        List[i].PageCount = PageCount;
+        List[i].MemoryType = MemoryType;
+        c++;
+    }
+
+    /* Return the new count */
+    return c;
+}
+
+const MEMORY_DESCRIPTOR*
+ArcGetMemoryDescriptor(const MEMORY_DESCRIPTOR* Current)
+{
+    if (Current == NULL)
+    {
+        return BiosMemoryMap;
     }
     else
     {
-        //
-        // Current entry is a fixed descriptor
-        //
-        if (CurrentDescriptor->Index + 1 < sizeof(MemoryDescriptors) / sizeof(MemoryDescriptors[0]))
-        {
-            //
-            // Return next fixed descriptor
-            //
-            return &MemoryDescriptors[CurrentDescriptor->Index + 1].m;
-        }
-        else
-        {
-            //
-            // No more fixed memory descriptor; end of memory map
-            //
-            return NULL;
-        }
+        Current++;
+        if (Current->PageCount == 0) return NULL;
+        return Current;
     }
 }
 
@@ -270,6 +165,8 @@ BOOLEAN MmInitializeMemoryManager(VOID)
 
        TRACE("Initializing Memory Manager.\n");
 
+    BiosMemoryMap = MachVtbl.GetMemoryMap(&BiosMemoryMapEntryCount);
+
 #if DBG
        // Dump the system memory map
        TRACE("System Memory Map (Base Address, Length, Type):\n");
@@ -298,6 +195,26 @@ BOOLEAN MmInitializeMemoryManager(VOID)
 
        // Initialize the page lookup table
        MmInitPageLookupTable(PageLookupTableAddress, TotalPagesInLookupTable);
+
+{
+    ULONG Type, Index, PrevIndex = 0;
+       PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTableAddress;
+
+    Type = RealPageLookupTable[0].PageAllocated;
+       for (Index = 1; Index < TotalPagesInLookupTable; Index++)
+       {
+           if ((RealPageLookupTable[Index].PageAllocated != Type) ||
+            (Index == TotalPagesInLookupTable - 1))
+           {
+            TRACE("Range: 0x%lx - 0x%lx Type=%d\n",
+                PrevIndex, Index - 1, Type);
+               Type = RealPageLookupTable[Index].PageAllocated;
+               PrevIndex = Index;
+           }
+       }
+}
+
+
        MmUpdateLastFreePageHint(PageLookupTableAddress, TotalPagesInLookupTable);
 
        FreePagesInLookupTable = MmCountFreePagesInLookupTable(PageLookupTableAddress, TotalPagesInLookupTable);
@@ -305,6 +222,8 @@ BOOLEAN MmInitializeMemoryManager(VOID)
        MmInitializeHeap(PageLookupTableAddress);
 
        TRACE("Memory Manager initialized. %d pages available.\n", FreePagesInLookupTable);
+
+
        return TRUE;
 }
 
@@ -359,7 +278,7 @@ ULONG MmGetAddressablePageCountIncludingHoles(VOID)
             //
             // Yes, remember it if this is real memory
             //
-            if (MemoryDescriptor->MemoryType == MemoryFree) MmLowestPhysicalPage = MemoryDescriptor->BasePage;
+            MmLowestPhysicalPage = MemoryDescriptor->BasePage;
         }
     }
 
@@ -467,6 +386,10 @@ VOID MmInitPageLookupTable(PVOID PageLookupTable, ULONG TotalPageCount)
     //
     while ((MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor)) != NULL)
     {
+        TRACE("Got range: 0x%lx-0x%lx, type=%s\n",
+              MemoryDescriptor->BasePage,
+              MemoryDescriptor->BasePage + MemoryDescriptor->PageCount,
+              MmGetSystemMemoryMapTypeString(MemoryDescriptor->MemoryType));
         //
         // Convert ARC memory type to loader memory type
         //
@@ -704,6 +627,9 @@ BOOLEAN MmAreMemoryPagesAvailable(PVOID PageLookupTable, ULONG TotalPageCount, P
        ULONG                                                   Index;
 
        StartPage = MmGetPageNumberFromAddress(PageAddress);
+
+       if (StartPage < MmLowestPhysicalPage) return FALSE;
+
     StartPage -= MmLowestPhysicalPage;
 
        // Make sure they aren't trying to go past the