[NTOS:ARM3] Change calculation for more system PTEs (#8613)

* [NTOSKRNL] Increase MI_NUMBER_SYSTEM_PTES for AMD64
* [NTOS:MM] Move the system PTE space on x86 to a different spot
* [KMTESTS] Adjust KmTest
This commit is contained in:
Justin Miller
2026-03-05 14:57:09 +00:00
committed by GitHub
parent c9e73b6a77
commit 4cba65d760
6 changed files with 97 additions and 52 deletions

View File

@@ -134,7 +134,15 @@ TestMmAllocatePagesForMdl(VOID)
FALSE,
NormalPagePriority);
#ifdef _M_IX86
ok(SystemVa == NULL, "MmMapLockedPagesSpecifyCache succeeded for 2 GB\n");
/*
* MmAllocatePagesForMdl is allowed to return fewer pages than requested.
* Only enforce the x86 mapping expectation if we actually got ~2GB.
*/
if (MmGetMdlByteCount(Mdl) >= (1UL << 31))
ok(SystemVa == NULL, "MmMapLockedPagesSpecifyCache succeeded for 2 GB\n");
else
trace("Skipping 2GB mapping expectation (allocated %lu bytes)\n",
MmGetMdlByteCount(Mdl));
#endif
if (SystemVa != NULL)
MmUnmapLockedPages(SystemVa, Mdl);
@@ -173,7 +181,7 @@ TestMmAllocatePagesForMdl(VOID)
trace("MmMapLockedPagesSpecifyCache failed with i = %lu\n", i);
break;
}
ok(MmGetMdlByteCount(Mdls[i]) == 32 * 1024 * 1024, "Byte count: %lu\n", MmGetMdlByteCount(Mdls[i]));
ok(MmGetMdlByteCount(Mdls[i]) <= 32 * 1024 * 1024, "Byte count: %lu\n", MmGetMdlByteCount(Mdls[i]));
ok(MmGetMdlVirtualAddress(Mdls[i]) == NULL, "Virtual address: %p, System VA: %p\n", MmGetMdlVirtualAddress(Mdls[i]), SystemVas[i]);
ok(Mdls[i]->MappedSystemVa == SystemVas[i], "MappedSystemVa: %p\n", Mdls[i]->MappedSystemVa, SystemVas[i]);
ok((Mdls[i]->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA), "MdlFlags: %lx\n", Mdls[i]->MdlFlags);

View File

@@ -76,7 +76,7 @@
#define MI_MIN_SECONDARY_COLORS 8
#define MI_SECONDARY_COLORS 64
#define MI_MAX_SECONDARY_COLORS 1024
#define MI_NUMBER_SYSTEM_PTES 22000
#define MI_NUMBER_SYSTEM_PTES (22000 * 22)
#define MI_MAX_FREE_PAGE_LISTS 4
#define MI_HYPERSPACE_PTES (256 - 1)
#define MI_ZERO_PTES (32)

View File

