[NTOS]: Assign a working set to the system process and correctly initialize its address space.

[NTOS]: Assign the working set list address, system-wide, but per-process (in hyperspace).
[NTOS]: Give every process its working set page, and store it. Build a bogus working set list (MMWSL).
[NTOS]: Use the process working set list (MMWSL) to track page table references during faults, just as Windows does.
[NTOS]: Correctly initialize the colored page list heads and assert their validity.

svn path=/trunk/; revision=49525
This commit is contained in:
Sir Richard 2010-11-08 12:35:50 +00:00
parent e8c269c0c4
commit f205f243bb
5 changed files with 172 additions and 4 deletions

View file

@ -84,7 +84,11 @@ PULONG MmGetPageDirectory(VOID);
#define MI_MAPPING_RANGE_START (ULONG)HYPER_SPACE
#define MI_MAPPING_RANGE_END (MI_MAPPING_RANGE_START + \
MI_HYPERSPACE_PTES * PAGE_SIZE)
#define MI_ZERO_PTE (PMMPTE)(MI_MAPPING_RANGE_END + \
#define MI_DUMMY_PTE (PMMPTE)(MI_MAPPING_RANGE_END + \
PAGE_SIZE)
#define MI_VAD_BITMAP (PMMPTE)(MI_DUMMY_PTE + \
PAGE_SIZE)
#define MI_WORKING_SET_LIST (PMMPTE)(MI_VAD_BITMAP + \
PAGE_SIZE)
/* On x86, these two are the same */

View file

@ -160,7 +160,9 @@ MiInitMachineDependent(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
MMPTE TempPde, TempPte;
PVOID NonPagedPoolExpansionVa;
KIRQL OldIrql;
PMMPFN Pfn1;
ULONG Flags;
/* Check for kernel stack size that's too big */
if (MmLargeStackSize > (KERNEL_LARGE_STACK_SIZE / _1KB))
{
@ -558,6 +560,9 @@ MiInitMachineDependent(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
MmFirstReservedMappingPte = MiAddressToPte(MI_MAPPING_RANGE_START);
MmLastReservedMappingPte = MiAddressToPte(MI_MAPPING_RANGE_END);
MmFirstReservedMappingPte->u.Hard.PageFrameNumber = MI_HYPERSPACE_PTES;
/* Set the working set address */
MmWorkingSetList = (PVOID)MI_WORKING_SET_LIST;
//
// Reserve system PTEs for zeroing PTEs and clear them
@ -571,6 +576,28 @@ MiInitMachineDependent(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
//
MiFirstReservedZeroingPte->u.Hard.PageFrameNumber = MI_ZERO_PTES - 1;
/* Lock PFN database */
OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
/* Reset the ref/share count so that MmInitializeProcessAddressSpace works */
Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(MiAddressToPde(PDE_BASE)));
Pfn1->u2.ShareCount = 0;
Pfn1->u3.e2.ReferenceCount = 0;
/* Get a page for the working set list */
MI_SET_USAGE(MI_USAGE_PAGE_TABLE);
MI_SET_PROCESS2("Kernel WS List");
PageFrameIndex = MiRemoveAnyPage(0);
TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
/* Map the working set list */
PointerPte = MiAddressToPte(MmWorkingSetList);
MI_WRITE_VALID_PTE(PointerPte, TempPte);
/* Zero it out, and save the frame index */
RtlZeroMemory(MiPteToAddress(PointerPte), PAGE_SIZE);
PsGetCurrentProcess()->WorkingSetPage = PageFrameIndex;
/* Check for Pentium LOCK errata */
if (KiI386PentiumLockErrataPresent)
{
@ -581,6 +608,43 @@ MiInitMachineDependent(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
PointerPte->u.Hard.WriteThrough = 1;
}
/* Release the lock */
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
/* Initialize the bogus address space */
Flags = 0;
MmInitializeProcessAddressSpace(PsGetCurrentProcess(), NULL, NULL, &Flags, NULL);
/* Make sure the color lists are valid */
ASSERT(MmFreePagesByColor[0] < (PMMCOLOR_TABLES)PTE_BASE);
StartPde = MiAddressToPde(MmFreePagesByColor[0]);
ASSERT(StartPde->u.Hard.Valid == 1);
PointerPte = MiAddressToPte(MmFreePagesByColor[0]);
ASSERT(PointerPte->u.Hard.Valid == 1);
LastPte = MiAddressToPte((ULONG_PTR)&MmFreePagesByColor[1][MmSecondaryColors] - 1);
ASSERT(LastPte->u.Hard.Valid == 1);
/* Loop the color list PTEs */
while (PointerPte <= LastPte)
{
/* Get the PFN entry */
Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte));
if (!Pfn1->u3.e2.ReferenceCount)
{
/* Fill it out */
Pfn1->u4.PteFrame = PFN_FROM_PTE(StartPde);
Pfn1->PteAddress = PointerPte;
Pfn1->u2.ShareCount++;
Pfn1->u3.e2.ReferenceCount = 1;
Pfn1->u3.e1.PageLocation = ActiveAndValid;
Pfn1->u3.e1.CacheAttribute = MiCached;
}
/* Keep going */
PointerPte++;
}
/* All done */
return STATUS_SUCCESS;
}

View file

@ -513,6 +513,7 @@ extern BOOLEAN MmZeroingPageThreadActive;
extern KEVENT MmZeroingPageEvent;
extern ULONG MmSystemPageColor;
extern ULONG MmProcessColorSeed;
extern PMMWSL MmWorkingSetList;
//
// Figures out the hardware bits for a PTE

View file

@ -991,6 +991,14 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
return Status;
}
/* Is this a user address? */
if (Address <= MM_HIGHEST_USER_ADDRESS)
{
/* Add an additional page table reference */
MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]++;
ASSERT(MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] <= PTE_COUNT);
}
/* Did we get a prototype PTE back? */
if (!ProtoPte)

