mirror of
https://github.com/reactos/reactos.git
synced 2024-08-12 22:26:31 +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_START (ULONG)HYPER_SPACE
|
||||||
#define MI_MAPPING_RANGE_END (MI_MAPPING_RANGE_START + \
|
#define MI_MAPPING_RANGE_END (MI_MAPPING_RANGE_START + \
|
||||||
MI_HYPERSPACE_PTES * PAGE_SIZE)
|
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)
|
PAGE_SIZE)
|
||||||
|
|
||||||
/* On x86, these two are the same */
|
/* On x86, these two are the same */
|
||||||
|
|
|
@ -160,6 +160,8 @@ MiInitMachineDependent(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
|
||||||
MMPTE TempPde, TempPte;
|
MMPTE TempPde, TempPte;
|
||||||
PVOID NonPagedPoolExpansionVa;
|
PVOID NonPagedPoolExpansionVa;
|
||||||
KIRQL OldIrql;
|
KIRQL OldIrql;
|
||||||
|
PMMPFN Pfn1;
|
||||||
|
ULONG Flags;
|
||||||
|
|
||||||
/* Check for kernel stack size that's too big */
|
/* Check for kernel stack size that's too big */
|
||||||
if (MmLargeStackSize > (KERNEL_LARGE_STACK_SIZE / _1KB))
|
if (MmLargeStackSize > (KERNEL_LARGE_STACK_SIZE / _1KB))
|
||||||
|
@ -559,6 +561,9 @@ MiInitMachineDependent(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
|
||||||
MmLastReservedMappingPte = MiAddressToPte(MI_MAPPING_RANGE_END);
|
MmLastReservedMappingPte = MiAddressToPte(MI_MAPPING_RANGE_END);
|
||||||
MmFirstReservedMappingPte->u.Hard.PageFrameNumber = MI_HYPERSPACE_PTES;
|
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
|
// 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;
|
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 */
|
/* Check for Pentium LOCK errata */
|
||||||
if (KiI386PentiumLockErrataPresent)
|
if (KiI386PentiumLockErrataPresent)
|
||||||
{
|
{
|
||||||
|
@ -581,6 +608,43 @@ MiInitMachineDependent(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
|
||||||
PointerPte->u.Hard.WriteThrough = 1;
|
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;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -513,6 +513,7 @@ extern BOOLEAN MmZeroingPageThreadActive;
|
||||||
extern KEVENT MmZeroingPageEvent;
|
extern KEVENT MmZeroingPageEvent;
|
||||||
extern ULONG MmSystemPageColor;
|
extern ULONG MmSystemPageColor;
|
||||||
extern ULONG MmProcessColorSeed;
|
extern ULONG MmProcessColorSeed;
|
||||||
|
extern PMMWSL MmWorkingSetList;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Figures out the hardware bits for a PTE
|
// Figures out the hardware bits for a PTE
|
||||||
|
|
|
@ -992,6 +992,14 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
|
||||||
return Status;
|
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? */
|
/* Did we get a prototype PTE back? */
|
||||||
if (!ProtoPte)
|
if (!ProtoPte)
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
/* GLOBALS ********************************************************************/
|
/* GLOBALS ********************************************************************/
|
||||||
|
|
||||||
ULONG MmProcessColorSeed = 0x12345678;
|
ULONG MmProcessColorSeed = 0x12345678;
|
||||||
|
PMMWSL MmWorkingSetList;
|
||||||
|
|
||||||
/* PRIVATE FUNCTIONS **********************************************************/
|
/* PRIVATE FUNCTIONS **********************************************************/
|
||||||
|
|
||||||
|
@ -892,6 +893,32 @@ MmCreateTeb(IN PEPROCESS Process,
|
||||||
return Status;
|
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
|
NTSTATUS
|
||||||
NTAPI
|
NTAPI
|
||||||
MmInitializeProcessAddressSpace(IN PEPROCESS Process,
|
MmInitializeProcessAddressSpace(IN PEPROCESS Process,
|
||||||
|
@ -912,6 +939,7 @@ MmInitializeProcessAddressSpace(IN PEPROCESS Process,
|
||||||
PWCHAR Source;
|
PWCHAR Source;
|
||||||
PCHAR Destination;
|
PCHAR Destination;
|
||||||
USHORT Length = 0;
|
USHORT Length = 0;
|
||||||
|
MMPTE TempPte;
|
||||||
|
|
||||||
/* We should have a PDE */
|
/* We should have a PDE */
|
||||||
ASSERT(Process->Pcb.DirectoryTableBase[0] != 0);
|
ASSERT(Process->Pcb.DirectoryTableBase[0] != 0);
|
||||||
|
@ -945,6 +973,22 @@ MmInitializeProcessAddressSpace(IN PEPROCESS Process,
|
||||||
PageFrameNumber = PFN_FROM_PTE(PointerPde);
|
PageFrameNumber = PFN_FROM_PTE(PointerPde);
|
||||||
MiInitializePfn(PageFrameNumber, PointerPde, TRUE);
|
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 */
|
/* Release PFN lock */
|
||||||
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
|
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
|
||||||
|
|
||||||
|
@ -1062,12 +1106,13 @@ MmCreateProcessAddressSpace(IN ULONG MinWs,
|
||||||
OUT PULONG_PTR DirectoryTableBase)
|
OUT PULONG_PTR DirectoryTableBase)
|
||||||
{
|
{
|
||||||
KIRQL OldIrql;
|
KIRQL OldIrql;
|
||||||
PFN_NUMBER PdeIndex, HyperIndex;
|
PFN_NUMBER PdeIndex, HyperIndex, WsListIndex;
|
||||||
PMMPTE PointerPte;
|
PMMPTE PointerPte;
|
||||||
MMPTE TempPte, PdePte;
|
MMPTE TempPte, PdePte;
|
||||||
ULONG PdeOffset;
|
ULONG PdeOffset;
|
||||||
PMMPTE SystemTable;
|
PMMPTE SystemTable, HyperTable;
|
||||||
ULONG Color;
|
ULONG Color;
|
||||||
|
PMMPFN Pfn1;
|
||||||
|
|
||||||
/* Choose a process color */
|
/* Choose a process color */
|
||||||
Process->NextPageColor = RtlRandom(&MmProcessColorSeed);
|
Process->NextPageColor = RtlRandom(&MmProcessColorSeed);
|
||||||
|
@ -1105,6 +1150,21 @@ MmCreateProcessAddressSpace(IN ULONG MinWs,
|
||||||
/* Zero it outside the PFN lock */
|
/* Zero it outside the PFN lock */
|
||||||
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
|
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
|
||||||
MiZeroPhysicalPage(HyperIndex);
|
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
|
else
|
||||||
{
|
{
|
||||||
|
@ -1117,12 +1177,43 @@ MmCreateProcessAddressSpace(IN ULONG MinWs,
|
||||||
Process->AddressSpaceInitialized = 1;
|
Process->AddressSpaceInitialized = 1;
|
||||||
|
|
||||||
/* Set the base directory pointers */
|
/* Set the base directory pointers */
|
||||||
|
Process->WorkingSetPage = WsListIndex;
|
||||||
DirectoryTableBase[0] = PdeIndex << PAGE_SHIFT;
|
DirectoryTableBase[0] = PdeIndex << PAGE_SHIFT;
|
||||||
DirectoryTableBase[1] = HyperIndex << PAGE_SHIFT;
|
DirectoryTableBase[1] = HyperIndex << PAGE_SHIFT;
|
||||||
|
|
||||||
/* Make sure we don't already have a page directory setup */
|
/* Make sure we don't already have a page directory setup */
|
||||||
ASSERT(Process->Pcb.DirectoryTableBase[0] == 0);
|
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 */
|
/* Insert us into the Mm process list */
|
||||||
InsertTailList(&MmProcessList, &Process->MmProcessLinks);
|
InsertTailList(&MmProcessList, &Process->MmProcessLinks);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue