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
This commit is contained in:
ReactOS Portable Systems Group 2008-02-14 23:39:31 +00:00
parent 6b9215e607
commit 131f74225c
4 changed files with 120 additions and 104 deletions

View file

@ -18,6 +18,11 @@ extern ULONG MmNumberOfPhysicalPages;
extern PVOID MmPagedPoolBase; extern PVOID MmPagedPoolBase;
extern ULONG MmPagedPoolSize; extern ULONG MmPagedPoolSize;
extern PMEMORY_ALLOCATION_DESCRIPTOR MiFreeDescriptor;
extern ULONG MmHighestPhysicalPage;
extern PVOID MmPfnDatabase;
extern ULONG_PTR MiKSeg0Start, MiKSeg0End;
struct _KTRAP_FRAME; struct _KTRAP_FRAME;
struct _EPROCESS; struct _EPROCESS;
struct _MM_RMAP_ENTRY; struct _MM_RMAP_ENTRY;
@ -261,6 +266,29 @@ typedef struct
ULONG PagingRequestsInLastFifteenMinutes; ULONG PagingRequestsInLastFifteenMinutes;
} MM_STATS; } 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; extern MM_STATS MmStats;
typedef struct _MM_PAGEOP typedef struct _MM_PAGEOP
@ -532,12 +560,8 @@ MiShutdownMemoryManager(VOID);
VOID VOID
NTAPI NTAPI
MmInit1( MmInit1(
ULONG_PTR FirstKernelPhysAddress,
ULONG_PTR LastKernelPhysAddress,
ULONG_PTR LastKernelAddress,
PADDRESS_RANGE BIOSMemoryMap, PADDRESS_RANGE BIOSMemoryMap,
ULONG AddressRangeCount, ULONG AddressRangeCount
ULONG MaxMemInMeg
); );
BOOLEAN BOOLEAN
@ -941,13 +965,9 @@ ULONG
NTAPI NTAPI
MmGetLockCountPage(PFN_TYPE Page); MmGetLockCountPage(PFN_TYPE Page);
PVOID VOID
NTAPI NTAPI
MmInitializePageList( MmInitializePageList(
ULONG_PTR FirstPhysKernelAddress,
ULONG_PTR LastPhysKernelAddress,
ULONG MemorySizeInPages,
ULONG_PTR LastKernelBase,
PADDRESS_RANGE BIOSMemoryMap, PADDRESS_RANGE BIOSMemoryMap,
ULONG AddressRangeCount ULONG AddressRangeCount
); );

View file