View file

@ -19,6 +19,7 @@
/* GLOBALS ********************************************************************/
ULONG MmProcessColorSeed = 0x12345678;
PMMWSL MmWorkingSetList;
/* PRIVATE FUNCTIONS **********************************************************/
@ -892,6 +893,32 @@ MmCreateTeb(IN PEPROCESS Process,
return Status;
}
VOID
NTAPI
MiInitializeWorkingSetList(IN PEPROCESS CurrentProcess)
{
PMMPFN Pfn1;
/* Setup some bogus list data */
MmWorkingSetList->LastEntry = CurrentProcess->Vm.MinimumWorkingSetSize;
MmWorkingSetList->HashTable = NULL;
MmWorkingSetList->HashTableSize = 0;
MmWorkingSetList->NumberOfImageWaiters = 0;
MmWorkingSetList->Wsle = (PVOID)0xDEADBABE;
MmWorkingSetList->VadBitMapHint = 1;
MmWorkingSetList->HashTableStart = (PVOID)0xBADAB00B;
MmWorkingSetList->HighestPermittedHashAddress = (PVOID)0xCAFEBABE;
MmWorkingSetList->FirstFree = 1;
MmWorkingSetList->FirstDynamic = 2;
MmWorkingSetList->NextSlot = 3;
MmWorkingSetList->LastInitializedWsle = 4;
/* The rule is that the owner process is always in the FLINK of the PDE's PFN entry */
Pfn1 = MiGetPfnEntry(MiAddressToPte(PDE_BASE)->u.Hard.PageFrameNumber);
ASSERT(Pfn1->u4.PteFrame == MiGetPfnEntryIndex(Pfn1));
Pfn1->u1.Event = (PKEVENT)CurrentProcess;
}
NTSTATUS
NTAPI
MmInitializeProcessAddressSpace(IN PEPROCESS Process,
@ -912,6 +939,7 @@ MmInitializeProcessAddressSpace(IN PEPROCESS Process,
PWCHAR Source;
PCHAR Destination;
USHORT Length = 0;
MMPTE TempPte;
/* We should have a PDE */
ASSERT(Process->Pcb.DirectoryTableBase[0] != 0);
@ -944,6 +972,22 @@ MmInitializeProcessAddressSpace(IN PEPROCESS Process,
PointerPde = MiAddressToPde(HYPER_SPACE);
PageFrameNumber = PFN_FROM_PTE(PointerPde);
MiInitializePfn(PageFrameNumber, PointerPde, TRUE);
/* Setup the PFN for the PTE for the working set */
PointerPte = MiAddressToPte(MI_WORKING_SET_LIST);
MI_MAKE_HARDWARE_PTE(&TempPte, PointerPte, MM_READWRITE, 0);
ASSERT(PointerPte->u.Long != 0);
PageFrameNumber = PFN_FROM_PTE(PointerPte);
MI_WRITE_INVALID_PTE(PointerPte, DemandZeroPte);
MiInitializePfn(PageFrameNumber, PointerPte, TRUE);
TempPte.u.Hard.PageFrameNumber = PageFrameNumber;
MI_WRITE_VALID_PTE(PointerPte, TempPte);
/* Now initialize the working set list */
MiInitializeWorkingSetList(Process);
/* Sanity check */
ASSERT(Process->PhysicalVadRoot == NULL);
/* Release PFN lock */
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
@ -1062,12 +1106,13 @@ MmCreateProcessAddressSpace(IN ULONG MinWs,
OUT PULONG_PTR DirectoryTableBase)
{
KIRQL OldIrql;
PFN_NUMBER PdeIndex, HyperIndex;
PFN_NUMBER PdeIndex, HyperIndex, WsListIndex;
PMMPTE PointerPte;
MMPTE TempPte, PdePte;
ULONG PdeOffset;
PMMPTE SystemTable;
PMMPTE SystemTable, HyperTable;
ULONG Color;
PMMPFN Pfn1;
/* Choose a process color */
Process->NextPageColor = RtlRandom(&MmProcessColorSeed);
@ -1105,6 +1150,21 @@ MmCreateProcessAddressSpace(IN ULONG MinWs,
/* Zero it outside the PFN lock */
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
MiZeroPhysicalPage(HyperIndex);
OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
}
/* Get a zero page for the woring set list, if possible */
MI_SET_USAGE(MI_USAGE_PAGE_TABLE);
Color = MI_GET_NEXT_PROCESS_COLOR(Process);
WsListIndex = MiRemoveZeroPageSafe(Color);
if (!WsListIndex)
{
/* No zero pages, grab a free one */
WsListIndex = MiRemoveAnyPage(Color);
/* Zero it outside the PFN lock */
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
MiZeroPhysicalPage(WsListIndex);
}
else
{
@ -1117,11 +1177,42 @@ MmCreateProcessAddressSpace(IN ULONG MinWs,
Process->AddressSpaceInitialized = 1;
/* Set the base directory pointers */
Process->WorkingSetPage = WsListIndex;
DirectoryTableBase[0] = PdeIndex << PAGE_SHIFT;
DirectoryTableBase[1] = HyperIndex << PAGE_SHIFT;
/* Make sure we don't already have a page directory setup */
ASSERT(Process->Pcb.DirectoryTableBase[0] == 0);
/* Get a PTE to map hyperspace */
PointerPte = MiReserveSystemPtes(1, SystemPteSpace);
ASSERT(PointerPte != NULL);
/* Build it */
MI_MAKE_HARDWARE_PTE_KERNEL(&PdePte,
PointerPte,
MM_READWRITE,
HyperIndex);
/* Set it dirty and map it */
PdePte.u.Hard.Dirty = TRUE;
MI_WRITE_VALID_PTE(PointerPte, PdePte);
/* Now get hyperspace's page table */
HyperTable = MiPteToAddress(PointerPte);
/* Now write the PTE/PDE entry for the working set list index itself */
TempPte = ValidKernelPte;
TempPte.u.Hard.PageFrameNumber = WsListIndex;
PdeOffset = MiAddressToPteOffset(MmWorkingSetList);
HyperTable[PdeOffset] = TempPte;
/* Let go of the system PTE */
MiReleaseSystemPtes(PointerPte, 1, SystemPteSpace);
/* Save the PTE address of the page directory itself */
Pfn1 = MiGetPfnEntry(PdeIndex);
Pfn1->PteAddress = (PMMPTE)PDE_BASE;
/* Insert us into the Mm process list */
InsertTailList(&MmProcessList, &Process->MmProcessLinks);