mirror of
https://github.com/reactos/reactos.git
synced 2024-07-06 20:55:16 +00:00
[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:
parent
e8c269c0c4
commit
f205f243bb
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue