Review and fix the buildingg and mapping of boot-time kernel address space.
authorReactOS Portable Systems Group <ros-arm-bringup@svn.reactos.org>
Thu, 14 Feb 2008 23:39:31 +0000 (23:39 +0000)
committerReactOS Portable Systems Group <ros-arm-bringup@svn.reactos.org>
Thu, 14 Feb 2008 23:39:31 +0000 (23:39 +0000)
The selection of the non-paged pool base address was broken (ion's comment was correct, but his implementation was not) -- NP pool now follows the PFN, or end of FreeLDR mapping area.
There was no reason to put paged pool at a 4MB boundary away from NP pool -- it now follows it immediately.
Got rid of multiple values which were calculated 3, even 4 times in a row, or even values that were calculated but never used (such as kernel_len).
Got rid of the shuffling back and forth of kernel and virtual start/end addresses. A global now keeps track of this, and MmInit1 is now solely responsible for assigning addresses to each kernel region.
Added new debug routine to show the kernel regions mapped -- enabled by default for now to visually detect any problems (once ReactOS's drivers go over 6MB, there may be).

svn path=/trunk/; revision=32368

reactos/ntoskrnl/include/internal/mm.h
reactos/ntoskrnl/ke/i386/kiinit.c
reactos/ntoskrnl/mm/freelist.c
reactos/ntoskrnl/mm/mminit.c

index ce4da08..576e58c 100644 (file)
@@ -18,6 +18,11 @@ extern ULONG MmNumberOfPhysicalPages;
 extern PVOID MmPagedPoolBase;
 extern ULONG MmPagedPoolSize;
 
+extern PMEMORY_ALLOCATION_DESCRIPTOR MiFreeDescriptor;
+extern ULONG MmHighestPhysicalPage;
+extern PVOID MmPfnDatabase;
+extern ULONG_PTR MiKSeg0Start, MiKSeg0End;
+
 struct _KTRAP_FRAME;
 struct _EPROCESS;
 struct _MM_RMAP_ENTRY;
@@ -261,6 +266,29 @@ typedef struct
     ULONG PagingRequestsInLastFifteenMinutes;
 } MM_STATS;
 
+typedef struct _PHYSICAL_PAGE
+{
+    union
+    {
+        struct
+        {
+            ULONG Type: 2;
+            ULONG Consumer: 3;
+            ULONG Zero: 1;
+        }
+        Flags;
+        ULONG AllFlags;
+    };
+    
+    LIST_ENTRY ListEntry;
+    ULONG ReferenceCount;
+    SWAPENTRY SavedSwapEntry;
+    ULONG LockCount;
+    ULONG MapCount;
+    struct _MM_RMAP_ENTRY* RmapListHead;
+}
+PHYSICAL_PAGE, *PPHYSICAL_PAGE;
+
 extern MM_STATS MmStats;
 
 typedef struct _MM_PAGEOP
@@ -532,12 +560,8 @@ MiShutdownMemoryManager(VOID);
 VOID
 NTAPI
 MmInit1(
-    ULONG_PTR FirstKernelPhysAddress,
-    ULONG_PTR LastKernelPhysAddress,
-    ULONG_PTR LastKernelAddress,
     PADDRESS_RANGE BIOSMemoryMap,
-    ULONG AddressRangeCount,
-    ULONG MaxMemInMeg
+    ULONG AddressRangeCount
 );
 
 BOOLEAN
@@ -941,13 +965,9 @@ ULONG
 NTAPI
 MmGetLockCountPage(PFN_TYPE Page);
 
-PVOID
+VOID
 NTAPI
 MmInitializePageList(
-    ULONG_PTR FirstPhysKernelAddress,
-    ULONG_PTR LastPhysKernelAddress,
-    ULONG MemorySizeInPages,
-    ULONG_PTR LastKernelBase,
     PADDRESS_RANGE BIOSMemoryMap,
     ULONG AddressRangeCount
 );
index 1ac5c12..d47c43c 100644 (file)
@@ -537,12 +537,7 @@ KiInitializeKernel(IN PKPROCESS InitProcess,
     ((PETHREAD)InitThread)->ThreadsProcess = (PEPROCESS)InitProcess;
 
     /* Initialize Kernel Memory Address Space */
-    MmInit1(MmFreeLdrFirstKrnlPhysAddr,
-            MmFreeLdrLastKrnlPhysAddr,
-            MmFreeLdrLastKernelAddress,
-            KeMemoryMap,
-            KeMemoryMapRangeCount,
-            4096);
+    MmInit1(KeMemoryMap, KeMemoryMapRangeCount);
 
     /* Set basic CPU Features that user mode can read */
     SharedUserData->ProcessorFeatures[PF_MMX_INSTRUCTIONS_AVAILABLE] =
index a47efb1..812ef61 100644 (file)
 #define MM_PHYSICAL_PAGE_USED    (0x2)
 #define MM_PHYSICAL_PAGE_BIOS    (0x3)
 
-typedef struct _PHYSICAL_PAGE
-{
-   union
-   {
-      struct
-      {
-        ULONG Type: 2;
-        ULONG Consumer: 3;
-       ULONG Zero: 1;
-      }
-      Flags;
-      ULONG AllFlags;
-   };
-
-   LIST_ENTRY ListEntry;
-   ULONG ReferenceCount;
-   SWAPENTRY SavedSwapEntry;
-   ULONG LockCount;
-   ULONG MapCount;
-   struct _MM_RMAP_ENTRY* RmapListHead;
-}
-PHYSICAL_PAGE, *PPHYSICAL_PAGE;
-
 
 #define ASSERT_PFN(x) ASSERT((x)->Flags.Type != 0)
 
@@ -302,15 +279,9 @@ MiIsPfnRam(PADDRESS_RANGE BIOSMemoryMap,
    return TRUE;
 }
 
-
-PVOID
-INIT_FUNCTION
+VOID
 NTAPI
-MmInitializePageList(IN ULONG_PTR FirstPhysKernelAddress,
-                     IN ULONG_PTR LastPhysKernelAddress,
-                     IN ULONG HighestPage,
-                     IN ULONG_PTR LastKernelAddress,
-                     IN PADDRESS_RANGE BIOSMemoryMap,
+MmInitializePageList(IN PADDRESS_RANGE BIOSMemoryMap,
                      IN ULONG AddressRangeCount)
 {
     ULONG i;
@@ -318,11 +289,11 @@ MmInitializePageList(IN ULONG_PTR FirstPhysKernelAddress,
     NTSTATUS Status;
     PFN_TYPE Pfn = 0;
     PHYSICAL_PAGE UsedPage;
-    extern PMEMORY_ALLOCATION_DESCRIPTOR MiFreeDescriptor;
     ULONG PdeStart = PsGetCurrentProcess()->Pcb.DirectoryTableBase.LowPart;
     ULONG PdePageStart, PdePageEnd;
     ULONG VideoPageStart, VideoPageEnd;
     ULONG KernelPageStart, KernelPageEnd;
+    ULONG_PTR KernelStart, KernelEnd;
 
     /* Initialize the page lists */
     KeInitializeSpinLock(&PageListLock);
@@ -331,13 +302,9 @@ MmInitializePageList(IN ULONG_PTR FirstPhysKernelAddress,
     InitializeListHead(&FreeZeroedPageListHead);
  
     /* Set the size and start of the PFN Database */
-    MmPageArraySize = HighestPage;
-    MmPageArray = (PHYSICAL_PAGE *)LastKernelAddress;
+    MmPageArray = (PHYSICAL_PAGE *)MmPfnDatabase;
+    MmPageArraySize = MmHighestPhysicalPage;
     Reserved = PAGE_ROUND_UP((MmPageArraySize * sizeof(PHYSICAL_PAGE))) / PAGE_SIZE;
-    
-    /* Update the last kernel address pointers */
-    LastKernelAddress = ((ULONG_PTR)LastKernelAddress + (Reserved * PAGE_SIZE));
-    LastPhysKernelAddress = (ULONG_PTR)LastPhysKernelAddress + (Reserved * PAGE_SIZE);
 
     /* Loop every page required to hold the PFN database */
     for (i = 0; i < Reserved; i++)
@@ -380,12 +347,14 @@ MmInitializePageList(IN ULONG_PTR FirstPhysKernelAddress,
     UsedPage.MapCount = 1;
 
     /* We'll be applying a bunch of hacks -- precompute some static values */
+    KernelStart = MiKSeg0Start - KSEG0_BASE;
+    KernelEnd = MiKSeg0End - KSEG0_BASE;
     PdePageStart = PdeStart / PAGE_SIZE;
     PdePageEnd = MmFreeLdrPageDirectoryEnd / PAGE_SIZE;
     VideoPageStart = 0xA0000 / PAGE_SIZE;
     VideoPageEnd = 0x100000 / PAGE_SIZE;
-    KernelPageStart = FirstPhysKernelAddress / PAGE_SIZE;
-    KernelPageEnd = LastPhysKernelAddress / PAGE_SIZE;
+    KernelPageStart = KernelStart / PAGE_SIZE;
+    KernelPageEnd = KernelEnd / PAGE_SIZE;
     
     /* Loop every page on the system */
     for (i = 0; i <= MmPageArraySize; i++)
@@ -470,7 +439,6 @@ MmInitializePageList(IN ULONG_PTR FirstPhysKernelAddress,
     
     MmStats.NrTotalPages = MmStats.NrFreePages + MmStats.NrSystemPages + MmStats.NrUserPages;
     MmInitializeBalancer(MmStats.NrFreePages, MmStats.NrSystemPages);
-    return((PVOID)LastKernelAddress);
 }
 
 VOID
index 1f45536..9f48108 100644 (file)
@@ -49,7 +49,10 @@ MM_SYSTEMSIZE MmSystemSize = MmSmallSystem;
 PHYSICAL_ADDRESS MmSharedDataPagePhysicalAddress;
 PVOID MiNonPagedPoolStart;
 ULONG MiNonPagedPoolLength;
+ULONG MmBootImageSize;
 ULONG MmNumberOfPhysicalPages, MmHighestPhysicalPage, MmLowestPhysicalPage;
+ULONG_PTR MiKSeg0Start, MiKSeg0End;
+PVOID MmPfnDatabase;
 PMEMORY_ALLOCATION_DESCRIPTOR MiFreeDescriptor;
 extern KMUTANT MmSystemLoadLock;
 BOOLEAN MiDbgEnableMdDump =
@@ -71,8 +74,7 @@ MiShutdownMemoryManager(VOID)
 VOID
 INIT_FUNCTION
 NTAPI
-MmInitVirtualMemory(ULONG_PTR LastKernelAddress,
-                    ULONG KernelLength)
+MmInitVirtualMemory()
 {
    PVOID BaseAddress;
    ULONG Length;
@@ -80,25 +82,10 @@ MmInitVirtualMemory(ULONG_PTR LastKernelAddress,
    PHYSICAL_ADDRESS BoundaryAddressMultiple;
    PMEMORY_AREA MArea;
 
-   DPRINT("MmInitVirtualMemory(%x, %x)\n",LastKernelAddress, KernelLength);
-
    BoundaryAddressMultiple.QuadPart = 0;
-   LastKernelAddress = PAGE_ROUND_UP(LastKernelAddress);
 
    MmInitMemoryAreas();
 
-   /*
-    * FreeLDR Marks 6MB "in use" at the start of the kernel base,
-    * so start the non-paged pool at a boundary of 6MB from where
-    * the last driver was loaded. This should be the end of the
-    * FreeLDR-marked region.
-    */
-   MiNonPagedPoolStart = (PVOID)ROUND_UP((ULONG_PTR)LastKernelAddress + PAGE_SIZE, 0x600000);
-   MiNonPagedPoolLength = MM_NONPAGED_POOL_SIZE;
-
-   MmPagedPoolBase = (PVOID)ROUND_UP((ULONG_PTR)MiNonPagedPoolStart + MiNonPagedPoolLength + PAGE_SIZE, 0x400000);
-   MmPagedPoolSize = MM_PAGED_POOL_SIZE;
-
    DPRINT("NonPagedPool %x - %x, PagedPool %x - %x\n", MiNonPagedPoolStart, (ULONG_PTR)MiNonPagedPoolStart + MiNonPagedPoolLength - 1,
            MmPagedPoolBase, (ULONG_PTR)MmPagedPoolBase + MmPagedPoolSize - 1);
 
@@ -261,6 +248,32 @@ MiCountFreePagesInLoaderBlock(PLOADER_PARAMETER_BLOCK LoaderBlock)
     }
 }
 
+VOID
+NTAPI
+MiDbgKernelLayout(VOID)
+{
+    DPRINT1("%8s%12s\t\t%s\n", "Start", "End", "Type");
+    DPRINT1("0x%p - 0x%p\t%s\n",
+            KSEG0_BASE, MiKSeg0Start,
+            "Undefined region");
+    DPRINT1("0x%p - 0x%p\t%s\n",
+            MiKSeg0Start, MmPfnDatabase,
+            "FreeLDR Kernel mapping region");
+    DPRINT1("0x%p - 0x%p\t%s\n",
+            MmPfnDatabase, MiKSeg0End,
+            "PFN Database region");
+    if (MiKSeg0End != (ULONG_PTR)MiNonPagedPoolStart)
+    DPRINT1("0x%p - 0x%p\t%s\n",
+            MiKSeg0End, MiNonPagedPoolStart,
+            "Remaining FreeLDR mapping");
+    DPRINT1("0x%p - 0x%p\t%s\n",
+             MiNonPagedPoolStart, (ULONG_PTR)MiNonPagedPoolStart + MiNonPagedPoolLength,
+            "Non paged pool region");
+    DPRINT1("0x%p - 0x%p\t%s\n",
+            MmPagedPoolBase, (ULONG_PTR)MmPagedPoolBase + MmPagedPoolSize,
+            "Paged pool region");
+}
+
 VOID
 NTAPI
 MiDbgDumpBiosMap(IN PADDRESS_RANGE BIOSMemoryMap,
@@ -306,7 +319,7 @@ MiGetLastKernelAddress(VOID)
     PLIST_ENTRY NextEntry;
     PMEMORY_ALLOCATION_DESCRIPTOR Md;
     ULONG_PTR LastKrnlPhysAddr = 0;
-        
+    
     for (NextEntry = KeLoaderBlock->MemoryDescriptorListHead.Flink;
          NextEntry != &KeLoaderBlock->MemoryDescriptorListHead;
          NextEntry = NextEntry->Flink)
@@ -320,7 +333,7 @@ MiGetLastKernelAddress(VOID)
                 LastKrnlPhysAddr = Md->BasePage+Md->PageCount;   
         }
     }
-
+    
     /* Convert to a physical address */
     return LastKrnlPhysAddr << PAGE_SHIFT;
 }
@@ -328,16 +341,11 @@ MiGetLastKernelAddress(VOID)
 VOID
 INIT_FUNCTION
 NTAPI
-MmInit1(ULONG_PTR FirstKrnlPhysAddr,
-        ULONG_PTR LastKrnlPhysAddr,
-        ULONG_PTR LastKernelAddress,
-        PADDRESS_RANGE BIOSMemoryMap,
-        ULONG AddressRangeCount,
-        ULONG MaxMem)
+MmInit1(IN PADDRESS_RANGE BIOSMemoryMap,
+        IN ULONG AddressRangeCount)
 {
-    ULONG kernel_len;
     PLDR_DATA_TABLE_ENTRY LdrEntry;
-
+    
     /* Dump memory descriptors */
     if (MiDbgEnableMdDump) MiDbgDumpMemoryDescriptors();
     if (MiDbgEnableMdDump) MiDbgDumpBiosMap(BIOSMemoryMap, AddressRangeCount);
@@ -345,18 +353,9 @@ MmInit1(ULONG_PTR FirstKrnlPhysAddr,
     /* Set the page directory */
     PsGetCurrentProcess()->Pcb.DirectoryTableBase.LowPart = (ULONG)MmGetPageDirectory();
 
-    /* NTLDR Hacks */
-    if (!MmFreeLdrPageDirectoryEnd) MmFreeLdrPageDirectoryEnd = 0x40000;
-
-    /* Get the first physical address */
-    LdrEntry = CONTAINING_RECORD(KeLoaderBlock->LoadOrderListHead.Flink,
-                                 LDR_DATA_TABLE_ENTRY,
-                                 InLoadOrderLinks);
-    FirstKrnlPhysAddr = (ULONG_PTR)LdrEntry->DllBase - KSEG0_BASE;
-
-    /* Get the last kernel address */ 
-    LastKrnlPhysAddr = PAGE_ROUND_UP(MiGetLastKernelAddress());
-    LastKernelAddress = LastKrnlPhysAddr | KSEG0_BASE;
+    /* Get the size of FreeLDR's image allocations */
+    MmBootImageSize = KeLoaderBlock->Extension->LoaderPagesSpanned;
+    MmBootImageSize *= PAGE_SIZE;
 
     /* Set memory limits */
     MmSystemRangeStart = (PVOID)KSEG0_BASE;
@@ -377,21 +376,55 @@ MmInit1(ULONG_PTR FirstKrnlPhysAddr,
     /* Initialize the kernel address space */
     MmInitializeKernelAddressSpace();
     MmInitGlobalKernelPageDirectory();
+    
+    /* Get kernel address boundaries */
+    LdrEntry = CONTAINING_RECORD(KeLoaderBlock->LoadOrderListHead.Flink,
+                                 LDR_DATA_TABLE_ENTRY,
+                                 InLoadOrderLinks);
+    MiKSeg0Start = (ULONG_PTR)LdrEntry->DllBase | KSEG0_BASE;
+    MiKSeg0End = PAGE_ROUND_UP(MiGetLastKernelAddress()  | KSEG0_BASE);
+
+    /* We'll put the PFN array right after the loaded modules */
+    MmPfnDatabase = (PVOID)MiKSeg0End;
+    MiKSeg0End += MmHighestPhysicalPage * sizeof(PHYSICAL_PAGE);
+    MiKSeg0End = PAGE_ROUND_UP(MiKSeg0End);
+    
+    /*
+     * FreeLDR maps 6MB starting at the kernel base address, followed by the
+     * PFN database. If the PFN database doesn't go over the FreeLDR allocation
+     * then choose the end of the FreeLDR block. If it does go past the FreeLDR
+     * allocation, then choose the next PAGE_SIZE boundary.
+     */
+    if (MiKSeg0End < (MiKSeg0Start + 0x600000))
+    {
+        /* Use the first memory following FreeLDR's 6MB mapping */
+        MiNonPagedPoolStart = (PVOID)PAGE_ROUND_UP(MiKSeg0Start + 0x600000);
+    }
+    else
+    {
+        /* Use the next free available page */
+        MiNonPagedPoolStart = (PVOID)MiKSeg0End;
+    }
+    
+    /* Length of non-paged pool */
+    MiNonPagedPoolLength = MM_NONPAGED_POOL_SIZE;
 
+    /* Put the paged pool after the non-paged pool */
+    MmPagedPoolBase = (PVOID)PAGE_ROUND_UP((ULONG_PTR)MiNonPagedPoolStart +
+                                           MiNonPagedPoolLength);
+    MmPagedPoolSize = MM_PAGED_POOL_SIZE;
+    
+    /* Dump kernel memory layout */
+    MiDbgKernelLayout();
+    
     /* Initialize the page list */
-    LastKernelAddress = (ULONG_PTR)MmInitializePageList(FirstKrnlPhysAddr,
-                                                        LastKrnlPhysAddr,
-                                                        MmHighestPhysicalPage,
-                                                        PAGE_ROUND_UP(LastKernelAddress),
-                                                        BIOSMemoryMap,
-                                                        AddressRangeCount);
-    kernel_len = LastKrnlPhysAddr - FirstKrnlPhysAddr;
+    MmInitializePageList(BIOSMemoryMap, AddressRangeCount);
     
     /* Unmap low memory */
     MmDeletePageTable(NULL, 0);
 
     /* Intialize memory areas */
-    MmInitVirtualMemory(LastKernelAddress, kernel_len);
+    MmInitVirtualMemory();
 
     /* Initialize MDLs */
     MmInitializeMdlImplementation();