@ -537,12 +537,7 @@ KiInitializeKernel(IN PKPROCESS InitProcess,
((PETHREAD)InitThread)->ThreadsProcess = (PEPROCESS)InitProcess; ((PETHREAD)InitThread)->ThreadsProcess = (PEPROCESS)InitProcess;
/* Initialize Kernel Memory Address Space */ /* Initialize Kernel Memory Address Space */
MmInit1(MmFreeLdrFirstKrnlPhysAddr, MmInit1(KeMemoryMap, KeMemoryMapRangeCount);
MmFreeLdrLastKrnlPhysAddr,
MmFreeLdrLastKernelAddress,
KeMemoryMap,
KeMemoryMapRangeCount,
4096);
/* Set basic CPU Features that user mode can read */ /* Set basic CPU Features that user mode can read */
SharedUserData->ProcessorFeatures[PF_MMX_INSTRUCTIONS_AVAILABLE] = SharedUserData->ProcessorFeatures[PF_MMX_INSTRUCTIONS_AVAILABLE] =

View file

@ -26,29 +26,6 @@
#define MM_PHYSICAL_PAGE_USED (0x2) #define MM_PHYSICAL_PAGE_USED (0x2)
#define MM_PHYSICAL_PAGE_BIOS (0x3) #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) #define ASSERT_PFN(x) ASSERT((x)->Flags.Type != 0)
@ -302,15 +279,9 @@ MiIsPfnRam(PADDRESS_RANGE BIOSMemoryMap,
return TRUE; return TRUE;
} }
VOID
PVOID
INIT_FUNCTION
NTAPI NTAPI
MmInitializePageList(IN ULONG_PTR FirstPhysKernelAddress, MmInitializePageList(IN PADDRESS_RANGE BIOSMemoryMap,
IN ULONG_PTR LastPhysKernelAddress,
IN ULONG HighestPage,
IN ULONG_PTR LastKernelAddress,
IN PADDRESS_RANGE BIOSMemoryMap,
IN ULONG AddressRangeCount) IN ULONG AddressRangeCount)
{ {
ULONG i; ULONG i;
@ -318,11 +289,11 @@ MmInitializePageList(IN ULONG_PTR FirstPhysKernelAddress,
NTSTATUS Status; NTSTATUS Status;
PFN_TYPE Pfn = 0; PFN_TYPE Pfn = 0;
PHYSICAL_PAGE UsedPage; PHYSICAL_PAGE UsedPage;
extern PMEMORY_ALLOCATION_DESCRIPTOR MiFreeDescriptor;
ULONG PdeStart = PsGetCurrentProcess()->Pcb.DirectoryTableBase.LowPart; ULONG PdeStart = PsGetCurrentProcess()->Pcb.DirectoryTableBase.LowPart;
ULONG PdePageStart, PdePageEnd; ULONG PdePageStart, PdePageEnd;
ULONG VideoPageStart, VideoPageEnd; ULONG VideoPageStart, VideoPageEnd;
ULONG KernelPageStart, KernelPageEnd; ULONG KernelPageStart, KernelPageEnd;
ULONG_PTR KernelStart, KernelEnd;
/* Initialize the page lists */ /* Initialize the page lists */
KeInitializeSpinLock(&PageListLock); KeInitializeSpinLock(&PageListLock);
@ -331,13 +302,9 @@ MmInitializePageList(IN ULONG_PTR FirstPhysKernelAddress,
InitializeListHead(&FreeZeroedPageListHead); InitializeListHead(&FreeZeroedPageListHead);
/* Set the size and start of the PFN Database */ /* Set the size and start of the PFN Database */
MmPageArraySize = HighestPage; MmPageArray = (PHYSICAL_PAGE *)MmPfnDatabase;
MmPageArray = (PHYSICAL_PAGE *)LastKernelAddress; MmPageArraySize = MmHighestPhysicalPage;
Reserved = PAGE_ROUND_UP((MmPageArraySize * sizeof(PHYSICAL_PAGE))) / PAGE_SIZE; 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 */ /* Loop every page required to hold the PFN database */
for (i = 0; i < Reserved; i++) for (i = 0; i < Reserved; i++)
@ -380,12 +347,14 @@ MmInitializePageList(IN ULONG_PTR FirstPhysKernelAddress,
UsedPage.MapCount = 1; UsedPage.MapCount = 1;
/* We'll be applying a bunch of hacks -- precompute some static values */ /* We'll be applying a bunch of hacks -- precompute some static values */
KernelStart = MiKSeg0Start - KSEG0_BASE;
KernelEnd = MiKSeg0End - KSEG0_BASE;
PdePageStart = PdeStart / PAGE_SIZE; PdePageStart = PdeStart / PAGE_SIZE;
PdePageEnd = MmFreeLdrPageDirectoryEnd / PAGE_SIZE; PdePageEnd = MmFreeLdrPageDirectoryEnd / PAGE_SIZE;
VideoPageStart = 0xA0000 / PAGE_SIZE; VideoPageStart = 0xA0000 / PAGE_SIZE;
VideoPageEnd = 0x100000 / PAGE_SIZE; VideoPageEnd = 0x100000 / PAGE_SIZE;
KernelPageStart = FirstPhysKernelAddress / PAGE_SIZE; KernelPageStart = KernelStart / PAGE_SIZE;
KernelPageEnd = LastPhysKernelAddress / PAGE_SIZE; KernelPageEnd = KernelEnd / PAGE_SIZE;
/* Loop every page on the system */ /* Loop every page on the system */
for (i = 0; i <= MmPageArraySize; i++) for (i = 0; i <= MmPageArraySize; i++)
@ -470,7 +439,6 @@ MmInitializePageList(IN ULONG_PTR FirstPhysKernelAddress,
MmStats.NrTotalPages = MmStats.NrFreePages + MmStats.NrSystemPages + MmStats.NrUserPages; MmStats.NrTotalPages = MmStats.NrFreePages + MmStats.NrSystemPages + MmStats.NrUserPages;
MmInitializeBalancer(MmStats.NrFreePages, MmStats.NrSystemPages); MmInitializeBalancer(MmStats.NrFreePages, MmStats.NrSystemPages);
return((PVOID)LastKernelAddress);
} }
VOID VOID

View file

@ -49,7 +49,10 @@ MM_SYSTEMSIZE MmSystemSize = MmSmallSystem;
PHYSICAL_ADDRESS MmSharedDataPagePhysicalAddress; PHYSICAL_ADDRESS MmSharedDataPagePhysicalAddress;
PVOID MiNonPagedPoolStart; PVOID MiNonPagedPoolStart;
ULONG MiNonPagedPoolLength; ULONG MiNonPagedPoolLength;
ULONG MmBootImageSize;
ULONG MmNumberOfPhysicalPages, MmHighestPhysicalPage, MmLowestPhysicalPage; ULONG MmNumberOfPhysicalPages, MmHighestPhysicalPage, MmLowestPhysicalPage;
ULONG_PTR MiKSeg0Start, MiKSeg0End;
PVOID MmPfnDatabase;
PMEMORY_ALLOCATION_DESCRIPTOR MiFreeDescriptor; PMEMORY_ALLOCATION_DESCRIPTOR MiFreeDescriptor;
extern KMUTANT MmSystemLoadLock; extern KMUTANT MmSystemLoadLock;
BOOLEAN MiDbgEnableMdDump = BOOLEAN MiDbgEnableMdDump =
@ -71,8 +74,7 @@ MiShutdownMemoryManager(VOID)
VOID VOID
INIT_FUNCTION INIT_FUNCTION
NTAPI NTAPI
MmInitVirtualMemory(ULONG_PTR LastKernelAddress, MmInitVirtualMemory()
ULONG KernelLength)
{ {
PVOID BaseAddress; PVOID BaseAddress;
ULONG Length; ULONG Length;
@ -80,25 +82,10 @@ MmInitVirtualMemory(ULONG_PTR LastKernelAddress,
PHYSICAL_ADDRESS BoundaryAddressMultiple; PHYSICAL_ADDRESS BoundaryAddressMultiple;
PMEMORY_AREA MArea; PMEMORY_AREA MArea;
DPRINT("MmInitVirtualMemory(%x, %x)\n",LastKernelAddress, KernelLength);
BoundaryAddressMultiple.QuadPart = 0; BoundaryAddressMultiple.QuadPart = 0;
LastKernelAddress = PAGE_ROUND_UP(LastKernelAddress);
MmInitMemoryAreas(); 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, DPRINT("NonPagedPool %x - %x, PagedPool %x - %x\n", MiNonPagedPoolStart, (ULONG_PTR)MiNonPagedPoolStart + MiNonPagedPoolLength - 1,
MmPagedPoolBase, (ULONG_PTR)MmPagedPoolBase + MmPagedPoolSize - 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 VOID
NTAPI NTAPI
MiDbgDumpBiosMap(IN PADDRESS_RANGE BIOSMemoryMap, MiDbgDumpBiosMap(IN PADDRESS_RANGE BIOSMemoryMap,
@ -306,7 +319,7 @@ MiGetLastKernelAddress(VOID)
PLIST_ENTRY NextEntry; PLIST_ENTRY NextEntry;
PMEMORY_ALLOCATION_DESCRIPTOR Md; PMEMORY_ALLOCATION_DESCRIPTOR Md;
ULONG_PTR LastKrnlPhysAddr = 0; ULONG_PTR LastKrnlPhysAddr = 0;
for (NextEntry = KeLoaderBlock->MemoryDescriptorListHead.Flink; for (NextEntry = KeLoaderBlock->MemoryDescriptorListHead.Flink;
NextEntry != &KeLoaderBlock->MemoryDescriptorListHead; NextEntry != &KeLoaderBlock->MemoryDescriptorListHead;
NextEntry = NextEntry->Flink) NextEntry = NextEntry->Flink)
@ -320,7 +333,7 @@ MiGetLastKernelAddress(VOID)
LastKrnlPhysAddr = Md->BasePage+Md->PageCount; LastKrnlPhysAddr = Md->BasePage+Md->PageCount;
} }
} }
/* Convert to a physical address */ /* Convert to a physical address */
return LastKrnlPhysAddr << PAGE_SHIFT; return LastKrnlPhysAddr << PAGE_SHIFT;
} }
@ -328,16 +341,11 @@ MiGetLastKernelAddress(VOID)
VOID VOID
INIT_FUNCTION INIT_FUNCTION
NTAPI NTAPI
MmInit1(ULONG_PTR FirstKrnlPhysAddr, MmInit1(IN PADDRESS_RANGE BIOSMemoryMap,
ULONG_PTR LastKrnlPhysAddr, IN ULONG AddressRangeCount)
ULONG_PTR LastKernelAddress,
PADDRESS_RANGE BIOSMemoryMap,
ULONG AddressRangeCount,
ULONG MaxMem)
{ {
ULONG kernel_len;
PLDR_DATA_TABLE_ENTRY LdrEntry; PLDR_DATA_TABLE_ENTRY LdrEntry;
/* Dump memory descriptors */ /* Dump memory descriptors */
if (MiDbgEnableMdDump) MiDbgDumpMemoryDescriptors(); if (MiDbgEnableMdDump) MiDbgDumpMemoryDescriptors();
if (MiDbgEnableMdDump) MiDbgDumpBiosMap(BIOSMemoryMap, AddressRangeCount); if (MiDbgEnableMdDump) MiDbgDumpBiosMap(BIOSMemoryMap, AddressRangeCount);
@ -345,18 +353,9 @@ MmInit1(ULONG_PTR FirstKrnlPhysAddr,
/* Set the page directory */ /* Set the page directory */
PsGetCurrentProcess()->Pcb.DirectoryTableBase.LowPart = (ULONG)MmGetPageDirectory(); PsGetCurrentProcess()->Pcb.DirectoryTableBase.LowPart = (ULONG)MmGetPageDirectory();
/* NTLDR Hacks */ /* Get the size of FreeLDR's image allocations */
if (!MmFreeLdrPageDirectoryEnd) MmFreeLdrPageDirectoryEnd = 0x40000; MmBootImageSize = KeLoaderBlock->Extension->LoaderPagesSpanned;
MmBootImageSize *= PAGE_SIZE;
/* 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;
/* Set memory limits */ /* Set memory limits */
MmSystemRangeStart = (PVOID)KSEG0_BASE; MmSystemRangeStart = (PVOID)KSEG0_BASE;
@ -377,21 +376,55 @@ MmInit1(ULONG_PTR FirstKrnlPhysAddr,
/* Initialize the kernel address space */ /* Initialize the kernel address space */
MmInitializeKernelAddressSpace(); MmInitializeKernelAddressSpace();
MmInitGlobalKernelPageDirectory(); 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 */ /* Initialize the page list */
LastKernelAddress = (ULONG_PTR)MmInitializePageList(FirstKrnlPhysAddr, MmInitializePageList(BIOSMemoryMap, AddressRangeCount);
LastKrnlPhysAddr,
MmHighestPhysicalPage,
PAGE_ROUND_UP(LastKernelAddress),
BIOSMemoryMap,
AddressRangeCount);
kernel_len = LastKrnlPhysAddr - FirstKrnlPhysAddr;
/* Unmap low memory */ /* Unmap low memory */
MmDeletePageTable(NULL, 0); MmDeletePageTable(NULL, 0);
/* Intialize memory areas */ /* Intialize memory areas */
MmInitVirtualMemory(LastKernelAddress, kernel_len); MmInitVirtualMemory();
/* Initialize MDLs */ /* Initialize MDLs */
MmInitializeMdlImplementation(); MmInitializeMdlImplementation();