mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-09-03 04:13:31 +00:00
[NTOSKRNL]
Implement MiInsertVadEx, replacing duplicated code from NtAllocateVirtualMemory and MiMapViewOfDataSection svn path=/trunk/; revision=64589
This commit is contained in:
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user