mirror of
https://github.com/reactos/reactos.git
synced 2024-12-29 02:25:17 +00:00
[NTOS:MM] Implement partial virtual region releases. CORE-17938
Fixes boot with MS videoprt.sys (and some apitests).
This commit is contained in:
parent
7014cf04b1
commit
8d701598fb
1 changed files with 84 additions and 16 deletions
|
@ -5210,8 +5210,10 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle,
|
||||||
SIZE_T PRegionSize;
|
SIZE_T PRegionSize;
|
||||||
PVOID PBaseAddress;
|
PVOID PBaseAddress;
|
||||||
LONG_PTR AlreadyDecommitted, CommitReduction = 0;
|
LONG_PTR AlreadyDecommitted, CommitReduction = 0;
|
||||||
|
LONG_PTR FirstCommit;
|
||||||
ULONG_PTR StartingAddress, EndingAddress;
|
ULONG_PTR StartingAddress, EndingAddress;
|
||||||
PMMVAD Vad;
|
PMMVAD Vad;
|
||||||
|
PMMVAD NewVad;
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
PEPROCESS Process;
|
PEPROCESS Process;
|
||||||
PMMSUPPORT AddressSpace;
|
PMMSUPPORT AddressSpace;
|
||||||
|
@ -5436,6 +5438,8 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle,
|
||||||
//
|
//
|
||||||
if ((EndingAddress >> PAGE_SHIFT) == Vad->EndingVpn)
|
if ((EndingAddress >> PAGE_SHIFT) == Vad->EndingVpn)
|
||||||
{
|
{
|
||||||
|
//
|
||||||
|
// Case D (freeing the entire region)
|
||||||
//
|
//
|
||||||
// This is the easiest one to handle -- it is identical to
|
// This is the easiest one to handle -- it is identical to
|
||||||
// the code path above when the caller sets a zero region size
|
// the code path above when the caller sets a zero region size
|
||||||
|
@ -5447,16 +5451,24 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
//
|
||||||
|
// Case A (freeing a part at the beginning)
|
||||||
//
|
//
|
||||||
// This case is pretty easy too -- we compute a bunch of
|
// This case is pretty easy too -- we compute a bunch of
|
||||||
// pages to decommit, and then push the VAD's starting address
|
// pages to decommit, and then push the VAD's starting address
|
||||||
// a bit further down, then decrement the commit charge
|
// a bit further down, then decrement the commit charge
|
||||||
//
|
//
|
||||||
// NOT YET IMPLEMENTED IN ARM3.
|
MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
|
||||||
//
|
CommitReduction = MiCalculatePageCommitment(StartingAddress,
|
||||||
DPRINT1("Case A not handled\n");
|
EndingAddress,
|
||||||
Status = STATUS_FREE_VM_NOT_AT_BASE;
|
Vad,
|
||||||
goto FailPath;
|
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
|
// 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)
|
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
|
// This is pretty easy and similar to case A. We compute the
|
||||||
// amount of pages to decommit, update the VAD's commit charge
|
// amount of pages to decommit, update the VAD's commit charge
|
||||||
|
@ -5487,7 +5499,6 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle,
|
||||||
Process);
|
Process);
|
||||||
Vad->u.VadFlags.CommitCharge -= CommitReduction;
|
Vad->u.VadFlags.CommitCharge -= CommitReduction;
|
||||||
// For ReactOS: shrink the corresponding memory area
|
// For ReactOS: shrink the corresponding memory area
|
||||||
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, (PVOID)StartingAddress);
|
|
||||||
ASSERT(Vad->StartingVpn == MemoryArea->VadNode.StartingVpn);
|
ASSERT(Vad->StartingVpn == MemoryArea->VadNode.StartingVpn);
|
||||||
ASSERT(Vad->EndingVpn == MemoryArea->VadNode.EndingVpn);
|
ASSERT(Vad->EndingVpn == MemoryArea->VadNode.EndingVpn);
|
||||||
Vad->EndingVpn = (StartingAddress - 1) >> PAGE_SHIFT;
|
Vad->EndingVpn = (StartingAddress - 1) >> PAGE_SHIFT;
|
||||||
|
@ -5496,16 +5507,73 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
// This is case B and the hardest one. Because we are removing
|
// Case B (freeing a part in the middle)
|
||||||
// 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.
|
|
||||||
//
|
//
|
||||||
// NOT YET IMPLEMENTED IN ARM3.
|
// 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.
|
||||||
//
|
//
|
||||||
DPRINT1("Case B not handled\n");
|
NewVad = ExAllocatePoolZero(NonPagedPool, sizeof(MMVAD_LONG), 'SdaV');
|
||||||
Status = STATUS_FREE_VM_NOT_AT_BASE;
|
if (NewVad == NULL)
|
||||||
goto FailPath;
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
Loading…
Reference in a new issue