Author: ros-arm-bringup Date: Fri Feb 15 02:39:31 2008 New Revision: 32368
URL: http://svn.reactos.org/svn/reactos?rev=32368&view=rev Log: 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).
Modified: trunk/reactos/ntoskrnl/include/internal/mm.h trunk/reactos/ntoskrnl/ke/i386/kiinit.c trunk/reactos/ntoskrnl/mm/freelist.c trunk/reactos/ntoskrnl/mm/mminit.c
Modified: trunk/reactos/ntoskrnl/include/internal/mm.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/m... ============================================================================== --- trunk/reactos/ntoskrnl/include/internal/mm.h (original) +++ trunk/reactos/ntoskrnl/include/internal/mm.h Fri Feb 15 02:39:31 2008 @@ -17,6 +17,11 @@
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; @@ -260,6 +265,29 @@ ULONG PagingRequestsInLastFiveMinutes; 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;
@@ -532,12 +560,8 @@ 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 @@ 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 );
Modified: trunk/reactos/ntoskrnl/ke/i386/kiinit.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/i386/kiinit.c?r... ============================================================================== --- trunk/reactos/ntoskrnl/ke/i386/kiinit.c (original) +++ trunk/reactos/ntoskrnl/ke/i386/kiinit.c Fri Feb 15 02:39:31 2008 @@ -537,12 +537,7 @@ ((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] =
Modified: trunk/reactos/ntoskrnl/mm/freelist.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/freelist.c?rev=... ============================================================================== --- trunk/reactos/ntoskrnl/mm/freelist.c (original) +++ trunk/reactos/ntoskrnl/mm/freelist.c Fri Feb 15 02:39:31 2008 @@ -25,29 +25,6 @@ #define MM_PHYSICAL_PAGE_FREE (0x1) #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 @@ return TRUE; }
- -PVOID -INIT_FUNCTION -NTAPI -MmInitializePageList(IN ULONG_PTR FirstPhysKernelAddress, - IN ULONG_PTR LastPhysKernelAddress, - IN ULONG HighestPage, - IN ULONG_PTR LastKernelAddress, - IN PADDRESS_RANGE BIOSMemoryMap, +VOID +NTAPI +MmInitializePageList(IN PADDRESS_RANGE BIOSMemoryMap, IN ULONG AddressRangeCount) { ULONG i; @@ -318,11 +289,11 @@ 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 @@ 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 @@ 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 @@
MmStats.NrTotalPages = MmStats.NrFreePages + MmStats.NrSystemPages + MmStats.NrUserPages; MmInitializeBalancer(MmStats.NrFreePages, MmStats.NrSystemPages); - return((PVOID)LastKernelAddress); }
VOID
Modified: trunk/reactos/ntoskrnl/mm/mminit.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/mminit.c?rev=32... ============================================================================== --- trunk/reactos/ntoskrnl/mm/mminit.c (original) +++ trunk/reactos/ntoskrnl/mm/mminit.c Fri Feb 15 02:39:31 2008 @@ -49,7 +49,10 @@ 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 @@ VOID INIT_FUNCTION NTAPI -MmInitVirtualMemory(ULONG_PTR LastKernelAddress, - ULONG KernelLength) +MmInitVirtualMemory() { PVOID BaseAddress; ULONG Length; @@ -80,24 +82,9 @@ 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); @@ -263,6 +250,32 @@
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, IN ULONG AddressRangeCount) { @@ -306,7 +319,7 @@ 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 @@ LastKrnlPhysAddr = Md->BasePage+Md->PageCount; } } - + /* Convert to a physical address */ return LastKrnlPhysAddr << PAGE_SHIFT; } @@ -328,16 +341,11 @@ VOID INIT_FUNCTION NTAPI -MmInit1(ULONG_PTR FirstKrnlPhysAddr, - ULONG_PTR LastKrnlPhysAddr, - ULONG_PTR LastKernelAddress, - PADDRESS_RANGE BIOSMemoryMap, - ULONG AddressRangeCount, - ULONG MaxMem) -{ - ULONG kernel_len; +MmInit1(IN PADDRESS_RANGE BIOSMemoryMap, + IN ULONG AddressRangeCount) +{ PLDR_DATA_TABLE_ENTRY LdrEntry; - + /* Dump memory descriptors */ if (MiDbgEnableMdDump) MiDbgDumpMemoryDescriptors(); if (MiDbgEnableMdDump) MiDbgDumpBiosMap(BIOSMemoryMap, AddressRangeCount); @@ -345,18 +353,9 @@ /* 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 @@ /* 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();