[NTOSKRNL]

Implement MiInsertVadEx, replacing duplicated code from NtAllocateVirtualMemory and MiMapViewOfDataSection

svn path=/trunk/; revision=64589
This commit is contained in:
Timo Kreuzer
2014-10-08 00:31:17 +00:00
parent 1b6c4fe27c
commit 40845ae7a6
4 changed files with 171 additions and 218 deletions
+10
View File
@@ -2144,6 +2144,16 @@ MiInsertVad(
IN PEPROCESS Process
);
NTSTATUS
NTAPI
MiInsertVadEx(
_Inout_ PMMVAD Vad,
_In_ ULONG_PTR *BaseAddress,
_In_ SIZE_T ViewSize,
_In_ ULONG_PTR HighestAddress,
_In_ ULONG_PTR Alignment,
_In_ ULONG AllocationType);
VOID
NTAPI
MiInsertBasedSection(
+13 -93
View File
@@ -1252,9 +1252,7 @@ MiMapViewOfDataSection(IN PCONTROL_AREA ControlArea,
IN ULONG AllocationType)
{
PMMVAD_LONG Vad;
PETHREAD Thread = PsGetCurrentThread();
PMMSUPPORT AddressSpace;
ULONG_PTR StartAddress, EndingAddress;
ULONG_PTR StartAddress;
ULONG_PTR ViewSizeInPages;
PSUBSECTION Subsection;
PSEGMENT Segment;
@@ -1263,8 +1261,6 @@ MiMapViewOfDataSection(IN PCONTROL_AREA ControlArea,
ULONG QuotaCharge = 0, QuotaExcess = 0;
PMMPTE PointerPte, LastPte;
MMPTE TempPte;
PMMADDRESS_NODE Parent;
TABLE_SEARCH_RESULT Result;
DPRINT("Mapping ARM3 data section\n");
/* Get the segment for this section */
@@ -1361,6 +1357,7 @@ MiMapViewOfDataSection(IN PCONTROL_AREA ControlArea,
/* Write all the data required in the VAD for handling a fault */
Vad->ControlArea = ControlArea;
Vad->u.VadFlags.CommitCharge = 0;
Vad->u.VadFlags.Protection = ProtectionMask;
Vad->u2.VadFlags2.FileOffset = (ULONG)(SectionOffset->QuadPart >> 16);
Vad->u2.VadFlags2.Inherit = (InheritDisposition == ViewShare);
@@ -1437,100 +1434,23 @@ MiMapViewOfDataSection(IN PCONTROL_AREA ControlArea,
StartAddress = 0;
}
/* Lock the address space and make sure the process is alive */
AddressSpace = MmGetCurrentAddressSpace();
MmLockAddressSpace(AddressSpace);
if (Process->VmDeleted)
{
MmUnlockAddressSpace(AddressSpace);
ExFreePoolWithTag(Vad, 'ldaV');
DPRINT1("The process is dying\n");
return STATUS_PROCESS_IS_TERMINATING;
}
/* Did the caller specify an address? */
if (StartAddress == 0)
{
/* ARM3 does not support these flags yet */
ASSERT(Process->VmTopDown == 0);
ASSERT(ZeroBits == 0);
/* Which way should we search? */
if (AllocationType & MEM_TOP_DOWN)
{
/* No, find an address top-down */
Result = MiFindEmptyAddressRangeDownTree(*ViewSize,
(ULONG_PTR)MM_HIGHEST_VAD_ADDRESS,
_64K,
&Process->VadRoot,
&StartAddress,
&Parent);
}
else
{
/* No, find an address bottom-up */
Result = MiFindEmptyAddressRangeInTree(*ViewSize,
_64K,
&Process->VadRoot,
&Parent,
&StartAddress);
}
/* Check if we found a suitable location */
if (Result == TableFoundNode)
{
DPRINT1("Not enough free space to insert this section!\n");
MmUnlockAddressSpace(AddressSpace);
MiDereferenceControlArea(ControlArea);
ExFreePoolWithTag(Vad, 'ldaV');
return STATUS_CONFLICTING_ADDRESSES;
}
/* Get the ending address, which is the last piece we need for the VAD */
EndingAddress = StartAddress + (ViewSizeInPages * PAGE_SIZE) - 1;
}
else
{
/* Get the ending address, which is the last piece we need for the VAD */
EndingAddress = StartAddress + (ViewSizeInPages * PAGE_SIZE) - 1;
/* Make sure it doesn't conflict with an existing allocation */
Result = MiCheckForConflictingNode(StartAddress >> PAGE_SHIFT,
EndingAddress >> PAGE_SHIFT,
&Process->VadRoot,
&Parent);
if (Result == TableFoundNode)
{
DPRINT1("Conflict with SEC_BASED or manually based section!\n");
MmUnlockAddressSpace(AddressSpace);
MiDereferenceControlArea(ControlArea);
ExFreePoolWithTag(Vad, 'ldaV');
return STATUS_CONFLICTING_ADDRESSES;
}
}
/* Now set the VAD address */
Vad->StartingVpn = StartAddress >> PAGE_SHIFT;
Vad->EndingVpn = EndingAddress >> PAGE_SHIFT;
/* Pretend as if we own the working set */
MiLockProcessWorkingSetUnsafe(Process, Thread);
/* Insert the VAD */
Process->VadRoot.NodeHint = Vad;
MiInsertNode(&Process->VadRoot, (PVOID)Vad, Parent, Result);
/* Release the working set */
MiUnlockProcessWorkingSetUnsafe(Process, Thread);
/* Unlock the address space */
MmUnlockAddressSpace(AddressSpace);
Status = MiInsertVadEx((PMMVAD)Vad,
&StartAddress,
ViewSizeInPages * PAGE_SIZE,
MAXULONG_PTR >> ZeroBits,
MM_VIRTMEM_GRANULARITY,
AllocationType);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Windows stores this for accounting purposes, do so as well */
if (!Segment->u2.FirstMappedVa) Segment->u2.FirstMappedVa = (PVOID)StartAddress;
/* Finally, let the caller know where, and for what size, the view was mapped */
*ViewSize = (ULONG_PTR)EndingAddress - (ULONG_PTR)StartAddress + 1;
*ViewSize = ViewSizeInPages * PAGE_SIZE;
*BaseAddress = (PVOID)StartAddress;
DPRINT("Start and region: 0x%p, 0x%p\n", *BaseAddress, *ViewSize);
return STATUS_SUCCESS;
+132
View File
@@ -193,6 +193,138 @@ MiInsertVad(IN PMMVAD Vad,
MiInsertNode(&Process->VadRoot, (PVOID)Vad, Parent, Result);
}
NTSTATUS
NTAPI
MiInsertVadEx(
_Inout_ PMMVAD Vad,
_In_ ULONG_PTR *BaseAddress,
_In_ SIZE_T ViewSize,
_In_ ULONG_PTR HighestAddress,
_In_ ULONG_PTR Alignment,
_In_ ULONG AllocationType)
{
ULONG_PTR StartingAddress, EndingAddress;
PEPROCESS CurrentProcess;
PETHREAD CurrentThread;
TABLE_SEARCH_RESULT Result;
PMMADDRESS_NODE Parent;
/* Align the view size to pages */
ViewSize = ALIGN_UP_BY(ViewSize, PAGE_SIZE);
/* Get the current process */
CurrentProcess = PsGetCurrentProcess();
/* Acquire the address creation lock and make sure the process is alive */
KeAcquireGuardedMutex(&CurrentProcess->AddressCreationLock);
if (CurrentProcess->VmDeleted)
{
KeReleaseGuardedMutex(&CurrentProcess->AddressCreationLock);
DPRINT1("The process is dying\n");
return STATUS_PROCESS_IS_TERMINATING;
}
/* Did the caller specify an address? */
if (*BaseAddress == 0)
{
/* Make sure HighestAddress is not too large */
HighestAddress = min(HighestAddress, (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS);
/* Which way should we search? */
if ((AllocationType & MEM_TOP_DOWN) || CurrentProcess->VmTopDown)
{
/* Find an address top-down */
Result = MiFindEmptyAddressRangeDownTree(ViewSize,
HighestAddress,
Alignment,
&CurrentProcess->VadRoot,
&StartingAddress,
&Parent);
}
else
{
/* Find an address bottom-up */
Result = MiFindEmptyAddressRangeInTree(ViewSize,
Alignment,
&CurrentProcess->VadRoot,
&Parent,
&StartingAddress);
}
/* Get the ending address, which is the last piece we need for the VAD */
EndingAddress = StartingAddress + ViewSize - 1;
/* Check if we found a suitable location */
if ((Result == TableFoundNode) || (EndingAddress > HighestAddress))
{
DPRINT1("Not enough free space to insert this VAD node!\n");
KeReleaseGuardedMutex(&CurrentProcess->AddressCreationLock);
return STATUS_CONFLICTING_ADDRESSES;
}
ASSERT(StartingAddress != 0);
ASSERT(StartingAddress < (ULONG_PTR)HighestAddress);
ASSERT(EndingAddress > StartingAddress);
}
else
{
/* Calculate the starting and ending address */
StartingAddress = ALIGN_DOWN_BY(*BaseAddress, Alignment);
EndingAddress = StartingAddress + ViewSize - 1;
/* Make sure it doesn't conflict with an existing allocation */
Result = MiCheckForConflictingNode(StartingAddress >> PAGE_SHIFT,
EndingAddress >> PAGE_SHIFT,
&CurrentProcess->VadRoot,
&Parent);
if (Result == TableFoundNode)
{
DPRINT1("Given address conflicts with existing node\n");
KeReleaseGuardedMutex(&CurrentProcess->AddressCreationLock);
return STATUS_CONFLICTING_ADDRESSES;
}
}
/* Now set the VAD address */
Vad->StartingVpn = StartingAddress >> PAGE_SHIFT;
Vad->EndingVpn = EndingAddress >> PAGE_SHIFT;
/* Check if the VAD is to be secured */
if (Vad->u2.VadFlags2.OneSecured)
{
/* This *must* be a long VAD! */
ASSERT(Vad->u2.VadFlags2.LongVad);
/* Yeah this is retarded, I didn't invent it! */
((PMMVAD_LONG)Vad)->u3.Secured.StartVpn = StartingAddress;
((PMMVAD_LONG)Vad)->u3.Secured.EndVpn = EndingAddress;
}
/* Lock the working set */
CurrentThread = PsGetCurrentThread();
MiLockProcessWorkingSetUnsafe(CurrentProcess, CurrentThread);
/* Insert the VAD */
CurrentProcess->VadRoot.NodeHint = Vad;
MiInsertNode(&CurrentProcess->VadRoot, (PVOID)Vad, Parent, Result);
/* Release the working set */
MiUnlockProcessWorkingSetUnsafe(CurrentProcess, CurrentThread);
/* Update the process' virtual size, and peak virtual size */
CurrentProcess->VirtualSize += ViewSize;
if (CurrentProcess->VirtualSize > CurrentProcess->PeakVirtualSize)
{
CurrentProcess->PeakVirtualSize = CurrentProcess->VirtualSize;
}
/* Unlock the address space */
KeReleaseGuardedMutex(&CurrentProcess->AddressCreationLock);
*BaseAddress = StartingAddress;
return STATUS_SUCCESS;
}
VOID
NTAPI
MiInsertBasedSection(IN PSECTION Section)
+16 -125
View File
@@ -4304,12 +4304,12 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
{
PEPROCESS Process;
PMEMORY_AREA MemoryArea;
PFN_NUMBER PageCount;
PMMVAD Vad = NULL, FoundVad;
NTSTATUS Status;
PMMSUPPORT AddressSpace;
PVOID PBaseAddress;
ULONG_PTR PRegionSize, StartingAddress, EndingAddress, HighestAddress;
ULONG_PTR PRegionSize, StartingAddress, EndingAddress;
ULONG_PTR HighestAddress = (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS;
PEPROCESS CurrentProcess = PsGetCurrentProcess();
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
PETHREAD CurrentThread = PsGetCurrentThread();
@@ -4319,7 +4319,6 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
MMPTE TempPte;
PMMPTE PointerPte, PointerPde, LastPte;
TABLE_SEARCH_RESULT Result;
PMMADDRESS_NODE Parent;
PAGED_CODE();
/* Check for valid Zero bits */
@@ -4544,7 +4543,6 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
// This is a blind commit, all we need is the region size
//
PRegionSize = ROUND_TO_PAGES(PRegionSize);
PageCount = BYTES_TO_PAGES(PRegionSize);
EndingAddress = 0;
StartingAddress = 0;
@@ -4563,13 +4561,6 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
goto FailPathNoLock;
}
}
else
{
//
// Use the highest VAD address as maximum
//
HighestAddress = (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS;
}
}
else
{
@@ -4579,8 +4570,8 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
// fall based on the aligned address and the passed in region size
//
EndingAddress = ((ULONG_PTR)PBaseAddress + PRegionSize - 1) | (PAGE_SIZE - 1);
StartingAddress = ROUND_DOWN((ULONG_PTR)PBaseAddress, _64K);
PageCount = BYTES_TO_PAGES(EndingAddress - StartingAddress);
PRegionSize = EndingAddress + 1 - ROUND_DOWN((ULONG_PTR)PBaseAddress, _64K);
StartingAddress = (ULONG_PTR)PBaseAddress;
}
//
@@ -4594,7 +4585,7 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
goto FailPathNoLock;
}
Vad->u.LongFlags = 0;
RtlZeroMemory(Vad, sizeof(MMVAD_LONG));
if (AllocationType & MEM_COMMIT) Vad->u.VadFlags.MemCommit = 1;
Vad->u.VadFlags.Protection = ProtectionMask;
Vad->u.VadFlags.PrivateMemory = 1;
@@ -4602,124 +4593,24 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
Vad->ControlArea = NULL; // For Memory-Area hack
//
// Lock the address space and make sure the process isn't already dead
// Insert the VAD
//
AddressSpace = MmGetCurrentAddressSpace();
MmLockAddressSpace(AddressSpace);
if (Process->VmDeleted)
Status = MiInsertVadEx(Vad,
&StartingAddress,
PRegionSize,
HighestAddress,
MM_VIRTMEM_GRANULARITY,
AllocationType);
if (!NT_SUCCESS(Status))
{
Status = STATUS_PROCESS_IS_TERMINATING;
goto FailPath;
DPRINT1("Failed to insert the VAD!\n");
goto FailPathNoLock;
}
//
// Did we have a base address? If no, find a valid address that is 64KB
// aligned in the VAD tree. Otherwise, make sure that the address range
// which was passed in isn't already conflicting with an existing address
// range.
//
if (!PBaseAddress)
{
/* Which way should we search? */
if ((AllocationType & MEM_TOP_DOWN) || Process->VmTopDown)
{
/* Find an address top-down */
Result = MiFindEmptyAddressRangeDownTree(PRegionSize,
HighestAddress,
_64K,
&Process->VadRoot,
&StartingAddress,
&Parent);
}
else
{
/* Find an address bottom-up */
Result = MiFindEmptyAddressRangeInTree(PRegionSize,
_64K,
&Process->VadRoot,
&Parent,
&StartingAddress);
}
if (Result == TableFoundNode)
{
Status = STATUS_NO_MEMORY;
goto FailPath;
}
//
// Now we know where the allocation ends. Make sure it doesn't end up
// somewhere in kernel mode.
//
ASSERT(StartingAddress != 0);
ASSERT(StartingAddress < (ULONG_PTR)MM_HIGHEST_USER_ADDRESS);
EndingAddress = (StartingAddress + PRegionSize - 1) | (PAGE_SIZE - 1);
ASSERT(EndingAddress > StartingAddress);
if (EndingAddress > HighestAddress)
{
Status = STATUS_NO_MEMORY;
goto FailPath;
}
}
else
{
/* Make sure it doesn't conflict with an existing allocation */
Result = MiCheckForConflictingNode(StartingAddress >> PAGE_SHIFT,
EndingAddress >> PAGE_SHIFT,
&Process->VadRoot,
&Parent);
if (Result == TableFoundNode)
{
//
// The address specified is in conflict!
//
Status = STATUS_CONFLICTING_ADDRESSES;
goto FailPath;
}
}
//
// Write out the VAD fields for this allocation
//
Vad->StartingVpn = StartingAddress >> PAGE_SHIFT;
Vad->EndingVpn = EndingAddress >> PAGE_SHIFT;
//
// FIXME: Should setup VAD bitmap
//
Status = STATUS_SUCCESS;
//
// Lock the working set and insert the VAD into the process VAD tree
//
MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
Process->VadRoot.NodeHint = Vad;
MiInsertNode(&Process->VadRoot, (PVOID)Vad, Parent, Result);
MiUnlockProcessWorkingSetUnsafe(Process, CurrentThread);
//
// Make sure the actual region size is at least as big as the
// requested region size and update the value
//
ASSERT(PRegionSize <= (EndingAddress + 1 - StartingAddress));
PRegionSize = (EndingAddress + 1 - StartingAddress);
//
// Update the virtual size of the process, and if this is now the highest
// virtual size we have ever seen, update the peak virtual size to reflect
// this.
//
Process->VirtualSize += PRegionSize;
if (Process->VirtualSize > Process->PeakVirtualSize)
{
Process->PeakVirtualSize = Process->VirtualSize;
}
//
// Release address space and detach and dereference the target process if
// Detach and dereference the target process if
// it was different from the current process
//
MmUnlockAddressSpace(AddressSpace);
if (Attached) KeUnstackDetachProcess(&ApcState);
if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);