Author: jgardou Date: Wed Sep 24 21:55:37 2014 New Revision: 64262
URL: http://svn.reactos.org/svn/reactos?rev=64262&view=rev Log: [NTOS/MM] - First try at creating and adding pages to the working set of processes in ARM3. Limited to 1k pages for now. CORE-8553
Modified: branches/TransitionPte/ntoskrnl/mm/ARM3/miarm.h branches/TransitionPte/ntoskrnl/mm/ARM3/pagfault.c branches/TransitionPte/ntoskrnl/mm/ARM3/procsup.c branches/TransitionPte/ntoskrnl/mm/ARM3/virtual.c
Modified: branches/TransitionPte/ntoskrnl/mm/ARM3/miarm.h URL: http://svn.reactos.org/svn/reactos/branches/TransitionPte/ntoskrnl/mm/ARM3/m... ============================================================================== --- branches/TransitionPte/ntoskrnl/mm/ARM3/miarm.h [iso-8859-1] (original) +++ branches/TransitionPte/ntoskrnl/mm/ARM3/miarm.h [iso-8859-1] Wed Sep 24 21:55:37 2014 @@ -2321,6 +2321,19 @@ IN KIRQL OldIrql );
+VOID +NTAPI +MiDeleteFromWorkingSetList( + _Inout_ PMMSUPPORT Vm, + _In_ PVOID Address); + +VOID +NTAPI +MiInsertInWorkingSetList( + _Inout_ PMMSUPPORT Vm, + _In_ PVOID Address, + _In_ ULONG Protection); + // // MiRemoveZeroPage will use inline code to zero out the page manually if only // free pages are available. In some scenarios, we don't/can't run that piece of
Modified: branches/TransitionPte/ntoskrnl/mm/ARM3/pagfault.c URL: http://svn.reactos.org/svn/reactos/branches/TransitionPte/ntoskrnl/mm/ARM3/p... ============================================================================== --- branches/TransitionPte/ntoskrnl/mm/ARM3/pagfault.c [iso-8859-1] (original) +++ branches/TransitionPte/ntoskrnl/mm/ARM3/pagfault.c [iso-8859-1] Wed Sep 24 21:55:37 2014 @@ -2247,6 +2247,9 @@
MiCopyPfn(PageFrameIndex, OldPageFrameIndex);
+ /* Delete the WS entry, we will soon replace it */ + MiDeleteFromWorkingSetList(&CurrentProcess->Vm, Address); + /* Dereference whatever this PTE is referencing */ Pfn1 = MI_PFN_ELEMENT(OldPageFrameIndex); ASSERT(Pfn1->u3.e1.PrototypePte == 1); @@ -2262,6 +2265,9 @@
MI_WRITE_VALID_PTE(PointerPte, TempPte);
+ /* Insert into the WS again */ + MiInsertInWorkingSetList(&CurrentProcess->Vm, Address, ProtectionCode); + KeReleaseQueuedSpinLock(LockQueuePfnLock, LockIrql);
/* Return the status */ @@ -2293,6 +2299,9 @@ PointerPte, CurrentProcess, MM_NOIRQL); + + /* Insert into the WS */ + MiInsertInWorkingSetList(&CurrentProcess->Vm, Address, ProtectionCode);
/* Return the status */ MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread); @@ -2528,6 +2537,12 @@ TrapInformation, Vad);
+ /* Add it to the WS */ + if (NT_SUCCESS(Status)) + { + MiInsertInWorkingSetList(&CurrentProcess->Vm, Address, ProtectionCode); + } + /* Return the status */ ASSERT(KeGetCurrentIrql() <= APC_LEVEL); MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
Modified: branches/TransitionPte/ntoskrnl/mm/ARM3/procsup.c URL: http://svn.reactos.org/svn/reactos/branches/TransitionPte/ntoskrnl/mm/ARM3/p... ============================================================================== --- branches/TransitionPte/ntoskrnl/mm/ARM3/procsup.c [iso-8859-1] (original) +++ branches/TransitionPte/ntoskrnl/mm/ARM3/procsup.c [iso-8859-1] Wed Sep 24 21:55:37 2014 @@ -896,25 +896,155 @@
VOID NTAPI +MiDeleteFromWorkingSetList( + _Inout_ PMMSUPPORT Vm, + _In_ PVOID Address) +{ + ULONG i; + PMMWSLE Wsle = NULL; + + /* Only the virtual page number is interesting */ + Address = PAGE_ALIGN(Address); + + /* Check we got the right lock */ + NT_ASSERT((PsGetCurrentThread()->OwnsSessionWorkingSetExclusive) || !MI_IS_SESSION_ADDRESS(Address)); + NT_ASSERT((PsGetCurrentThread()->OwnsSystemWorkingSetExclusive) || (Address < MmSystemRangeStart) || + MI_IS_SESSION_ADDRESS(Address)); + NT_ASSERT((PsGetCurrentThread()->OwnsProcessWorkingSetExclusive) || (Address > MmSystemRangeStart)); + + /* Loop over the entries */ + for (i = 0; i < Vm->VmWorkingSetList->LastInitializedWsle; i++) + { + if (!Vm->VmWorkingSetList->Wsle[i].u1.e1.Valid) + continue; + + if (PAGE_ALIGN(Vm->VmWorkingSetList->Wsle[i].u1.VirtualAddress) == Address) + { + Wsle = &Vm->VmWorkingSetList->Wsle[i]; + break; + } + } + + if (Wsle == NULL) + { + /* Most likely because we don't expand the thing */ + DPRINT1("Address %p not found in Vm %p.\n", Address, Vm); + return; + } + + /* Simply relink it and voilà */ + Wsle->u1.Long = Vm->VmWorkingSetList->FirstFree << 1; + Vm->VmWorkingSetList->FirstFree = i; + Vm->WorkingSetSize--; +} + +VOID +NTAPI +MiInsertInWorkingSetList( + _Inout_ PMMSUPPORT Vm, + _In_ PVOID Address, + _In_ ULONG Protection) +{ + PMMWSLE Wsle = Vm->VmWorkingSetList->Wsle; + PMMPFN Pfn1; + PMMPTE PointerPte; + + /* Only the virtual page number is interesting */ + Address = PAGE_ALIGN(Address); + + /* Check we got the right lock */ + NT_ASSERT((PsGetCurrentThread()->OwnsSessionWorkingSetExclusive) || !MI_IS_SESSION_ADDRESS(Address)); + NT_ASSERT((PsGetCurrentThread()->OwnsSystemWorkingSetExclusive) || (Address < MmSystemRangeStart) || + MI_IS_SESSION_ADDRESS(Address)); + NT_ASSERT((PsGetCurrentThread()->OwnsProcessWorkingSetExclusive) || (Address > MmSystemRangeStart)); + + /* Get the entry where we will insert it */ + if (Vm->VmWorkingSetList->FirstFree == Vm->VmWorkingSetList->LastInitializedWsle) + { + ULONG i; + + if (Vm->VmWorkingSetList->FirstFree == Vm->VmWorkingSetList->LastEntry) + { + DPRINT1("FIXME: Could not add address %p to Vm %p because it is FULL!\n", Address, Vm); + return; + } + + /* Double that */ + Vm->VmWorkingSetList->LastInitializedWsle *= 2; + if (Vm->VmWorkingSetList->LastInitializedWsle > Vm->VmWorkingSetList->LastEntry) + Vm->VmWorkingSetList->LastInitializedWsle = Vm->VmWorkingSetList->LastEntry; + + /* Initialize them */ + for (i = Vm->VmWorkingSetList->FirstFree; i < Vm->VmWorkingSetList->LastInitializedWsle; i++) + Wsle[i].u1.Long = (i + 1) << 1; + } + + /* Get the entry where we will insert it */ + Wsle = &Vm->VmWorkingSetList->Wsle[Vm->VmWorkingSetList->FirstFree]; + + /* See if the PFN deserves to have an entry into the WS */ + PointerPte = MiAddressToPte(Address); + NT_ASSERT(PointerPte->u.Hard.Valid); + Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte)); + if ((Address >= MmSystemRangeStart) || (Pfn1->u3.e1.PrototypePte == 0)) + { + Pfn1->u1.WsIndex = Vm->VmWorkingSetList->FirstFree; + } + + /* Update the list head */ + Vm->VmWorkingSetList->FirstFree = Wsle->u1.Long >> 1; + + /* Set the entry address */ + Wsle->u1.VirtualAddress = Address; + + Wsle->u1.e1.Valid = 1; + Wsle->u1.e1.Protection = Protection; + + /* Bump it */ + Vm->WorkingSetSize++; +} + +VOID +NTAPI MiInitializeWorkingSetList(IN PEPROCESS CurrentProcess) { PMMPFN Pfn1; PMMPTE sysPte; MMPTE tempPte; - - /* Setup some bogus list data */ - MmWorkingSetList->LastEntry = CurrentProcess->Vm.MinimumWorkingSetSize; + ULONG i; + PFN_NUMBER WslePageIndex; + + /* Initialize the WS sizes */ + // FIXME: hardcoded for now + CurrentProcess->Vm.MinimumWorkingSetSize = 50; + CurrentProcess->Vm.MaximumWorkingSetSize = 345; + + /* Setup list data */ + MmWorkingSetList->LastEntry = PAGE_SIZE / sizeof(MMWSLE); 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->HashTableStart = NULL; + MmWorkingSetList->HighestPermittedHashAddress = NULL; MmWorkingSetList->FirstFree = 1; - MmWorkingSetList->FirstDynamic = 2; - MmWorkingSetList->NextSlot = 3; - MmWorkingSetList->LastInitializedWsle = 4; + MmWorkingSetList->FirstDynamic = 0; + MmWorkingSetList->NextSlot = 0; + MmWorkingSetList->LastInitializedWsle = CurrentProcess->Vm.MaximumWorkingSetSize; + + /* Reserve a page for the entries */ + WslePageIndex = MiRemoveAnyPage(MI_GET_NEXT_COLOR()); + sysPte = MiReserveSystemPtes(1, SystemPteSpace); + MI_MAKE_HARDWARE_PTE_KERNEL(&tempPte, sysPte, MM_READWRITE, WslePageIndex); + MiInitializePfnAndMakePteValid(WslePageIndex, sysPte, tempPte); + MmWorkingSetList->Wsle = MiPteToAddress(sysPte); + + /* Initialize the linked-list of free entries */ + for (i = 0; i < MmWorkingSetList->LastInitializedWsle; i++) + { + /* Save LSB to keep track of active/non active state */ + MmWorkingSetList->Wsle[i].u1.Long = (i + 1) << 1; + }
/* The rule is that the owner process is always in the FLINK of the PDE's PFN entry */ Pfn1 = MiGetPfnEntry(CurrentProcess->Pcb.DirectoryTableBase[0] >> PAGE_SHIFT); @@ -926,6 +1056,20 @@ MI_MAKE_HARDWARE_PTE_KERNEL(&tempPte, sysPte, MM_READWRITE, CurrentProcess->WorkingSetPage); MI_WRITE_VALID_PTE(sysPte, tempPte); CurrentProcess->Vm.VmWorkingSetList = MiPteToAddress(sysPte); +} + +VOID +NTAPI +MiDeleteWorkingSetList(PMMWSL WorkingSetList) +{ + PMMPTE SysPte; + PMMPFN Pfn1; + + SysPte = MiAddressToPte(WorkingSetList->Wsle); + Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(SysPte)); + MI_SET_PFN_DELETED(Pfn1); + MiDecrementShareCount(Pfn1, PFN_FROM_PTE(SysPte)); + MiReleaseSystemPtes(SysPte, 1, SystemPteSpace); }
NTSTATUS @@ -1387,6 +1531,9 @@ /* Check for fully initialized process */ if (Process->AddressSpaceInitialized == 2) { + /* Free the working set list entries */ + MiDeleteWorkingSetList(Process->Vm.VmWorkingSetList); + /* Map the working set page and its page table */ Pfn1 = MiGetPfnEntry(Process->WorkingSetPage); Pfn2 = MiGetPfnEntry(Pfn1->u4.PteFrame);
Modified: branches/TransitionPte/ntoskrnl/mm/ARM3/virtual.c URL: http://svn.reactos.org/svn/reactos/branches/TransitionPte/ntoskrnl/mm/ARM3/v... ============================================================================== --- branches/TransitionPte/ntoskrnl/mm/ARM3/virtual.c [iso-8859-1] (original) +++ branches/TransitionPte/ntoskrnl/mm/ARM3/virtual.c [iso-8859-1] Wed Sep 24 21:55:37 2014 @@ -721,6 +721,11 @@ } else { + if (TempPte.u.Hard.Valid == 1) + { + MiDeleteFromWorkingSetList(&CurrentProcess->Vm, MiPteToAddress(PointerPte)); + } + /* Delete the PTE proper */ MiDeletePte(PointerPte, (PVOID)Va, @@ -2360,9 +2365,12 @@ PteContents.u.Hard.Valid = 0; PteContents.u.Soft.Transition = 1; PteContents.u.Trans.Protection = ProtectionMask; + + /* Remove it from the WS */ + MiDeleteFromWorkingSetList(&Process->Vm, MiPteToAddress(PointerPte)); + /* Decrease PFN share count and write the PTE */ MiDecrementShareCount(Pfn1, PFN_FROM_PTE(&PteContents)); - // FIXME: remove the page from the WS MI_WRITE_INVALID_PTE(PointerPte, PteContents); #ifdef CONFIG_SMP // FIXME: Should invalidate entry in every CPU TLB