@@ -245,7 +245,6 @@ MiInitMachineDependent(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
PMMPTE StartPde, EndPde, PointerPte, LastPte;
MMPTE TempPde, TempPte;
PVOID NonPagedPoolExpansionVa;
SIZE_T NonPagedSystemSize;
KIRQL OldIrql;
PMMPFN Pfn1;
ULONG Flags;
@@ -294,43 +293,12 @@ MiInitMachineDependent(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
DPRINT("NP Pool has been tuned to: %lu bytes and %lu bytes\n",
MmSizeOfNonPagedPoolInBytes, MmMaximumNonPagedPoolInBytes);
//
// Now calculate the nonpaged system VA region, which includes the
// nonpaged pool expansion (above) and the system PTEs. Note that it is
// then aligned to a PDE boundary (4MB).
//
NonPagedSystemSize = (MmNumberOfSystemPtes + 1) * PAGE_SIZE;
MmNonPagedSystemStart = (PVOID)((ULONG_PTR)MmNonPagedPoolStart -
NonPagedSystemSize);
MmNonPagedSystemStart = (PVOID)((ULONG_PTR)MmNonPagedSystemStart &
~(PDE_MAPPED_VA - 1));
//
// Don't let it go below the minimum
//
if (MmNonPagedSystemStart < (PVOID)0xEB000000)
{
//
// This is a hard-coded limit in the Windows NT address space
//
MmNonPagedSystemStart = (PVOID)0xEB000000;
//
// Reduce the amount of system PTEs to reach this point
//
MmNumberOfSystemPtes = ((ULONG_PTR)MmNonPagedPoolStart -
(ULONG_PTR)MmNonPagedSystemStart) >>
PAGE_SHIFT;
MmNumberOfSystemPtes--;
ASSERT(MmNumberOfSystemPtes > 1000);
}
//
// Check if we are in a situation where the size of the paged pool
// is so large that it overflows into nonpaged pool
// is so large that it overflows into nonpaged pool expansion VA
//
if (MmSizeOfPagedPoolInBytes >
((ULONG_PTR)MmNonPagedSystemStart - (ULONG_PTR)MmPagedPoolStart))
((ULONG_PTR)NonPagedPoolExpansionVa - (ULONG_PTR)MmPagedPoolStart))
{
//
// We need some recalculations here
@@ -347,6 +315,29 @@ MiInitMachineDependent(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
MmPfnDatabase = (PVOID)0xB0000000;
ASSERT(((ULONG_PTR)MmPfnDatabase & (PDE_MAPPED_VA - 1)) == 0);
//
// Use the gap between loader mappings and PFN database for
// System PTEs: place it right after the loader mappings
// using MmBootImageSize (LoaderPagesSpanned, PDE-aligned).
//
MmSystemPteSpaceStart = (PVOID)((ULONG_PTR)KSEG0_BASE + MmBootImageSize);
ASSERT(((ULONG_PTR)MmSystemPteSpaceStart & (PDE_MAPPED_VA - 1)) == 0);
ASSERT((ULONG_PTR)MmSystemPteSpaceStart < (ULONG_PTR)MmPfnDatabase);
/* Make sure the System PTE VA space doesn't overlap the PFN DB */
SIZE_T MaxSystemPtePages = ((ULONG_PTR)MmPfnDatabase -
(ULONG_PTR)MmSystemPteSpaceStart) >> PAGE_SHIFT;
ASSERT(MaxSystemPtePages > 1000);
MmNumberOfSystemPtes = (ULONG)(MaxSystemPtePages - 1);
ASSERT(MmNumberOfSystemPtes > 1000);
/*
* Keep MmNonPagedSystemStart initialized for debugger (KD/Windbg) use.
* On x86 ARM3, the System PTE space is placed in the loader-gap region.
*/
MmNonPagedSystemStart = MmSystemPteSpaceStart;
//
// Non paged pool comes after the PFN database
//
@@ -368,9 +359,27 @@ MiInitMachineDependent(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
//
// Now we need some pages to create the page tables for the NP system VA
// which includes system PTEs and expansion NP
// which includes the System PTE VA region (below the PFN DB)
//
StartPde = MiAddressToPde(MmNonPagedSystemStart);
StartPde = MiAddressToPde(MmSystemPteSpaceStart);
EndPde = MiAddressToPde((PVOID)((ULONG_PTR)MmSystemPteSpaceStart +
((MmNumberOfSystemPtes + 1) * PAGE_SIZE) - 1));
while (StartPde <= EndPde)
{
TempPde.u.Hard.PageFrameNumber = MxGetNextPage(1);
MI_WRITE_VALID_PTE(StartPde, TempPde);
PointerPte = MiPteToAddress(StartPde);
RtlZeroMemory(PointerPte, PAGE_SIZE);
StartPde++;
}
//
// Now allocate the page tables for the nonpaged pool expansion VA region
// (top-of-kernel VA). This keeps existing nonpaged pool expansion behavior.
//
StartPde = MiAddressToPde(NonPagedPoolExpansionVa);
EndPde = MiAddressToPde((PVOID)((ULONG_PTR)MmNonPagedPoolEnd - 1));
while (StartPde <= EndPde)
{
@@ -443,8 +452,9 @@ MiInitMachineDependent(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
//
// Sanity check: make sure we have properly defined the system PTE space
//
ASSERT(MiAddressToPte(MmNonPagedSystemStart) <
MiAddressToPte(MmNonPagedPoolExpansionStart));
ASSERT(((ULONG_PTR)MmSystemPteSpaceStart +
((MmNumberOfSystemPtes + 1) * PAGE_SIZE)) <=
(ULONG_PTR)MmPfnDatabase);
/* Now go ahead and initialize the nonpaged pool */
MiInitializeNonPagedPool();
@@ -471,12 +481,9 @@ MiInitMachineDependent(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
InitializePool(NonPagedPool, 0);
//
// We PDE-aligned the nonpaged system start VA, so haul some extra PTEs!
// Initialize the System PTE allocator at the requested VA start.
//
PointerPte = MiAddressToPte(MmNonPagedSystemStart);
MmNumberOfSystemPtes = MiAddressToPte(MmNonPagedPoolExpansionStart) -
PointerPte;
MmNumberOfSystemPtes--;
PointerPte = MiAddressToPte(MmSystemPteSpaceStart);
DPRINT("Final System PTE count: %lu (%lu bytes)\n",
MmNumberOfSystemPtes, MmNumberOfSystemPtes * PAGE_SIZE);

View File

@@ -554,6 +554,7 @@ extern SIZE_T MmMaximumNonPagedPoolInBytes;
extern PFN_NUMBER MmMaximumNonPagedPoolInPages;
extern PFN_NUMBER MmSizeOfPagedPoolInPages;
extern PVOID MmNonPagedSystemStart;
extern PVOID MmSystemPteSpaceStart;
extern PVOID MmNonPagedPoolStart;
extern PVOID MmNonPagedPoolExpansionStart;
extern PVOID MmNonPagedPoolEnd;

View File

@@ -94,6 +94,7 @@ ULONG MmMaxAdditionNonPagedPoolPerMb = 400 * 1024;
// https://web.archive.org/web/20130412053421/http://www.ditii.com/2007/09/28/windows-memory-management-x86-virtual-address-space/
//
PVOID MmNonPagedSystemStart;
PVOID MmSystemPteSpaceStart;
PVOID MmNonPagedPoolStart;
PVOID MmNonPagedPoolExpansionStart;
PVOID MmNonPagedPoolEnd = MI_NONPAGED_POOL_END;
@@ -1787,7 +1788,7 @@ MiBuildPagedPool(VOID)
// By default, it should be twice as big as nonpaged pool.
//
MmSizeOfPagedPoolInBytes = 2 * MmMaximumNonPagedPoolInBytes;
if (MmSizeOfPagedPoolInBytes > ((ULONG_PTR)MmNonPagedSystemStart -
if (MmSizeOfPagedPoolInBytes > ((ULONG_PTR)MmNonPagedPoolExpansionStart -
(ULONG_PTR)MmPagedPoolStart))
{
//
@@ -1795,7 +1796,7 @@ MiBuildPagedPool(VOID)
// for paged pool doesn't overflow into nonpaged pool VA. Otherwise, set
// whatever maximum is possible.
//
MmSizeOfPagedPoolInBytes = (ULONG_PTR)MmNonPagedSystemStart -
MmSizeOfPagedPoolInBytes = (ULONG_PTR)MmNonPagedPoolExpansionStart -
(ULONG_PTR)MmPagedPoolStart;
}
#endif // _M_IX86
@@ -1812,6 +1813,17 @@ MiBuildPagedPool(VOID)
//
NumberOfPdes = (NumberOfPages + (PTE_PER_PAGE - 1)) / PTE_PER_PAGE;
#ifdef _M_IX86
SIZE_T MaxNumberOfPdes;
SIZE_T MaxBytes;
MaxBytes = (ULONG_PTR)MmNonPagedPoolExpansionStart - (ULONG_PTR)MmPagedPoolStart;
MaxNumberOfPdes = MaxBytes / PDE_MAPPED_VA;
ASSERT(MaxNumberOfPdes != 0);
NumberOfPdes = min(NumberOfPdes, MaxNumberOfPdes);
#endif // _M_IX86
//
// Recompute the PDE-aligned size of the paged pool, in bytes and pages.
//
@@ -1820,10 +1832,10 @@ MiBuildPagedPool(VOID)
#ifdef _M_IX86
//
// Let's be really sure this doesn't overflow into nonpaged system VA
// Let's be really sure this doesn't overflow into nonpaged pool expansion VA
//
ASSERT((MmSizeOfPagedPoolInBytes + (ULONG_PTR)MmPagedPoolStart) <=
(ULONG_PTR)MmNonPagedSystemStart);
(ULONG_PTR)MmNonPagedPoolExpansionStart);
#endif // _M_IX86
//
@@ -2294,6 +2306,12 @@ MmArmInitSystem(IN ULONG Phase,
/* Initialize the platform-specific parts */
MiInitMachineDependent(LoaderBlock);
//
// x86 uses the loader-gap region
//
if (!MmSystemPteSpaceStart)
MmSystemPteSpaceStart = MmNonPagedSystemStart;
#if DBG
/* Prototype PTEs are assumed to be in paged pool, so check if the math works */
PointerPte = (PMMPTE)MmPagedPoolStart;

View File

@@ -91,7 +91,7 @@ MiInitSystemMemoryAreas(VOID)
MiCreateArm3StaticMemoryArea(MmNonPagedPoolStart, MmSizeOfNonPagedPoolInBytes, FALSE);
// System PTE space
MiCreateArm3StaticMemoryArea(MmNonPagedSystemStart, (MmNumberOfSystemPtes + 1) * PAGE_SIZE, FALSE);
MiCreateArm3StaticMemoryArea(MmSystemPteSpaceStart, (MmNumberOfSystemPtes + 1) * PAGE_SIZE, FALSE);
// Nonpaged pool expansion space
MiCreateArm3StaticMemoryArea(MmNonPagedPoolExpansionStart, (ULONG_PTR)MmNonPagedPoolEnd - (ULONG_PTR)MmNonPagedPoolExpansionStart, FALSE);
@@ -136,6 +136,13 @@ MiDbgDumpAddressSpace(VOID)
KSEG0_BASE,
(ULONG_PTR)KSEG0_BASE + MmBootImageSize,
"Boot Loaded Image");
#ifdef _M_IX86
DPRINT1(" 0x%p - 0x%p\t%s\n",
MmSystemPteSpaceStart,
(PVOID)((ULONG_PTR)MmSystemPteSpaceStart +
(MmNumberOfSystemPtes + 1) * PAGE_SIZE),
"System PTE Space");
#endif
DPRINT1(" 0x%p - 0x%p\t%s\n",
MmPfnDatabase,
(ULONG_PTR)MmPfnDatabase + (MxPfnAllocation << PAGE_SHIFT),
@@ -168,9 +175,13 @@ MiDbgDumpAddressSpace(VOID)
MmPagedPoolStart,
(ULONG_PTR)MmPagedPoolStart + MmSizeOfPagedPoolInBytes,
"ARM3 Paged Pool");
#ifndef _M_IX86
DPRINT1(" 0x%p - 0x%p\t%s\n",
MmNonPagedSystemStart, MmNonPagedPoolExpansionStart,
MmSystemPteSpaceStart,
(PVOID)((ULONG_PTR)MmSystemPteSpaceStart +
((MmNumberOfSystemPtes + 1) * PAGE_SIZE)),
"System PTE Space");
#endif
DPRINT1(" 0x%p - 0x%p\t%s\n",
MmNonPagedPoolExpansionStart, MmNonPagedPoolEnd,
"Non Paged Pool Expansion PTE Space");