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 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
);

View 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] =

View file

@ -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

View 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();