https://git.reactos.org/?p=reactos.git;a=commitdiff;h=8d701598fb1ac1da99df4…
commit 8d701598fb1ac1da99df489e365c93b8a9fc6647
Author: Thomas Faber <thomas.faber(a)reactos.org>
AuthorDate: Mon Dec 27 20:00:45 2021 -0500
Commit: Thomas Faber <thomas.faber(a)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;
}
//