From 131f74225c804624046460120b924d029d62c9a7 Mon Sep 17 00:00:00 2001 From: ReactOS Portable Systems Group Date: Thu, 14 Feb 2008 23:39:31 +0000 Subject: [PATCH] Review and fix the buildingg and mapping of boot-time kernel address space. 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 | 40 ++++++-- reactos/ntoskrnl/ke/i386/kiinit.c | 7 +- reactos/ntoskrnl/mm/freelist.c | 50 ++-------- reactos/ntoskrnl/mm/mminit.c | 127 ++++++++++++++++--------- 4 files changed, 120 insertions(+), 104 deletions(-) diff --git a/reactos/ntoskrnl/include/internal/mm.h b/reactos/ntoskrnl/include/internal/mm.h index ce4da08a592..576e58c63a4 100644 --- a/reactos/ntoskrnl/include/internal/mm.h +++ b/reactos/ntoskrnl/include/internal/mm.h @@ -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 ); diff --git a/reactos/ntoskrnl/ke/i386/kiinit.c b/reactos/ntoskrnl/ke/i386/kiinit.c index 1ac5c1229ee..d47c43cb512 100644 --- a/reactos/ntoskrnl/ke/i386/kiinit.c +++ b/reactos/ntoskrnl/ke/i386/kiinit.c @@ -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] = diff --git a/reactos/ntoskrnl/mm/freelist.c b/reactos/ntoskrnl/mm/freelist.c index a47efb1f28a..812ef613535 100644 --- a/reactos/ntoskrnl/mm/freelist.c +++ b/reactos/ntoskrnl/mm/freelist.c @@ -26,29 +26,6 @@ #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 diff --git a/reactos/ntoskrnl/mm/mminit.c b/reactos/ntoskrnl/mm/mminit.c index 1f455360d4e..9f481082488 100644 --- a/reactos/ntoskrnl/mm/mminit.c +++ b/reactos/ntoskrnl/mm/mminit.c @@ -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();