230 lines
5.2 KiB
C
230 lines
5.2 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1989 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
vadtree.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module implements the routines to manipulate the virtual address
|
||
|
descriptor tree.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "mi.h"
|
||
|
|
||
|
VOID
|
||
|
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:
|
||
|
|
||
|
None - An exception is raised if quota is exceeded.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PMMADDRESS_NODE *Root;
|
||
|
|
||
|
ASSERT (Vad->EndingVpn >= Vad->StartingVpn);
|
||
|
|
||
|
Root = &MmVadRoot;
|
||
|
|
||
|
//
|
||
|
// Set the hint field in the process to this Vad.
|
||
|
//
|
||
|
|
||
|
MmVadHint = (PMMADDRESS_NODE)Vad;
|
||
|
|
||
|
if (MmVadFreeHint != NULL) {
|
||
|
if (((ULONG)((PMMVAD)MmVadFreeHint)->EndingVpn +
|
||
|
MI_VA_TO_VPN (X64K)) >=
|
||
|
Vad->StartingVpn) {
|
||
|
MmVadFreeHint = (PMMADDRESS_NODE)Vad;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
MiInsertNode ( (PMMADDRESS_NODE)Vad, Root);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
|
||
|
if (Vad == (PMMVAD)MmVadFreeHint) {
|
||
|
MmVadFreeHint = (PMMADDRESS_NODE)MiGetPreviousVad (Vad);
|
||
|
}
|
||
|
|
||
|
Root = &MmVadRoot;
|
||
|
|
||
|
MiRemoveNode ( (PMMADDRESS_NODE)Vad, Root);
|
||
|
|
||
|
//
|
||
|
// If the VadHint was the removed Vad, change the Hint.
|
||
|
|
||
|
if (MmVadHint == (PMMADDRESS_NODE)Vad) {
|
||
|
MmVadHint = MmVadRoot;
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
ULONG_PTR Vpn;
|
||
|
|
||
|
if (MmVadHint == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
Vpn = MI_VA_TO_VPN (VirtualAddress);
|
||
|
if ((Vpn >= MmVadHint->StartingVpn) &&
|
||
|
(Vpn <= MmVadHint->EndingVpn)) {
|
||
|
|
||
|
return (PMMVAD)MmVadHint;
|
||
|
}
|
||
|
|
||
|
FoundVad = (PMMVAD)MiLocateAddressInTree ( Vpn, &MmVadRoot );
|
||
|
|
||
|
if (FoundVad != NULL) {
|
||
|
MmVadHint = (PMMADDRESS_NODE)FoundVad;
|
||
|
}
|
||
|
return FoundVad;
|
||
|
}
|
||
|
|
||
|
PVOID
|
||
|
MiFindEmptyAddressRange (
|
||
|
IN SIZE_T SizeOfRange,
|
||
|
IN ULONG_PTR Alignment,
|
||
|
IN ULONG QuickCheck
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
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.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns the starting address of a suitable range.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PMMVAD NextVad;
|
||
|
PMMVAD FreeHint;
|
||
|
PVOID StartingVa;
|
||
|
PVOID EndingVa;
|
||
|
|
||
|
FreeHint = (PMMVAD)MmVadFreeHint;
|
||
|
|
||
|
if ((QuickCheck == 0) && (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))) {
|
||
|
return (PMMADDRESS_NODE)MI_ROUND_TO_SIZE((ULONG_PTR)EndingVa,
|
||
|
Alignment);
|
||
|
}
|
||
|
} 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)) {
|
||
|
return (PMMADDRESS_NODE)MI_ROUND_TO_SIZE((ULONG_PTR)EndingVa,
|
||
|
Alignment);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return (PMMVAD)MiFindEmptyAddressRangeInTree (
|
||
|
SizeOfRange,
|
||
|
Alignment,
|
||
|
MmVadRoot,
|
||
|
&MmVadFreeHint);
|
||
|
}
|