https://git.reactos.org/?p=reactos.git;a=commitdiff;h=e4047d1521cd75ffded656aef221d7eb8285a04e
commit e4047d1521cd75ffded656aef221d7eb8285a04e Author: Jérôme Gardou <[email protected]> AuthorDate: Tue Oct 27 17:37:38 2020 +0100 Commit: Jérôme Gardou <[email protected]> CommitDate: Wed Feb 3 09:41:22 2021 +0100 [NTOS/MM] Introduce MmArePagesResident and MmMakePagesResident --- ntoskrnl/include/internal/mm.h | 14 +++++ ntoskrnl/mm/section.c | 140 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 154 insertions(+) diff --git a/ntoskrnl/include/internal/mm.h b/ntoskrnl/include/internal/mm.h index 662f49c9bd7..be8b0acc4b0 100644 --- a/ntoskrnl/include/internal/mm.h +++ b/ntoskrnl/include/internal/mm.h @@ -1323,6 +1323,20 @@ MmMapViewInSystemSpaceEx ( _Inout_ PLARGE_INTEGER SectionOffset ); +BOOLEAN +NTAPI +MmArePagesResident( + _In_ PEPROCESS Process, + _In_ PVOID BaseAddress, + _In_ ULONG Length); + +NTSTATUS +NTAPI +MmMakePagesResident( + _In_ PEPROCESS Process, + _In_ PVOID Address, + _In_ ULONG Length); + /* sysldr.c ******************************************************************/ VOID diff --git a/ntoskrnl/mm/section.c b/ntoskrnl/mm/section.c index fc2c1a3e904..4d29f5a9ff4 100644 --- a/ntoskrnl/mm/section.c +++ b/ntoskrnl/mm/section.c @@ -5076,4 +5076,144 @@ MmCreateSection (OUT PVOID * Section, return Status; } +BOOLEAN +NTAPI +MmArePagesResident( + _In_ PEPROCESS Process, + _In_ PVOID Address, + _In_ ULONG Length) +{ + PMEMORY_AREA MemoryArea; + BOOLEAN Ret = TRUE; + PMM_SECTION_SEGMENT Segment; + LARGE_INTEGER SegmentOffset, RangeEnd; + + MmLockAddressSpace(&Process->Vm); + + MemoryArea = MmLocateMemoryAreaByAddress(&Process->Vm, Address); + if (MemoryArea == NULL) + { + MmUnlockAddressSpace(&Process->Vm); + return FALSE; + } + + /* Only supported in old Mm for now */ + ASSERT(MemoryArea->Type == MEMORY_AREA_SECTION_VIEW); + /* For file mappings */ + ASSERT(MemoryArea->VadNode.u.VadFlags.VadType != VadImageMap); + + Segment = MemoryArea->SectionData.Segment; + MmLockSectionSegment(Segment); + + SegmentOffset.QuadPart = PAGE_ROUND_DOWN(Address) - MA_GetStartingAddress(MemoryArea) + + MemoryArea->SectionData.ViewOffset.QuadPart; + RangeEnd.QuadPart = PAGE_ROUND_UP((ULONG_PTR)Address + Length) - MA_GetStartingAddress(MemoryArea) + + MemoryArea->SectionData.ViewOffset.QuadPart; + + while (SegmentOffset.QuadPart < RangeEnd.QuadPart) + { + ULONG_PTR Entry = MmGetPageEntrySectionSegment(Segment, &SegmentOffset); + if ((Entry == 0) || IS_SWAP_FROM_SSE(Entry)) + { + Ret = FALSE; + break; + } + SegmentOffset.QuadPart += PAGE_SIZE; + } + + MmUnlockSectionSegment(Segment); + + MmUnlockAddressSpace(&Process->Vm); + return Ret; +} + +NTSTATUS +NTAPI +MmMakePagesResident( + _In_ PEPROCESS Process, + _In_ PVOID Address, + _In_ ULONG Length) +{ + PMEMORY_AREA MemoryArea; + PMM_SECTION_SEGMENT Segment; + LARGE_INTEGER SegmentOffset, RangeEnd; + + MmLockAddressSpace(&Process->Vm); + + MemoryArea = MmLocateMemoryAreaByAddress(&Process->Vm, Address); + if (MemoryArea == NULL) + { + MmUnlockAddressSpace(&Process->Vm); + return FALSE; + } + + /* Only supported in old Mm for now */ + ASSERT(MemoryArea->Type == MEMORY_AREA_SECTION_VIEW); + /* For file mappings */ + ASSERT(MemoryArea->VadNode.u.VadFlags.VadType != VadImageMap); + + Segment = MemoryArea->SectionData.Segment; + MmLockSectionSegment(Segment); + + SegmentOffset.QuadPart = PAGE_ROUND_DOWN(Address) - MA_GetStartingAddress(MemoryArea) + + MemoryArea->SectionData.ViewOffset.QuadPart; + RangeEnd.QuadPart = PAGE_ROUND_UP((ULONG_PTR)Address + Length) - MA_GetStartingAddress(MemoryArea) + + MemoryArea->SectionData.ViewOffset.QuadPart; + + while (SegmentOffset.QuadPart < RangeEnd.QuadPart) + { + ULONG_PTR Entry = MmGetPageEntrySectionSegment(Segment, &SegmentOffset); + + /* Let any pending read proceed */ + while (MM_IS_WAIT_PTE(Entry)) + { + MmUnlockSectionSegment(Segment); + MmUnlockAddressSpace(&Process->Vm); + MiWaitForPageEvent(NULL, NULL); + MmLockAddressSpace(&Process->Vm); + MmLockSectionSegment(Segment); + Entry = MmGetPageEntrySectionSegment(Segment, &SegmentOffset); + } + + /* We are called from Cc, this can't be backed by the page files */ + ASSERT(!IS_SWAP_FROM_SSE(Entry)); + + /* At this point, there may be a valid page there */ + if (Entry == 0) + { + PFN_NUMBER Page; + NTSTATUS Status; + + /* + * Release all our locks and read in the page from disk + */ + MmSetPageEntrySectionSegment(Segment, &SegmentOffset, MAKE_SWAP_SSE(MM_WAIT_ENTRY)); + MmUnlockSectionSegment(Segment); + MmUnlockAddressSpace(&Process->Vm); + + /* FIXME: Read the whole range at once instead of one page at a time */ + Status = MiReadPage(MemoryArea, SegmentOffset.QuadPart, &Page); + if (!NT_SUCCESS(Status)) + { + /* Reset the Segment entry and fail */ + MmLockSectionSegment(Segment); + MmSetPageEntrySectionSegment(Segment, &SegmentOffset, 0); + MmUnlockSectionSegment(Segment); + MiSetPageEvent(Process, Address); + return Status; + } + + MmLockAddressSpace(&Process->Vm); + MmLockSectionSegment(Segment); + MmSetPageEntrySectionSegment(Segment, &SegmentOffset, MAKE_SSE(Page << PAGE_SHIFT, 1)); + } + SegmentOffset.QuadPart += PAGE_SIZE; + } + + MmUnlockSectionSegment(Segment); + + MmUnlockAddressSpace(&Process->Vm); + return STATUS_SUCCESS; +} + /* EOF */
