919 lines
23 KiB
C
919 lines
23 KiB
C
/*++
|
||
|
||
Copyright (c) 1989 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
vadtree.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the routine to manipulate the virtual address
|
||
descriptor tree.
|
||
|
||
Author:
|
||
|
||
Lou Perazzoli (loup) 19-May-1989
|
||
Landy Wang (landyw) 02-June-1997
|
||
|
||
Environment:
|
||
|
||
Kernel mode only, working set mutex held, APCs disabled.
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "mi.h"
|
||
|
||
VOID
|
||
VadTreeWalk (
|
||
VOID
|
||
);
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE,MiInsertVad)
|
||
#pragma alloc_text(PAGE,MiRemoveVad)
|
||
#pragma alloc_text(PAGE,MiFindEmptyAddressRange)
|
||
#pragma alloc_text(PAGE, MmPerfVadTreeWalk)
|
||
#if DBG
|
||
#pragma alloc_text(PAGE,VadTreeWalk)
|
||
#endif
|
||
#endif
|
||
|
||
NTSTATUS
|
||
MiInsertVad (
|
||
IN PMMVAD Vad
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function inserts a virtual address descriptor into the tree and
|
||
reorders the splay tree as appropriate.
|
||
|
||
Arguments:
|
||
|
||
Vad - Supplies a pointer to a virtual address descriptor.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG StartBit;
|
||
ULONG EndBit;
|
||
PMMADDRESS_NODE *Root;
|
||
PEPROCESS CurrentProcess;
|
||
SIZE_T RealCharge;
|
||
SIZE_T PageCharge;
|
||
SIZE_T PagesReallyCharged;
|
||
ULONG FirstPage;
|
||
ULONG LastPage;
|
||
SIZE_T PagedPoolCharge;
|
||
LOGICAL ChargedJobCommit;
|
||
NTSTATUS Status;
|
||
RTL_BITMAP VadBitMap;
|
||
#if (_MI_PAGING_LEVELS >= 3)
|
||
ULONG FirstPdPage;
|
||
ULONG LastPdPage;
|
||
#endif
|
||
#if (_MI_PAGING_LEVELS >= 4)
|
||
ULONG FirstPpPage;
|
||
ULONG LastPpPage;
|
||
#endif
|
||
|
||
ASSERT (Vad->EndingVpn >= Vad->StartingVpn);
|
||
|
||
CurrentProcess = PsGetCurrentProcess();
|
||
|
||
//
|
||
// Commit charge of MAX_COMMIT means don't charge quota.
|
||
//
|
||
|
||
if (Vad->u.VadFlags.CommitCharge != MM_MAX_COMMIT) {
|
||
|
||
PageCharge = 0;
|
||
PagedPoolCharge = 0;
|
||
ChargedJobCommit = FALSE;
|
||
|
||
//
|
||
// Charge quota for the nonpaged pool for the VAD. This is
|
||
// done here rather than by using ExAllocatePoolWithQuota
|
||
// so the process object is not referenced by the quota charge.
|
||
//
|
||
|
||
Status = PsChargeProcessNonPagedPoolQuota (CurrentProcess, sizeof(MMVAD));
|
||
if (!NT_SUCCESS(Status)) {
|
||
return STATUS_COMMITMENT_LIMIT;
|
||
}
|
||
|
||
//
|
||
// Charge quota for the prototype PTEs if this is a mapped view.
|
||
//
|
||
|
||
if ((Vad->u.VadFlags.PrivateMemory == 0) &&
|
||
(Vad->ControlArea != NULL)) {
|
||
|
||
PagedPoolCharge =
|
||
(Vad->EndingVpn - Vad->StartingVpn + 1) << PTE_SHIFT;
|
||
|
||
Status = PsChargeProcessPagedPoolQuota (CurrentProcess,
|
||
PagedPoolCharge);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
PagedPoolCharge = 0;
|
||
RealCharge = 0;
|
||
goto Failed;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Add in the charge for page table pages.
|
||
//
|
||
|
||
FirstPage = MiGetPdeIndex (MI_VPN_TO_VA (Vad->StartingVpn));
|
||
LastPage = MiGetPdeIndex (MI_VPN_TO_VA (Vad->EndingVpn));
|
||
|
||
while (FirstPage <= LastPage) {
|
||
|
||
if (!MI_CHECK_BIT (MmWorkingSetList->CommittedPageTables,
|
||
FirstPage)) {
|
||
PageCharge += 1;
|
||
}
|
||
FirstPage += 1;
|
||
}
|
||
|
||
#if (_MI_PAGING_LEVELS >= 4)
|
||
|
||
//
|
||
// Add in the charge for page directory parent pages.
|
||
//
|
||
|
||
FirstPpPage = MiGetPxeIndex (MI_VPN_TO_VA (Vad->StartingVpn));
|
||
LastPpPage = MiGetPxeIndex (MI_VPN_TO_VA (Vad->EndingVpn));
|
||
|
||
while (FirstPpPage <= LastPpPage) {
|
||
|
||
if (!MI_CHECK_BIT (MmWorkingSetList->CommittedPageDirectoryParents,
|
||
FirstPpPage)) {
|
||
PageCharge += 1;
|
||
}
|
||
FirstPpPage += 1;
|
||
}
|
||
#endif
|
||
|
||
#if (_MI_PAGING_LEVELS >= 3)
|
||
|
||
//
|
||
// Add in the charge for page directory pages.
|
||
//
|
||
|
||
FirstPdPage = MiGetPpeIndex (MI_VPN_TO_VA (Vad->StartingVpn));
|
||
LastPdPage = MiGetPpeIndex (MI_VPN_TO_VA (Vad->EndingVpn));
|
||
|
||
while (FirstPdPage <= LastPdPage) {
|
||
|
||
if (!MI_CHECK_BIT (MmWorkingSetList->CommittedPageDirectories,
|
||
FirstPdPage)) {
|
||
PageCharge += 1;
|
||
}
|
||
FirstPdPage += 1;
|
||
}
|
||
#endif
|
||
|
||
RealCharge = Vad->u.VadFlags.CommitCharge + PageCharge;
|
||
|
||
if (RealCharge != 0) {
|
||
|
||
Status = PsChargeProcessPageFileQuota (CurrentProcess, RealCharge);
|
||
if (!NT_SUCCESS (Status)) {
|
||
RealCharge = 0;
|
||
goto Failed;
|
||
}
|
||
|
||
if (CurrentProcess->CommitChargeLimit) {
|
||
if (CurrentProcess->CommitCharge + RealCharge > CurrentProcess->CommitChargeLimit) {
|
||
if (CurrentProcess->Job) {
|
||
PsReportProcessMemoryLimitViolation ();
|
||
}
|
||
goto Failed;
|
||
}
|
||
}
|
||
if (CurrentProcess->JobStatus & PS_JOB_STATUS_REPORT_COMMIT_CHANGES) {
|
||
if (PsChangeJobMemoryUsage(RealCharge) == FALSE) {
|
||
goto Failed;
|
||
}
|
||
ChargedJobCommit = TRUE;
|
||
}
|
||
|
||
if (MiChargeCommitment (RealCharge, CurrentProcess) == FALSE) {
|
||
goto Failed;
|
||
}
|
||
|
||
CurrentProcess->CommitCharge += RealCharge;
|
||
if (CurrentProcess->CommitCharge > CurrentProcess->CommitChargePeak) {
|
||
CurrentProcess->CommitChargePeak = CurrentProcess->CommitCharge;
|
||
}
|
||
|
||
MI_INCREMENT_TOTAL_PROCESS_COMMIT (RealCharge);
|
||
|
||
ASSERT (RealCharge == Vad->u.VadFlags.CommitCharge + PageCharge);
|
||
MM_TRACK_COMMIT (MM_DBG_COMMIT_INSERT_VAD, Vad->u.VadFlags.CommitCharge);
|
||
MM_TRACK_COMMIT (MM_DBG_COMMIT_INSERT_VAD_PT, PageCharge);
|
||
}
|
||
|
||
if (PageCharge != 0) {
|
||
|
||
//
|
||
// Since the commitment was successful, charge the page
|
||
// table pages.
|
||
//
|
||
|
||
PagesReallyCharged = 0;
|
||
|
||
FirstPage = MiGetPdeIndex (MI_VPN_TO_VA (Vad->StartingVpn));
|
||
|
||
while (FirstPage <= LastPage) {
|
||
|
||
if (!MI_CHECK_BIT (MmWorkingSetList->CommittedPageTables,
|
||
FirstPage)) {
|
||
MI_SET_BIT (MmWorkingSetList->CommittedPageTables,
|
||
FirstPage);
|
||
MmWorkingSetList->NumberOfCommittedPageTables += 1;
|
||
|
||
ASSERT32 (MmWorkingSetList->NumberOfCommittedPageTables <
|
||
PD_PER_SYSTEM * PDE_PER_PAGE);
|
||
PagesReallyCharged += 1;
|
||
}
|
||
FirstPage += 1;
|
||
}
|
||
|
||
#if (_MI_PAGING_LEVELS >= 3)
|
||
|
||
//
|
||
// Charge the page directory pages.
|
||
//
|
||
|
||
FirstPdPage = MiGetPpeIndex (MI_VPN_TO_VA (Vad->StartingVpn));
|
||
|
||
while (FirstPdPage <= LastPdPage) {
|
||
|
||
if (!MI_CHECK_BIT (MmWorkingSetList->CommittedPageDirectories,
|
||
FirstPdPage)) {
|
||
|
||
MI_SET_BIT (MmWorkingSetList->CommittedPageDirectories,
|
||
FirstPdPage);
|
||
MmWorkingSetList->NumberOfCommittedPageDirectories += 1;
|
||
ASSERT (MmWorkingSetList->NumberOfCommittedPageDirectories <
|
||
PDE_PER_PAGE);
|
||
PagesReallyCharged += 1;
|
||
}
|
||
FirstPdPage += 1;
|
||
}
|
||
#endif
|
||
|
||
#if (_MI_PAGING_LEVELS >= 4)
|
||
|
||
//
|
||
// Charge the page directory parent pages.
|
||
//
|
||
|
||
FirstPpPage = MiGetPxeIndex (MI_VPN_TO_VA (Vad->StartingVpn));
|
||
|
||
while (FirstPpPage <= LastPpPage) {
|
||
|
||
if (!MI_CHECK_BIT (MmWorkingSetList->CommittedPageDirectoryParents,
|
||
FirstPpPage)) {
|
||
|
||
MI_SET_BIT (MmWorkingSetList->CommittedPageDirectoryParents,
|
||
FirstPpPage);
|
||
MmWorkingSetList->NumberOfCommittedPageDirectoryParents += 1;
|
||
ASSERT (MmWorkingSetList->NumberOfCommittedPageDirectoryParents <
|
||
PDE_PER_PAGE);
|
||
PagesReallyCharged += 1;
|
||
}
|
||
FirstPpPage += 1;
|
||
}
|
||
#endif
|
||
|
||
ASSERT (PageCharge == PagesReallyCharged);
|
||
}
|
||
}
|
||
|
||
Root = (PMMADDRESS_NODE *)&CurrentProcess->VadRoot;
|
||
|
||
//
|
||
// Set the relevant fields in the Vad bitmap.
|
||
//
|
||
|
||
StartBit = (ULONG)(((ULONG_PTR) MI_64K_ALIGN (MI_VPN_TO_VA (Vad->StartingVpn))) / X64K);
|
||
EndBit = (ULONG) (((ULONG_PTR) MI_64K_ALIGN (MI_VPN_TO_VA (Vad->EndingVpn))) / X64K);
|
||
|
||
//
|
||
// Initialize the bitmap inline for speed.
|
||
//
|
||
|
||
VadBitMap.SizeOfBitMap = MiLastVadBit + 1;
|
||
VadBitMap.Buffer = VAD_BITMAP_SPACE;
|
||
|
||
//
|
||
// Note VADs like the PEB & TEB start on page (not 64K) boundaries so
|
||
// for these, the relevant bits may already be set.
|
||
//
|
||
|
||
#if defined (_WIN64) || defined (_X86PAE_)
|
||
if (EndBit > MiLastVadBit) {
|
||
EndBit = MiLastVadBit;
|
||
}
|
||
|
||
//
|
||
// Only the first (PAGE_SIZE*8*64K) of VA space on NT64 is bitmapped.
|
||
//
|
||
|
||
if (StartBit <= MiLastVadBit) {
|
||
RtlSetBits (&VadBitMap, StartBit, EndBit - StartBit + 1);
|
||
}
|
||
#else
|
||
RtlSetBits (&VadBitMap, StartBit, EndBit - StartBit + 1);
|
||
#endif
|
||
|
||
if (MmWorkingSetList->VadBitMapHint == StartBit) {
|
||
MmWorkingSetList->VadBitMapHint = EndBit + 1;
|
||
}
|
||
|
||
//
|
||
// Set the hint field in the process to this Vad.
|
||
//
|
||
|
||
CurrentProcess->VadHint = Vad;
|
||
|
||
if (CurrentProcess->VadFreeHint != NULL) {
|
||
if (((ULONG)((PMMVAD)CurrentProcess->VadFreeHint)->EndingVpn +
|
||
MI_VA_TO_VPN (X64K)) >=
|
||
Vad->StartingVpn) {
|
||
CurrentProcess->VadFreeHint = Vad;
|
||
}
|
||
}
|
||
|
||
MiInsertNode ((PMMADDRESS_NODE)Vad, Root);
|
||
CurrentProcess->NumberOfVads += 1;
|
||
return STATUS_SUCCESS;
|
||
|
||
Failed:
|
||
|
||
//
|
||
// Return any quotas charged thus far.
|
||
//
|
||
|
||
PsReturnProcessNonPagedPoolQuota (CurrentProcess, sizeof(MMVAD));
|
||
|
||
if (PagedPoolCharge != 0) {
|
||
PsReturnProcessPagedPoolQuota (CurrentProcess, PagedPoolCharge);
|
||
}
|
||
|
||
if (RealCharge != 0) {
|
||
PsReturnProcessPageFileQuota (CurrentProcess, RealCharge);
|
||
}
|
||
|
||
if (ChargedJobCommit == TRUE) {
|
||
PsChangeJobMemoryUsage(-(SSIZE_T)RealCharge);
|
||
}
|
||
|
||
return STATUS_COMMITMENT_LIMIT;
|
||
}
|
||
|
||
|
||
VOID
|
||
MiRemoveVad (
|
||
IN PMMVAD Vad
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function removes a virtual address descriptor from the tree and
|
||
reorders the splay tree as appropriate. If any quota or commitment
|
||
was charged by the VAD (as indicated by the CommitCharge field) it
|
||
is released.
|
||
|
||
Arguments:
|
||
|
||
Vad - Supplies a pointer to a virtual address descriptor.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PMMADDRESS_NODE *Root;
|
||
PEPROCESS CurrentProcess;
|
||
SIZE_T RealCharge;
|
||
PLIST_ENTRY Next;
|
||
PMMSECURE_ENTRY Entry;
|
||
|
||
CurrentProcess = PsGetCurrentProcess();
|
||
|
||
#if defined(_MIALT4K_)
|
||
if (((Vad->u.VadFlags.PrivateMemory) && (Vad->u.VadFlags.NoChange == 0))
|
||
||
|
||
(Vad->u2.VadFlags2.LongVad == 0)) {
|
||
|
||
NOTHING;
|
||
}
|
||
else {
|
||
ASSERT ((((PMMVAD_LONG)Vad)->AliasInformation == NULL) || (CurrentProcess->Wow64Process != NULL));
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// Commit charge of MAX_COMMIT means don't charge quota.
|
||
//
|
||
|
||
if (Vad->u.VadFlags.CommitCharge != MM_MAX_COMMIT) {
|
||
|
||
//
|
||
// Return the quota charge to the process.
|
||
//
|
||
|
||
PsReturnProcessNonPagedPoolQuota (CurrentProcess, sizeof(MMVAD));
|
||
|
||
if ((Vad->u.VadFlags.PrivateMemory == 0) &&
|
||
(Vad->ControlArea != NULL)) {
|
||
PsReturnProcessPagedPoolQuota (CurrentProcess,
|
||
(Vad->EndingVpn - Vad->StartingVpn + 1) << PTE_SHIFT);
|
||
}
|
||
|
||
RealCharge = Vad->u.VadFlags.CommitCharge;
|
||
|
||
if (RealCharge != 0) {
|
||
|
||
PsReturnProcessPageFileQuota (CurrentProcess, RealCharge);
|
||
|
||
if ((Vad->u.VadFlags.PrivateMemory == 0) &&
|
||
(Vad->ControlArea != NULL)) {
|
||
|
||
#if 0 //commented out so page file quota is meaningful.
|
||
if (Vad->ControlArea->FilePointer == NULL) {
|
||
|
||
//
|
||
// Don't release commitment for the page file space
|
||
// occupied by a page file section. This will be charged
|
||
// as the shared memory is committed.
|
||
//
|
||
|
||
RealCharge -= BYTES_TO_PAGES ((ULONG)Vad->EndingVa -
|
||
(ULONG)Vad->StartingVa);
|
||
}
|
||
#endif
|
||
}
|
||
|
||
MiReturnCommitment (RealCharge);
|
||
MM_TRACK_COMMIT (MM_DBG_COMMIT_RETURN_VAD, RealCharge);
|
||
if (CurrentProcess->JobStatus & PS_JOB_STATUS_REPORT_COMMIT_CHANGES) {
|
||
PsChangeJobMemoryUsage(-(SSIZE_T)RealCharge);
|
||
}
|
||
CurrentProcess->CommitCharge -= RealCharge;
|
||
|
||
MI_INCREMENT_TOTAL_PROCESS_COMMIT (0 - RealCharge);
|
||
}
|
||
}
|
||
|
||
if (Vad == CurrentProcess->VadFreeHint) {
|
||
CurrentProcess->VadFreeHint = MiGetPreviousVad (Vad);
|
||
}
|
||
|
||
Root = (PMMADDRESS_NODE *)&CurrentProcess->VadRoot;
|
||
|
||
MiRemoveNode ( (PMMADDRESS_NODE)Vad, Root);
|
||
|
||
ASSERT (CurrentProcess->NumberOfVads >= 1);
|
||
CurrentProcess->NumberOfVads -= 1;
|
||
|
||
if (Vad->u.VadFlags.NoChange) {
|
||
if (Vad->u2.VadFlags2.MultipleSecured) {
|
||
|
||
//
|
||
// Free the oustanding pool allocations.
|
||
//
|
||
|
||
Next = ((PMMVAD_LONG) Vad)->u3.List.Flink;
|
||
do {
|
||
Entry = CONTAINING_RECORD( Next,
|
||
MMSECURE_ENTRY,
|
||
List);
|
||
|
||
Next = Entry->List.Flink;
|
||
ExFreePool (Entry);
|
||
} while (Next != &((PMMVAD_LONG)Vad)->u3.List);
|
||
}
|
||
}
|
||
|
||
//
|
||
// If the VadHint was the removed Vad, change the Hint.
|
||
|
||
if (CurrentProcess->VadHint == Vad) {
|
||
CurrentProcess->VadHint = CurrentProcess->VadRoot;
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
PMMVAD
|
||
FASTCALL
|
||
MiLocateAddress (
|
||
IN PVOID VirtualAddress
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The function locates the virtual address descriptor which describes
|
||
a given address.
|
||
|
||
Arguments:
|
||
|
||
VirtualAddress - Supplies the virtual address to locate a descriptor
|
||
for.
|
||
|
||
Return Value:
|
||
|
||
Returns a pointer to the virtual address descriptor which contains
|
||
the supplied virtual address or NULL if none was located.
|
||
|
||
--*/
|
||
|
||
{
|
||
PMMVAD FoundVad;
|
||
PEPROCESS CurrentProcess;
|
||
ULONG_PTR Vpn;
|
||
|
||
CurrentProcess = PsGetCurrentProcess();
|
||
|
||
if (CurrentProcess->VadHint == NULL) {
|
||
return NULL;
|
||
}
|
||
|
||
Vpn = MI_VA_TO_VPN (VirtualAddress);
|
||
if ((Vpn >= ((PMMADDRESS_NODE)CurrentProcess->VadHint)->StartingVpn) &&
|
||
(Vpn <= ((PMMADDRESS_NODE)CurrentProcess->VadHint)->EndingVpn)) {
|
||
|
||
return (PMMVAD)CurrentProcess->VadHint;
|
||
}
|
||
|
||
FoundVad = (PMMVAD)MiLocateAddressInTree ( Vpn,
|
||
(PMMADDRESS_NODE *)&(CurrentProcess->VadRoot));
|
||
|
||
if (FoundVad != NULL) {
|
||
CurrentProcess->VadHint = (PVOID)FoundVad;
|
||
}
|
||
return FoundVad;
|
||
}
|
||
|
||
NTSTATUS
|
||
MiFindEmptyAddressRange (
|
||
IN SIZE_T SizeOfRange,
|
||
IN ULONG_PTR Alignment,
|
||
IN ULONG QuickCheck,
|
||
IN PVOID *Base
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The function examines the virtual address descriptors to locate
|
||
an unused range of the specified size and returns the starting
|
||
address of the range.
|
||
|
||
Arguments:
|
||
|
||
SizeOfRange - Supplies the size in bytes of the range to locate.
|
||
|
||
Alignment - Supplies the alignment for the address. Must be
|
||
a power of 2 and greater than the page_size.
|
||
|
||
QuickCheck - Supplies a zero if a quick check for free memory
|
||
after the VadFreeHint exists, non-zero if checking
|
||
should start at the lowest address.
|
||
|
||
Base - Receives the starting address of a suitable range on success.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG FirstBitValue;
|
||
ULONG StartPosition;
|
||
ULONG BitsNeeded;
|
||
PMMVAD NextVad;
|
||
PMMVAD FreeHint;
|
||
PEPROCESS CurrentProcess;
|
||
PVOID StartingVa;
|
||
PVOID EndingVa;
|
||
NTSTATUS Status;
|
||
RTL_BITMAP VadBitMap;
|
||
|
||
CurrentProcess = PsGetCurrentProcess();
|
||
|
||
if (QuickCheck == 0) {
|
||
|
||
//
|
||
// Initialize the bitmap inline for speed.
|
||
//
|
||
|
||
VadBitMap.SizeOfBitMap = MiLastVadBit + 1;
|
||
VadBitMap.Buffer = VAD_BITMAP_SPACE;
|
||
|
||
//
|
||
// Skip the first bit here as we don't generally recommend
|
||
// that applications map virtual address zero.
|
||
//
|
||
|
||
FirstBitValue = *((PULONG)VAD_BITMAP_SPACE);
|
||
|
||
*((PULONG)VAD_BITMAP_SPACE) = (FirstBitValue | 0x1);
|
||
|
||
BitsNeeded = (ULONG) ((MI_ROUND_TO_64K (SizeOfRange)) / X64K);
|
||
|
||
StartPosition = RtlFindClearBits (&VadBitMap,
|
||
BitsNeeded,
|
||
MmWorkingSetList->VadBitMapHint);
|
||
|
||
if (FirstBitValue & 0x1) {
|
||
FirstBitValue = (ULONG)-1;
|
||
}
|
||
else {
|
||
FirstBitValue = (ULONG)~0x1;
|
||
}
|
||
|
||
*((PULONG)VAD_BITMAP_SPACE) &= FirstBitValue;
|
||
|
||
if (StartPosition != NO_BITS_FOUND) {
|
||
*Base = (PVOID) (((ULONG_PTR)StartPosition) * X64K);
|
||
#if DBG
|
||
if (MiCheckForConflictingVad (CurrentProcess, *Base, (ULONG_PTR)*Base + SizeOfRange - 1) != NULL) {
|
||
DbgPrint ("MiFindEmptyAddressRange: overlapping VAD %p %p\n", *Base, SizeOfRange);
|
||
DbgBreakPoint ();
|
||
}
|
||
#endif
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
FreeHint = CurrentProcess->VadFreeHint;
|
||
|
||
if (FreeHint != NULL) {
|
||
|
||
EndingVa = MI_VPN_TO_VA_ENDING (FreeHint->EndingVpn);
|
||
NextVad = MiGetNextVad (FreeHint);
|
||
|
||
if (NextVad == NULL) {
|
||
|
||
if (SizeOfRange <
|
||
(((ULONG_PTR)MM_HIGHEST_USER_ADDRESS + 1) -
|
||
MI_ROUND_TO_SIZE((ULONG_PTR)EndingVa, Alignment))) {
|
||
*Base = (PVOID) MI_ROUND_TO_SIZE((ULONG_PTR)EndingVa,
|
||
Alignment);
|
||
return STATUS_SUCCESS;
|
||
}
|
||
}
|
||
else {
|
||
StartingVa = MI_VPN_TO_VA (NextVad->StartingVpn);
|
||
|
||
if (SizeOfRange <
|
||
((ULONG_PTR)StartingVa -
|
||
MI_ROUND_TO_SIZE((ULONG_PTR)EndingVa, Alignment))) {
|
||
|
||
//
|
||
// Check to ensure that the ending address aligned upwards
|
||
// is not greater than the starting address.
|
||
//
|
||
|
||
if ((ULONG_PTR)StartingVa >
|
||
MI_ROUND_TO_SIZE((ULONG_PTR)EndingVa,Alignment)) {
|
||
|
||
*Base = (PVOID)MI_ROUND_TO_SIZE((ULONG_PTR)EndingVa,
|
||
Alignment);
|
||
return STATUS_SUCCESS;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
Status = MiFindEmptyAddressRangeInTree (
|
||
SizeOfRange,
|
||
Alignment,
|
||
(PMMADDRESS_NODE)(CurrentProcess->VadRoot),
|
||
(PMMADDRESS_NODE *)&CurrentProcess->VadFreeHint,
|
||
Base);
|
||
|
||
return Status;
|
||
}
|
||
|
||
#if DBG
|
||
VOID
|
||
VadTreeWalk (
|
||
VOID
|
||
)
|
||
|
||
{
|
||
NodeTreeWalk ( (PMMADDRESS_NODE)(PsGetCurrentProcess()->VadRoot));
|
||
|
||
return;
|
||
}
|
||
#endif
|
||
|
||
LOGICAL
|
||
MiCheckForConflictingVadExistence (
|
||
IN PEPROCESS Process,
|
||
IN PVOID StartingAddress,
|
||
IN PVOID EndingAddress
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The function determines if any addresses between a given starting and
|
||
ending address is contained within a virtual address descriptor.
|
||
|
||
Arguments:
|
||
|
||
StartingAddress - Supplies the virtual address to locate a containing
|
||
descriptor.
|
||
|
||
EndingAddress - Supplies the virtual address to locate a containing
|
||
descriptor.
|
||
|
||
Return Value:
|
||
|
||
TRUE if the VAD if found, FALSE if not.
|
||
|
||
Environment:
|
||
|
||
Kernel mode, process address creation mutex held.
|
||
|
||
--*/
|
||
|
||
{
|
||
#if 0
|
||
ULONG StartBit;
|
||
ULONG EndBit;
|
||
|
||
if (MiLastVadBit != 0) {
|
||
|
||
StartBit = (ULONG) (((ULONG_PTR) MI_64K_ALIGN (StartingAddress)) / X64K);
|
||
EndBit = (ULONG) (((ULONG_PTR) MI_64K_ALIGN (EndingAddress)) / X64K);
|
||
|
||
ASSERT (StartBit <= EndBit);
|
||
if (EndBit > MiLastVadBit) {
|
||
ASSERT (FALSE);
|
||
EndBit = MiLastVadBit;
|
||
if (StartBit > MiLastVadBit) {
|
||
StartBit = MiLastVadBit;
|
||
}
|
||
}
|
||
|
||
while (StartBit <= EndBit) {
|
||
if (MI_CHECK_BIT (((PULONG)VAD_BITMAP_SPACE), StartBit) != 0) {
|
||
return TRUE;
|
||
}
|
||
StartBit += 1;
|
||
}
|
||
|
||
ASSERT (MiCheckForConflictingVad (Process, StartingAddress, EndingAddress) == NULL);
|
||
return FALSE;
|
||
}
|
||
#endif
|
||
|
||
if (MiCheckForConflictingVad (Process, StartingAddress, EndingAddress) != NULL) {
|
||
return TRUE;
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
PFILE_OBJECT *
|
||
MmPerfVadTreeWalk (
|
||
IN PEPROCESS Process
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine walks through the VAD tree to find all files mapped
|
||
into the specified process. It returns a pointer to a pool allocation
|
||
containing the referenced file object pointers.
|
||
|
||
Arguments:
|
||
|
||
Process - Supplies the process to walk.
|
||
|
||
Return Value:
|
||
|
||
Returns a pointer to a NULL terminated pool allocation containing
|
||
the file object pointers which have been referenced in the process,
|
||
NULL if the memory could not be allocated.
|
||
|
||
It is also the responsibility of the caller to dereference each
|
||
file object in the list and then free the returned pool.
|
||
|
||
Environment:
|
||
|
||
PASSIVE_LEVEL, arbitrary thread context.
|
||
|
||
--*/
|
||
{
|
||
PMMVAD Vad;
|
||
PMMVAD NextVad;
|
||
ULONG VadCount;
|
||
PFILE_OBJECT *File;
|
||
PFILE_OBJECT *FileObjects;
|
||
|
||
ASSERT (KeGetCurrentIrql () == PASSIVE_LEVEL);
|
||
|
||
LOCK_ADDRESS_SPACE(Process);
|
||
|
||
Vad = Process->VadRoot;
|
||
|
||
if (Vad == NULL) {
|
||
ASSERT (Process->NumberOfVads == 0);
|
||
UNLOCK_ADDRESS_SPACE (Process);
|
||
return NULL;
|
||
}
|
||
|
||
ASSERT (Process->NumberOfVads != 0);
|
||
|
||
//
|
||
// Allocate one additional entry for the NULL terminator.
|
||
//
|
||
|
||
VadCount = Process->NumberOfVads + 1;
|
||
|
||
FileObjects = (PFILE_OBJECT *) ExAllocatePoolWithTag (
|
||
PagedPool,
|
||
VadCount * sizeof(PFILE_OBJECT),
|
||
'01pM');
|
||
|
||
if (FileObjects == NULL) {
|
||
UNLOCK_ADDRESS_SPACE (Process);
|
||
return NULL;
|
||
}
|
||
|
||
File = FileObjects;
|
||
|
||
while (Vad->LeftChild != NULL) {
|
||
Vad = Vad->LeftChild;
|
||
}
|
||
|
||
if ((!Vad->u.VadFlags.PrivateMemory) &&
|
||
(Vad->ControlArea != NULL) &&
|
||
(Vad->ControlArea->FilePointer != NULL)) {
|
||
|
||
*File = Vad->ControlArea->FilePointer;
|
||
ObReferenceObject (*File);
|
||
File += 1;
|
||
}
|
||
|
||
for (;;) {
|
||
NextVad = (PMMVAD) MiGetNextNode ((PMMADDRESS_NODE)Vad);
|
||
|
||
if (NextVad == NULL) {
|
||
break;
|
||
}
|
||
|
||
Vad = (PMMVAD) NextVad;
|
||
|
||
if ((!Vad->u.VadFlags.PrivateMemory) &&
|
||
(Vad->ControlArea != NULL) &&
|
||
(Vad->ControlArea->FilePointer != NULL)) {
|
||
|
||
*File = Vad->ControlArea->FilePointer;
|
||
ObReferenceObject (*File);
|
||
File += 1;
|
||
}
|
||
|
||
Vad = NextVad;
|
||
}
|
||
|
||
ASSERT (File < FileObjects + VadCount);
|
||
|
||
UNLOCK_ADDRESS_SPACE(Process);
|
||
|
||
*File = NULL;
|
||
|
||
return FileObjects;
|
||
}
|