https://git.reactos.org/?p=reactos.git;a=commitdiff;h=8d701598fb1ac1da99df489e365c93b8a9fc6647

commit 8d701598fb1ac1da99df489e365c93b8a9fc6647
Author:     Thomas Faber <[email protected]>
AuthorDate: Mon Dec 27 20:00:45 2021 -0500
Commit:     Thomas Faber <[email protected]>
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;
                 }
 
                 //

Reply via email to