https://git.reactos.org/?p=reactos.git;a=commitdiff;h=8d701598fb1ac1da99df48...
commit 8d701598fb1ac1da99df489e365c93b8a9fc6647 Author: Thomas Faber thomas.faber@reactos.org AuthorDate: Mon Dec 27 20:00:45 2021 -0500 Commit: Thomas Faber thomas.faber@reactos.org CommitDate: Sat Jan 22 15:07:06 2022 -0500
[NTOS:MM] Implement partial virtual region releases. CORE-17938
Fixes boot with MS videoprt.sys (and some apitests). --- ntoskrnl/mm/ARM3/virtual.c | 100 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 84 insertions(+), 16 deletions(-)
diff --git a/ntoskrnl/mm/ARM3/virtual.c b/ntoskrnl/mm/ARM3/virtual.c index abe0e810074..f178edbb909 100644 --- a/ntoskrnl/mm/ARM3/virtual.c +++ b/ntoskrnl/mm/ARM3/virtual.c @@ -5210,8 +5210,10 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle, SIZE_T PRegionSize; PVOID PBaseAddress; LONG_PTR AlreadyDecommitted, CommitReduction = 0; + LONG_PTR FirstCommit; ULONG_PTR StartingAddress, EndingAddress; PMMVAD Vad; + PMMVAD NewVad; NTSTATUS Status; PEPROCESS Process; PMMSUPPORT AddressSpace; @@ -5436,6 +5438,8 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle, // if ((EndingAddress >> PAGE_SHIFT) == Vad->EndingVpn) { + // + // Case D (freeing the entire region) // // This is the easiest one to handle -- it is identical to // the code path above when the caller sets a zero region size @@ -5447,16 +5451,24 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle, } else { + // + // Case A (freeing a part at the beginning) // // This case is pretty easy too -- we compute a bunch of // pages to decommit, and then push the VAD's starting address // a bit further down, then decrement the commit charge // - // NOT YET IMPLEMENTED IN ARM3. - // - DPRINT1("Case A not handled\n"); - Status = STATUS_FREE_VM_NOT_AT_BASE; - goto FailPath; + MiLockProcessWorkingSetUnsafe(Process, CurrentThread); + CommitReduction = MiCalculatePageCommitment(StartingAddress, + EndingAddress, + Vad, + Process); + Vad->u.VadFlags.CommitCharge -= CommitReduction; + // For ReactOS: shrink the corresponding memory area + ASSERT(Vad->StartingVpn == MemoryArea->VadNode.StartingVpn); + ASSERT(Vad->EndingVpn == MemoryArea->VadNode.EndingVpn); + Vad->StartingVpn = (EndingAddress + 1) >> PAGE_SHIFT; + MemoryArea->VadNode.StartingVpn = Vad->StartingVpn;
// // After analyzing the VAD, set it to NULL so that we don't @@ -5472,8 +5484,8 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle, // if ((EndingAddress >> PAGE_SHIFT) == Vad->EndingVpn) { - PMEMORY_AREA MemoryArea; - + // + // Case C (freeing a part at the end) // // This is pretty easy and similar to case A. We compute the // amount of pages to decommit, update the VAD's commit charge @@ -5487,7 +5499,6 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle, Process); Vad->u.VadFlags.CommitCharge -= CommitReduction; // For ReactOS: shrink the corresponding memory area - MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, (PVOID)StartingAddress); ASSERT(Vad->StartingVpn == MemoryArea->VadNode.StartingVpn); ASSERT(Vad->EndingVpn == MemoryArea->VadNode.EndingVpn); Vad->EndingVpn = (StartingAddress - 1) >> PAGE_SHIFT; @@ -5496,16 +5507,73 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle, else { // - // This is case B and the hardest one. Because we are removing - // a chunk of memory from the very middle of the VAD, we must - // actually split the VAD into two new VADs and compute the - // commit charges for each of them, and reinsert new charges. + // Case B (freeing a part in the middle) + // + // This is the hardest one. Because we are removing a chunk + // of memory from the very middle of the VAD, we must actually + // split the VAD into two new VADs and compute the commit + // charges for each of them, and reinsert new charges. + // + NewVad = ExAllocatePoolZero(NonPagedPool, sizeof(MMVAD_LONG), 'SdaV'); + if (NewVad == NULL) + { + DPRINT1("Failed to allocate a VAD!\n"); + Status = STATUS_INSUFFICIENT_RESOURCES; + goto FailPath; + } + + // + // This new VAD describes the second chunk, so we keep the end + // address of the original and adjust the start to point past + // the released region. + // The commit charge will be calculated below. + // + NewVad->StartingVpn = (EndingAddress + 1) >> PAGE_SHIFT; + NewVad->EndingVpn = Vad->EndingVpn; + NewVad->u.LongFlags = Vad->u.LongFlags; + NewVad->u.VadFlags.CommitCharge = 0; + ASSERT(NewVad->EndingVpn >= NewVad->StartingVpn); + + // + // TODO: charge quota for the new VAD + // + + // + // Get the commit charge for the released region + // + MiLockProcessWorkingSetUnsafe(Process, CurrentThread); + CommitReduction = MiCalculatePageCommitment(StartingAddress, + EndingAddress, + Vad, + Process); + + // + // Adjust the end of the original VAD (first chunk). + // For ReactOS: shrink the corresponding memory area + // + ASSERT(Vad->StartingVpn == MemoryArea->VadNode.StartingVpn); + ASSERT(Vad->EndingVpn == MemoryArea->VadNode.EndingVpn); + Vad->EndingVpn = (StartingAddress - 1) >> PAGE_SHIFT; + MemoryArea->VadNode.EndingVpn = Vad->EndingVpn; + + // + // Now the addresses for both VADs are consistent, + // so insert the new one. + // ReactOS: This will take care of creating a second MEMORY_AREA. + // + MiInsertVad(NewVad, &Process->VadRoot); + // - // NOT YET IMPLEMENTED IN ARM3. + // Calculate the commit charge for the first split. + // The second chunk's size is the original size, minus the + // released region's size, minus this first chunk. // - DPRINT1("Case B not handled\n"); - Status = STATUS_FREE_VM_NOT_AT_BASE; - goto FailPath; + FirstCommit = MiCalculatePageCommitment(Vad->StartingVpn << PAGE_SHIFT, + StartingAddress - 1, + Vad, + Process); + NewVad->u.VadFlags.CommitCharge = Vad->u.VadFlags.CommitCharge - CommitReduction - FirstCommit; + Vad->u.VadFlags.CommitCharge = FirstCommit; }
//