mirror of https://github.com/tongzx/nt5src
1485 lines
42 KiB
1485 lines
42 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
addrsup.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
|
|
|
|
Ripped off and modified from timersup.c
|
|
The support for siblings was removed and a routine to locate
|
|
the corresponding virtual address descriptor for a given address
|
|
was added.
|
|
|
|
Environment:
|
|
|
|
Kernel mode only, working set mutex held, APCs disabled.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "mi.h"
|
|
|
|
#if (_MSC_VER >= 800)
|
|
#pragma warning(disable:4010) // Allow pretty pictures without the noise
|
|
#endif
|
|
|
|
VOID
|
|
MiReorderTree (
|
|
IN PMMADDRESS_NODE Node,
|
|
IN OUT PMMADDRESS_NODE *Root
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE,MiGetFirstNode)
|
|
#pragma alloc_text(PAGE,MiInsertNode)
|
|
#pragma alloc_text(PAGE,MiGetNextNode)
|
|
#pragma alloc_text(PAGE,MiGetPreviousNode)
|
|
#pragma alloc_text(PAGE,MiCheckForConflictingNode)
|
|
#pragma alloc_text(PAGE,MiFindEmptyAddressRangeInTree)
|
|
#pragma alloc_text(PAGE,MiFindEmptyAddressRangeDownTree)
|
|
#pragma alloc_text(PAGE,MiReorderTree)
|
|
#pragma alloc_text(PAGE,NodeTreeWalk)
|
|
#endif
|
|
|
|
|
|
VOID
|
|
MiReorderTree (
|
|
IN PMMADDRESS_NODE Node,
|
|
IN OUT PMMADDRESS_NODE *Root
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function reorders the Node tree by applying various splay functions
|
|
to the tree. This is a local function that is called by the insert Node
|
|
routine.
|
|
|
|
Arguments:
|
|
|
|
Node - Supplies a pointer to a virtual address descriptor.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PMMADDRESS_NODE GrandParent;
|
|
PMMADDRESS_NODE Parent;
|
|
PMMADDRESS_NODE SplayNode;
|
|
|
|
//
|
|
// Reorder Node tree to make it as balanced as possible with as little
|
|
// work as possible.
|
|
//
|
|
|
|
SplayNode = Node;
|
|
|
|
while (SplayNode != *Root) {
|
|
|
|
Parent = SplayNode->Parent;
|
|
if (Parent == *Root) {
|
|
|
|
//
|
|
// Splay node's parent is the root of the tree. Rotate the tree
|
|
// left or right depending on whether the splay node is the left
|
|
// of right child of its parent.
|
|
//
|
|
// Pictorially:
|
|
//
|
|
// Right Left
|
|
//
|
|
// P X P X
|
|
// / \ / \ / \ / \
|
|
// X C -> A P C X -> P A
|
|
// / \ / \ / \ / \
|
|
// A B B C B A C B
|
|
//
|
|
|
|
*Root = SplayNode;
|
|
SplayNode->Parent = (PMMADDRESS_NODE)NULL;
|
|
Parent->Parent = SplayNode;
|
|
if (SplayNode == Parent->LeftChild) {
|
|
|
|
//
|
|
// Splay node is the left child of its parent. Rotate tree
|
|
// right.
|
|
//
|
|
|
|
Parent->LeftChild = SplayNode->RightChild;
|
|
if (SplayNode->RightChild) {
|
|
SplayNode->RightChild->Parent = Parent;
|
|
}
|
|
SplayNode->RightChild = Parent;
|
|
} else {
|
|
|
|
//
|
|
// Splay node is the right child of its parent. Rotate tree
|
|
// left.
|
|
//
|
|
|
|
Parent->RightChild = SplayNode->LeftChild;
|
|
if (SplayNode->LeftChild) {
|
|
SplayNode->LeftChild->Parent = Parent;
|
|
}
|
|
SplayNode->LeftChild = Parent;
|
|
}
|
|
break;
|
|
} else {
|
|
GrandParent = Parent->Parent;
|
|
if ((SplayNode == Parent->LeftChild) &&
|
|
(Parent == GrandParent->LeftChild)) {
|
|
|
|
//
|
|
// Both the splay node and the parent node are left children
|
|
// of their parents. Rotate tree right and make the parent
|
|
// the root of the new subtree.
|
|
//
|
|
// Pictorially:
|
|
//
|
|
// G P
|
|
// / \ / \
|
|
// P D X G
|
|
// / \ -> / \ / \
|
|
// X C A B C D
|
|
// / \
|
|
// A B
|
|
//
|
|
|
|
if (GrandParent == *Root) {
|
|
*Root = Parent;
|
|
Parent->Parent = (PMMADDRESS_NODE)NULL;
|
|
} else {
|
|
Parent->Parent = GrandParent->Parent;
|
|
if (GrandParent == GrandParent->Parent->LeftChild) {
|
|
GrandParent->Parent->LeftChild = Parent;
|
|
} else {
|
|
GrandParent->Parent->RightChild = Parent;
|
|
}
|
|
}
|
|
GrandParent->LeftChild = Parent->RightChild;
|
|
if (Parent->RightChild) {
|
|
Parent->RightChild->Parent = GrandParent;
|
|
}
|
|
GrandParent->Parent = Parent;
|
|
Parent->RightChild = GrandParent;
|
|
SplayNode = Parent;
|
|
} else if ((SplayNode == Parent->RightChild) &&
|
|
(Parent == GrandParent->RightChild)) {
|
|
|
|
//
|
|
// Both the splay node and the parent node are right children
|
|
// of their parents. Rotate tree left and make the parent
|
|
// the root of the new subtree.
|
|
//
|
|
// Pictorially:
|
|
//
|
|
// G P
|
|
// / \ / \
|
|
// D P G X
|
|
// / \ -> / \ / \
|
|
// C X D C B A
|
|
// / \
|
|
// A B
|
|
//
|
|
|
|
if (GrandParent == *Root) {
|
|
*Root = Parent;
|
|
Parent->Parent = (PMMADDRESS_NODE)NULL;
|
|
} else {
|
|
Parent->Parent = GrandParent->Parent;
|
|
if (GrandParent == GrandParent->Parent->LeftChild) {
|
|
GrandParent->Parent->LeftChild = Parent;
|
|
} else {
|
|
GrandParent->Parent->RightChild = Parent;
|
|
}
|
|
}
|
|
GrandParent->RightChild = Parent->LeftChild;
|
|
if (Parent->LeftChild) {
|
|
Parent->LeftChild->Parent = GrandParent;
|
|
}
|
|
GrandParent->Parent = Parent;
|
|
Parent->LeftChild = GrandParent;
|
|
SplayNode = Parent;
|
|
} else if ((SplayNode == Parent->LeftChild) &&
|
|
(Parent == GrandParent->RightChild)) {
|
|
|
|
//
|
|
// Splay node is the left child of its parent and parent is
|
|
// the right child of its parent. Rotate tree left and make
|
|
// splay node the root of the new subtree.
|
|
//
|
|
// Pictorially:
|
|
//
|
|
// G X
|
|
// / \ / \
|
|
// A P G P
|
|
// / \ -> / \ / \
|
|
// X D A B C D
|
|
// / \
|
|
// B C
|
|
//
|
|
|
|
if (GrandParent == *Root) {
|
|
*Root = SplayNode;
|
|
SplayNode->Parent = (PMMADDRESS_NODE)NULL;
|
|
} else {
|
|
SplayNode->Parent = GrandParent->Parent;
|
|
if (GrandParent == GrandParent->Parent->LeftChild) {
|
|
GrandParent->Parent->LeftChild = SplayNode;
|
|
} else {
|
|
GrandParent->Parent->RightChild = SplayNode;
|
|
}
|
|
}
|
|
Parent->LeftChild = SplayNode->RightChild;
|
|
if (SplayNode->RightChild) {
|
|
SplayNode->RightChild->Parent = Parent;
|
|
}
|
|
GrandParent->RightChild = SplayNode->LeftChild;
|
|
if (SplayNode->LeftChild) {
|
|
SplayNode->LeftChild->Parent = GrandParent;
|
|
}
|
|
Parent->Parent = SplayNode;
|
|
GrandParent->Parent = SplayNode;
|
|
SplayNode->LeftChild = GrandParent;
|
|
SplayNode->RightChild = Parent;
|
|
} else {
|
|
|
|
//
|
|
// Splay node is the right child of its parent and parent is
|
|
// the left child of its parent. Rotate tree right and make
|
|
// splay node the root of the new subtree.
|
|
//
|
|
// Pictorially:
|
|
//
|
|
// G X
|
|
// / \ / \
|
|
// P A P G
|
|
// / \ -> / \ / \
|
|
// D X D C B A
|
|
// / \
|
|
// C B
|
|
//
|
|
|
|
if (GrandParent == *Root) {
|
|
*Root = SplayNode;
|
|
SplayNode->Parent = (PMMADDRESS_NODE)NULL;
|
|
} else {
|
|
SplayNode->Parent = GrandParent->Parent;
|
|
if (GrandParent == GrandParent->Parent->LeftChild) {
|
|
GrandParent->Parent->LeftChild = SplayNode;
|
|
} else {
|
|
GrandParent->Parent->RightChild = SplayNode;
|
|
}
|
|
}
|
|
Parent->RightChild = SplayNode->LeftChild;
|
|
if (SplayNode->LeftChild) {
|
|
SplayNode->LeftChild->Parent = Parent;
|
|
}
|
|
GrandParent->LeftChild = SplayNode->RightChild;
|
|
if (SplayNode->RightChild) {
|
|
SplayNode->RightChild->Parent = GrandParent;
|
|
}
|
|
Parent->Parent = SplayNode;
|
|
GrandParent->Parent = SplayNode;
|
|
SplayNode->LeftChild = Parent;
|
|
SplayNode->RightChild = GrandParent;
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
PMMADDRESS_NODE
|
|
FASTCALL
|
|
MiGetNextNode (
|
|
IN PMMADDRESS_NODE Node
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function locates the virtual address descriptor which contains
|
|
the address range which logically follows the specified address range.
|
|
|
|
Arguments:
|
|
|
|
Node - Supplies a pointer to a virtual address descriptor.
|
|
|
|
Return Value:
|
|
|
|
Returns a pointer to the virtual address descriptor containing the
|
|
next address range, NULL if none.
|
|
|
|
--*/
|
|
|
|
{
|
|
PMMADDRESS_NODE Next;
|
|
PMMADDRESS_NODE Parent;
|
|
PMMADDRESS_NODE Left;
|
|
|
|
Next = Node;
|
|
|
|
if (Next->RightChild == (PMMADDRESS_NODE)NULL) {
|
|
|
|
while ((Parent = Next->Parent) != (PMMADDRESS_NODE)NULL) {
|
|
|
|
//
|
|
// Locate the first ancestor of this node of which this
|
|
// node is the left child of and return that node as the
|
|
// next element.
|
|
//
|
|
|
|
if (Parent->LeftChild == Next) {
|
|
return Parent;
|
|
}
|
|
|
|
Next = Parent;
|
|
|
|
}
|
|
|
|
return (PMMADDRESS_NODE)NULL;
|
|
}
|
|
|
|
//
|
|
// A right child exists, locate the left most child of that right child.
|
|
//
|
|
|
|
Next = Next->RightChild;
|
|
|
|
while ((Left = Next->LeftChild) != (PMMADDRESS_NODE)NULL) {
|
|
Next = Left;
|
|
}
|
|
return Next;
|
|
|
|
}
|
|
|
|
PMMADDRESS_NODE
|
|
FASTCALL
|
|
MiGetPreviousNode (
|
|
IN PMMADDRESS_NODE Node
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function locates the virtual address descriptor which contains
|
|
the address range which logically precedes the specified virtual
|
|
address descriptor.
|
|
|
|
Arguments:
|
|
|
|
Node - Supplies a pointer to a virtual address descriptor.
|
|
|
|
Return Value:
|
|
|
|
Returns a pointer to the virtual address descriptor containing the
|
|
next address range, NULL if none.
|
|
|
|
--*/
|
|
|
|
{
|
|
PMMADDRESS_NODE Previous;
|
|
|
|
Previous = Node;
|
|
|
|
if (Previous->LeftChild == (PMMADDRESS_NODE)NULL) {
|
|
|
|
|
|
while (Previous->Parent != (PMMADDRESS_NODE)NULL) {
|
|
|
|
//
|
|
// Locate the first ancestor of this node of which this
|
|
// node is the right child of and return that node as the
|
|
// Previous element.
|
|
//
|
|
|
|
if (Previous->Parent->RightChild == Previous) {
|
|
return Previous->Parent;
|
|
}
|
|
|
|
Previous = Previous->Parent;
|
|
|
|
}
|
|
return (PMMADDRESS_NODE)NULL;
|
|
}
|
|
|
|
//
|
|
// A left child exists, locate the right most child of that left child.
|
|
//
|
|
|
|
Previous = Previous->LeftChild;
|
|
while (Previous->RightChild != (PMMADDRESS_NODE)NULL) {
|
|
Previous = Previous->RightChild;
|
|
}
|
|
return Previous;
|
|
}
|
|
|
|
PMMADDRESS_NODE
|
|
FASTCALL
|
|
MiGetFirstNode (
|
|
IN PMMADDRESS_NODE Root
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function locates the virtual address descriptor which contains
|
|
the address range which logically is first within the address space.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Returns a pointer to the virtual address descriptor containing the
|
|
first address range, NULL if none.
|
|
|
|
--*/
|
|
|
|
{
|
|
PMMADDRESS_NODE First;
|
|
|
|
First = Root;
|
|
|
|
if (First == (PMMADDRESS_NODE)NULL) {
|
|
return (PMMADDRESS_NODE)NULL;
|
|
}
|
|
|
|
while (First->LeftChild != (PMMADDRESS_NODE)NULL) {
|
|
First = First->LeftChild;
|
|
}
|
|
|
|
return First;
|
|
}
|
|
|
|
VOID
|
|
FASTCALL
|
|
MiInsertNode (
|
|
IN PMMADDRESS_NODE Node,
|
|
IN OUT PMMADDRESS_NODE *Root
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function inserts a virtual address descriptor into the tree and
|
|
reorders the splay tree as appropriate.
|
|
|
|
Arguments:
|
|
|
|
Node - Supplies a pointer to a virtual address descriptor
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG Level = 0;
|
|
PMMADDRESS_NODE Parent;
|
|
|
|
//
|
|
// Initialize virtual address descriptor child links.
|
|
//
|
|
|
|
Node->LeftChild = (PMMADDRESS_NODE)NULL;
|
|
Node->RightChild = (PMMADDRESS_NODE)NULL;
|
|
|
|
//
|
|
// If the tree is empty, then establish this virtual address descriptor
|
|
// as the root of the tree.
|
|
// Otherwise descend the tree to find the correct place to
|
|
// insert the descriptor.
|
|
//
|
|
|
|
Parent = *Root;
|
|
if (!Parent) {
|
|
*Root = Node;
|
|
Node->Parent = (PMMADDRESS_NODE)NULL;
|
|
} else {
|
|
|
|
for (;;) {
|
|
|
|
Level += 1;
|
|
if (Level == 15) {
|
|
MiReorderTree(Parent, Root);
|
|
}
|
|
|
|
//
|
|
// If the starting address for this virtual address descriptor
|
|
// is less than the parent starting address, then
|
|
// follow the left child link. Else follow the right child link.
|
|
//
|
|
|
|
if (Node->StartingVpn < Parent->StartingVpn) {
|
|
|
|
//
|
|
// Starting address of the virtual address descriptor is less
|
|
// than the parent starting virtual address.
|
|
// Follow left child link if not null. Otherwise
|
|
// insert the descriptor as the left child of the parent and
|
|
// reorder the tree.
|
|
//
|
|
|
|
if (Parent->LeftChild) {
|
|
Parent = Parent->LeftChild;
|
|
} else {
|
|
Parent->LeftChild = Node;
|
|
Node->Parent = Parent;
|
|
// MiReorderTree(Node, Root);
|
|
break;
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// Starting address of the virtual address descriptor is greater
|
|
// than the parent starting virtual address.
|
|
// Follow right child link if not null. Otherwise
|
|
// insert the descriptor as the right child of the parent and
|
|
// reorder the tree.
|
|
//
|
|
|
|
if (Parent->RightChild) {
|
|
Parent = Parent->RightChild;
|
|
} else {
|
|
Parent->RightChild = Node;
|
|
Node->Parent = Parent;
|
|
// MiReorderTree(Node, Root);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
FASTCALL
|
|
MiRemoveNode (
|
|
IN PMMADDRESS_NODE Node,
|
|
IN OUT PMMADDRESS_NODE *Root
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function removes a virtual address descriptor from the tree and
|
|
reorders the splay tree as appropriate.
|
|
|
|
Arguments:
|
|
|
|
Node - Supplies a pointer to a virtual address descriptor.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PMMADDRESS_NODE LeftChild;
|
|
PMMADDRESS_NODE RightChild;
|
|
PMMADDRESS_NODE SplayNode;
|
|
|
|
|
|
LeftChild = Node->LeftChild;
|
|
RightChild = Node->RightChild;
|
|
|
|
|
|
//
|
|
// If the Node is the root of the tree, then establish new root. Else
|
|
// isolate splay case and perform splay tree transformation.
|
|
//
|
|
|
|
if (Node == *Root) {
|
|
|
|
//
|
|
// This Node is the root of the tree. There are four cases to
|
|
// handle:
|
|
//
|
|
// 1. the descriptor has no children
|
|
// 2. the descriptor has a left child but no right child
|
|
// 3. the descriptor has a right child but no left child
|
|
// 4. the descriptor has both a right child and a left child
|
|
//
|
|
|
|
if (LeftChild) {
|
|
if (RightChild) {
|
|
|
|
//
|
|
// The descriptor has both a left child and a right child.
|
|
//
|
|
|
|
if (LeftChild->RightChild) {
|
|
|
|
//
|
|
// The left child has a right child. Make the right most
|
|
// descendent of the right child of the left child the
|
|
// new root of the tree.
|
|
//
|
|
// Pictorially:
|
|
//
|
|
// R R
|
|
// | |
|
|
// X Z
|
|
// / \ / \
|
|
// A B -> A B
|
|
// \ \
|
|
// . .
|
|
// \
|
|
// Z
|
|
//
|
|
|
|
SplayNode = LeftChild->RightChild;
|
|
while (SplayNode->RightChild) {
|
|
SplayNode = SplayNode->RightChild;
|
|
}
|
|
*Root = SplayNode;
|
|
SplayNode->Parent->RightChild = SplayNode->LeftChild;
|
|
if (SplayNode->LeftChild) {
|
|
SplayNode->LeftChild->Parent = SplayNode->Parent;
|
|
}
|
|
SplayNode->Parent = (PMMADDRESS_NODE)NULL;
|
|
LeftChild->Parent = SplayNode;
|
|
RightChild->Parent = SplayNode;
|
|
SplayNode->LeftChild = LeftChild;
|
|
SplayNode->RightChild = RightChild;
|
|
} else if (RightChild->LeftChild) {
|
|
|
|
//
|
|
// The right child has a left child. Make the left most
|
|
// descendent of the left child of the right child the
|
|
// new root of the tree.
|
|
//
|
|
// Pictorially:
|
|
//
|
|
// R R
|
|
// | |
|
|
// X Z
|
|
// / \ / \
|
|
// A B -> A B
|
|
// / /
|
|
// . .
|
|
// /
|
|
// Z
|
|
//
|
|
|
|
SplayNode = RightChild->LeftChild;
|
|
while (SplayNode->LeftChild) {
|
|
SplayNode = SplayNode->LeftChild;
|
|
}
|
|
*Root = SplayNode;
|
|
SplayNode->Parent->LeftChild = SplayNode->RightChild;
|
|
if (SplayNode->RightChild) {
|
|
SplayNode->RightChild->Parent = SplayNode->Parent;
|
|
}
|
|
SplayNode->Parent = (PMMADDRESS_NODE)NULL;
|
|
LeftChild->Parent = SplayNode;
|
|
RightChild->Parent = SplayNode;
|
|
SplayNode->LeftChild = LeftChild;
|
|
SplayNode->RightChild = RightChild;
|
|
} else {
|
|
|
|
//
|
|
// The left child of the descriptor does not have a right child,
|
|
// and the right child of the descriptor does not have a left
|
|
// child. Make the left child of the descriptor the new root of
|
|
// the tree.
|
|
//
|
|
// Pictorially:
|
|
//
|
|
// R R
|
|
// | |
|
|
// X A
|
|
// / \ / \
|
|
// A B -> . B
|
|
// / /
|
|
// .
|
|
//
|
|
|
|
*Root = LeftChild;
|
|
LeftChild->Parent = (PMMADDRESS_NODE)NULL;
|
|
LeftChild->RightChild = RightChild;
|
|
LeftChild->RightChild->Parent = LeftChild;
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// The descriptor has a left child, but does not have a right child.
|
|
// Make the left child the new root of the tree.
|
|
//
|
|
// Pictorially:
|
|
//
|
|
// R R
|
|
// | |
|
|
// X -> A
|
|
// /
|
|
// A
|
|
//
|
|
|
|
*Root = LeftChild;
|
|
LeftChild->Parent = (PMMADDRESS_NODE)NULL;
|
|
}
|
|
} else if (RightChild) {
|
|
|
|
//
|
|
// The descriptor has a right child, but does not have a left child.
|
|
// Make the right child the new root of the tree.
|
|
//
|
|
// Pictorially:
|
|
//
|
|
// R R
|
|
// | |
|
|
// X -> A
|
|
// \
|
|
// A
|
|
//
|
|
|
|
*Root = RightChild;
|
|
RightChild->Parent = (PMMADDRESS_NODE)NULL;
|
|
while (RightChild->LeftChild) {
|
|
RightChild = RightChild->LeftChild;
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// The descriptor has neither a left child nor a right child. The
|
|
// tree will be empty after removing the descriptor.
|
|
//
|
|
// Pictorially:
|
|
//
|
|
// R R
|
|
// | ->
|
|
// X
|
|
//
|
|
|
|
*Root = NULL;
|
|
}
|
|
} else if (LeftChild) {
|
|
if (RightChild) {
|
|
|
|
//
|
|
// The descriptor has both a left child and a right child.
|
|
//
|
|
|
|
if (LeftChild->RightChild) {
|
|
|
|
//
|
|
// The left child has a right child. Make the right most
|
|
// descendent of the right child of the left child the new
|
|
// root of the subtree.
|
|
//
|
|
// Pictorially:
|
|
//
|
|
// P P
|
|
// / \
|
|
// X X
|
|
// / \ / \
|
|
// A B or A B
|
|
// \ \
|
|
// . .
|
|
// \ \
|
|
// Z Z
|
|
//
|
|
// |
|
|
// v
|
|
//
|
|
// P P
|
|
// / \
|
|
// Z Z
|
|
// / \ / \
|
|
// A B or A B
|
|
// \ \
|
|
// . .
|
|
//
|
|
|
|
SplayNode = LeftChild->RightChild;
|
|
while (SplayNode->RightChild) {
|
|
SplayNode = SplayNode->RightChild;
|
|
}
|
|
SplayNode->Parent->RightChild = SplayNode->LeftChild;
|
|
if (SplayNode->LeftChild) {
|
|
SplayNode->LeftChild->Parent = SplayNode->Parent;
|
|
}
|
|
SplayNode->Parent = Node->Parent;
|
|
if (Node == Node->Parent->LeftChild) {
|
|
Node->Parent->LeftChild = SplayNode;
|
|
} else {
|
|
Node->Parent->RightChild = SplayNode;
|
|
}
|
|
LeftChild->Parent = SplayNode;
|
|
RightChild->Parent = SplayNode;
|
|
SplayNode->LeftChild = LeftChild;
|
|
SplayNode->RightChild = RightChild;
|
|
} else if (RightChild->LeftChild) {
|
|
|
|
//
|
|
// The right child has a left child. Make the left most
|
|
// descendent of the left child of the right child the
|
|
// new root of the subtree.
|
|
//
|
|
// Pictorially:
|
|
//
|
|
// P P
|
|
// / \
|
|
// X X
|
|
// / \ / \
|
|
// A B or A B
|
|
// / /
|
|
// . .
|
|
// / /
|
|
// Z Z
|
|
//
|
|
// |
|
|
// v
|
|
//
|
|
// P P
|
|
// / \
|
|
// Z Z
|
|
// / \ / \
|
|
// A B or A B
|
|
// / /
|
|
// . .
|
|
//
|
|
|
|
SplayNode = RightChild->LeftChild;
|
|
while (SplayNode->LeftChild) {
|
|
SplayNode = SplayNode->LeftChild;
|
|
}
|
|
SplayNode->Parent->LeftChild = SplayNode->RightChild;
|
|
if (SplayNode->RightChild) {
|
|
SplayNode->RightChild->Parent = SplayNode->Parent;
|
|
}
|
|
SplayNode->Parent = Node->Parent;
|
|
if (Node == Node->Parent->LeftChild) {
|
|
Node->Parent->LeftChild = SplayNode;
|
|
} else {
|
|
Node->Parent->RightChild = SplayNode;
|
|
}
|
|
LeftChild->Parent = SplayNode;
|
|
RightChild->Parent = SplayNode;
|
|
SplayNode->LeftChild = LeftChild;
|
|
SplayNode->RightChild = RightChild;
|
|
} else {
|
|
|
|
//
|
|
// The left child of the descriptor does not have a right child,
|
|
// and the right child of the descriptor does node have a left
|
|
// child. Make the left child of the descriptor the new root of
|
|
// the subtree.
|
|
//
|
|
// Pictorially:
|
|
//
|
|
// P P
|
|
// / \
|
|
// X X
|
|
// / \ / \
|
|
// A B or A B
|
|
// / /
|
|
// . .
|
|
//
|
|
// |
|
|
// v
|
|
//
|
|
// P P
|
|
// / \
|
|
// A A
|
|
// / \ / \
|
|
// . B or . B
|
|
// / /
|
|
//
|
|
|
|
SplayNode = LeftChild;
|
|
SplayNode->Parent = Node->Parent;
|
|
if (Node == Node->Parent->LeftChild) {
|
|
Node->Parent->LeftChild = SplayNode;
|
|
} else {
|
|
Node->Parent->RightChild = SplayNode;
|
|
}
|
|
SplayNode->RightChild = RightChild;
|
|
RightChild->Parent = SplayNode;
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// The descriptor has a left child, but does not have a right child.
|
|
// Make the left child the new root of the subtree.
|
|
//
|
|
// Pictorially:
|
|
//
|
|
// P P
|
|
// / \
|
|
// X or X
|
|
// / /
|
|
// A A
|
|
//
|
|
// |
|
|
// v
|
|
//
|
|
// P P
|
|
// / \
|
|
// A A
|
|
//
|
|
|
|
LeftChild->Parent = Node->Parent;
|
|
if (Node == Node->Parent->LeftChild) {
|
|
Node->Parent->LeftChild = LeftChild;
|
|
} else {
|
|
Node->Parent->RightChild = LeftChild;
|
|
}
|
|
}
|
|
} else if (RightChild) {
|
|
|
|
//
|
|
// descriptor has a right child, but does not have a left child. Make
|
|
// the right child the new root of the subtree.
|
|
//
|
|
// Pictorially:
|
|
//
|
|
// P P
|
|
// / \
|
|
// X or X
|
|
// \ \
|
|
// A A
|
|
//
|
|
// |
|
|
// v
|
|
//
|
|
// P P
|
|
// / \
|
|
// A A
|
|
//
|
|
|
|
RightChild->Parent = Node->Parent;
|
|
if (Node == Node->Parent->LeftChild) {
|
|
Node->Parent->LeftChild = RightChild;
|
|
} else {
|
|
Node->Parent->RightChild = RightChild;
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// The descriptor has neither a left child nor a right child. Delete
|
|
// the descriptor from the tree and adjust its parent right or left
|
|
// link.
|
|
//
|
|
// Pictorially:
|
|
//
|
|
// P P
|
|
// / \
|
|
// X or X
|
|
//
|
|
// |
|
|
// v
|
|
//
|
|
// P P
|
|
//
|
|
|
|
if (Node == Node->Parent->LeftChild) {
|
|
Node->Parent->LeftChild = (PMMADDRESS_NODE)NULL;
|
|
} else {
|
|
Node->Parent->RightChild = (PMMADDRESS_NODE)NULL;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
PMMADDRESS_NODE
|
|
FASTCALL
|
|
MiLocateAddressInTree (
|
|
IN ULONG_PTR Vpn,
|
|
IN PMMADDRESS_NODE *Root
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The function locates the virtual address descriptor which describes
|
|
a given address.
|
|
|
|
Arguments:
|
|
|
|
Vpn - Supplies the virtual page number 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.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PMMADDRESS_NODE Parent;
|
|
ULONG Level = 0;
|
|
|
|
Parent = *Root;
|
|
|
|
for (;;) {
|
|
|
|
if (Parent == (PMMADDRESS_NODE)NULL) {
|
|
return (PMMADDRESS_NODE)NULL;
|
|
}
|
|
|
|
if (Level == 20) {
|
|
|
|
//
|
|
// There are 20 nodes above this point, reorder the
|
|
// tree with this node as the root. Note this reorder
|
|
// cannot be done unless the address creation mutex is held,
|
|
// and it is not held on faults.
|
|
#if 0
|
|
MiReorderTree(Parent, Root);
|
|
#endif
|
|
}
|
|
|
|
if (Vpn < Parent->StartingVpn) {
|
|
Parent = Parent->LeftChild;
|
|
Level += 1;
|
|
|
|
} else if (Vpn > Parent->EndingVpn) {
|
|
Parent = Parent->RightChild;
|
|
Level += 1;
|
|
|
|
} else {
|
|
|
|
//
|
|
// The address is within the start and end range.
|
|
//
|
|
|
|
return Parent;
|
|
}
|
|
}
|
|
}
|
|
|
|
PMMADDRESS_NODE
|
|
MiCheckForConflictingNode (
|
|
IN ULONG_PTR StartVpn,
|
|
IN ULONG_PTR EndVpn,
|
|
IN PMMADDRESS_NODE Root
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The function determines if any addresses between a given starting and
|
|
ending address is contained within a virtual address descriptor.
|
|
|
|
Arguments:
|
|
|
|
StartVpn - Supplies the virtual address to locate a containing
|
|
descriptor.
|
|
|
|
EndVpn - Supplies the virtual address to locate a containing
|
|
descriptor.
|
|
|
|
Return Value:
|
|
|
|
Returns a pointer to the first conflicting virtual address descriptor
|
|
if one is found, otherwise a NULL value is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
PMMADDRESS_NODE Node;
|
|
|
|
Node = Root;
|
|
|
|
for (;;) {
|
|
|
|
if (Node == (PMMADDRESS_NODE)NULL) {
|
|
return (PMMADDRESS_NODE)NULL;
|
|
}
|
|
|
|
if (StartVpn > Node->EndingVpn) {
|
|
Node = Node->RightChild;
|
|
|
|
} else if (EndVpn < Node->StartingVpn) {
|
|
Node = Node->LeftChild;
|
|
|
|
} else {
|
|
|
|
//
|
|
// The starting address is less than or equal to the end VA
|
|
// and the ending address is greater than or equal to the
|
|
// start va. Return this node.
|
|
//
|
|
|
|
return Node;
|
|
}
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
MiFindEmptyAddressRangeInTree (
|
|
IN SIZE_T SizeOfRange,
|
|
IN ULONG_PTR Alignment,
|
|
IN PMMADDRESS_NODE Root,
|
|
OUT PMMADDRESS_NODE *PreviousVad,
|
|
OUT 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.
|
|
|
|
Root - Supplies the root of the tree to search through.
|
|
|
|
PreviousVad - Supplies the Vad which is before this the found
|
|
address range.
|
|
|
|
Base - Receives the starting address of a suitable range on success.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS.
|
|
|
|
--*/
|
|
|
|
{
|
|
PMMADDRESS_NODE Node;
|
|
PMMADDRESS_NODE NextNode;
|
|
ULONG_PTR AlignmentVpn;
|
|
ULONG_PTR SizeOfRangeVpn;
|
|
|
|
AlignmentVpn = Alignment >> PAGE_SHIFT;
|
|
|
|
//
|
|
// Locate the Node with the lowest starting address.
|
|
//
|
|
|
|
ASSERT (SizeOfRange != 0);
|
|
SizeOfRangeVpn = (SizeOfRange + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
|
|
ASSERT (SizeOfRangeVpn != 0);
|
|
|
|
Node = Root;
|
|
|
|
if (Node == (PMMADDRESS_NODE)NULL) {
|
|
*Base = MM_LOWEST_USER_ADDRESS;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
while (Node->LeftChild != (PMMADDRESS_NODE)NULL) {
|
|
Node = Node->LeftChild;
|
|
}
|
|
|
|
//
|
|
// Check to see if a range exists between the lowest address VAD
|
|
// and lowest user address.
|
|
//
|
|
|
|
if (Node->StartingVpn > MI_VA_TO_VPN (MM_LOWEST_USER_ADDRESS)) {
|
|
if ( SizeOfRangeVpn <
|
|
(Node->StartingVpn - MI_VA_TO_VPN (MM_LOWEST_USER_ADDRESS))) {
|
|
|
|
*PreviousVad = NULL;
|
|
*Base = MM_LOWEST_USER_ADDRESS;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
for (;;) {
|
|
|
|
NextNode = MiGetNextNode (Node);
|
|
|
|
if (NextNode != (PMMADDRESS_NODE)NULL) {
|
|
|
|
if (SizeOfRangeVpn <=
|
|
((ULONG_PTR)NextNode->StartingVpn -
|
|
MI_ROUND_TO_SIZE(1 + Node->EndingVpn,
|
|
AlignmentVpn))) {
|
|
|
|
//
|
|
// Check to ensure that the ending address aligned upwards
|
|
// is not greater than the starting address.
|
|
//
|
|
|
|
if ((ULONG_PTR)NextNode->StartingVpn >
|
|
MI_ROUND_TO_SIZE(1 + Node->EndingVpn,
|
|
AlignmentVpn)) {
|
|
|
|
*PreviousVad = Node;
|
|
*Base = (PVOID) MI_ROUND_TO_SIZE(
|
|
(ULONG_PTR)MI_VPN_TO_VA_ENDING(Node->EndingVpn),
|
|
Alignment);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// No more descriptors, check to see if this fits into the remainder
|
|
// of the address space.
|
|
//
|
|
|
|
if ((((ULONG_PTR)Node->EndingVpn + MI_VA_TO_VPN(X64K)) <
|
|
MI_VA_TO_VPN (MM_HIGHEST_VAD_ADDRESS))
|
|
&&
|
|
(SizeOfRange <=
|
|
((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS -
|
|
(ULONG_PTR)MI_ROUND_TO_SIZE(
|
|
(ULONG_PTR)MI_VPN_TO_VA(Node->EndingVpn), Alignment)))) {
|
|
|
|
*PreviousVad = Node;
|
|
*Base = (PVOID) MI_ROUND_TO_SIZE(
|
|
(ULONG_PTR)MI_VPN_TO_VA_ENDING(Node->EndingVpn),
|
|
Alignment);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
Node = NextNode;
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
MiFindEmptyAddressRangeDownTree (
|
|
IN SIZE_T SizeOfRange,
|
|
IN PVOID HighestAddressToEndAt,
|
|
IN ULONG_PTR Alignment,
|
|
IN PMMADDRESS_NODE Root,
|
|
OUT 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. The function examines from the high
|
|
addresses down and ensures that starting address is less than
|
|
the specified address.
|
|
|
|
Arguments:
|
|
|
|
SizeOfRange - Supplies the size in bytes of the range to locate.
|
|
|
|
HighestAddressToEndAt - Supplies the virtual address that limits
|
|
the value of the ending address. The ending
|
|
address of the located range must be less
|
|
than this address.
|
|
|
|
Alignment - Supplies the alignment for the address. Must be
|
|
a power of 2 and greater than the page_size.
|
|
|
|
Root - Supplies the root of the tree to search through.
|
|
|
|
Base - Receives the starting address of a suitable range on success.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS.
|
|
|
|
--*/
|
|
|
|
{
|
|
PMMADDRESS_NODE Node;
|
|
PMMADDRESS_NODE PreviousNode;
|
|
ULONG_PTR AlignedEndingVa;
|
|
PVOID OptimalStart;
|
|
ULONG_PTR OptimalStartVpn;
|
|
ULONG_PTR HighestVpn;
|
|
ULONG_PTR AlignmentVpn;
|
|
|
|
SizeOfRange = MI_ROUND_TO_SIZE (SizeOfRange, PAGE_SIZE);
|
|
|
|
if (((ULONG_PTR)HighestAddressToEndAt + 1) < SizeOfRange) {
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
ASSERT (HighestAddressToEndAt != NULL);
|
|
ASSERT (HighestAddressToEndAt <= (PVOID)((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1));
|
|
|
|
HighestVpn = MI_VA_TO_VPN (HighestAddressToEndAt);
|
|
|
|
//
|
|
// Locate the Node with the highest starting address.
|
|
//
|
|
|
|
OptimalStart = (PVOID)(MI_ALIGN_TO_SIZE(
|
|
(((ULONG_PTR)HighestAddressToEndAt + 1) - SizeOfRange),
|
|
Alignment));
|
|
Node = Root;
|
|
|
|
if (Node == (PMMADDRESS_NODE)NULL) {
|
|
|
|
//
|
|
// The tree is empty, any range is okay.
|
|
//
|
|
|
|
*Base = OptimalStart;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// See if an empty slot exists to hold this range, locate the largest
|
|
// element in the tree.
|
|
//
|
|
|
|
while (Node->RightChild != (PMMADDRESS_NODE)NULL) {
|
|
Node = Node->RightChild;
|
|
}
|
|
|
|
//
|
|
// Check to see if a range exists between the highest address VAD
|
|
// and the highest address to end at.
|
|
//
|
|
|
|
AlignedEndingVa = (ULONG_PTR)MI_ROUND_TO_SIZE ((ULONG_PTR)MI_VPN_TO_VA_ENDING (Node->EndingVpn),
|
|
Alignment);
|
|
|
|
if (AlignedEndingVa < (ULONG_PTR)HighestAddressToEndAt) {
|
|
|
|
if ( SizeOfRange < ((ULONG_PTR)HighestAddressToEndAt - AlignedEndingVa)) {
|
|
|
|
*Base = MI_ALIGN_TO_SIZE(
|
|
((ULONG_PTR)HighestAddressToEndAt - SizeOfRange),
|
|
Alignment);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Walk the tree backwards looking for a fit.
|
|
//
|
|
|
|
OptimalStartVpn = MI_VA_TO_VPN (OptimalStart);
|
|
AlignmentVpn = MI_VA_TO_VPN (Alignment);
|
|
|
|
for (;;) {
|
|
|
|
PreviousNode = MiGetPreviousNode (Node);
|
|
|
|
if (PreviousNode != (PMMADDRESS_NODE)NULL) {
|
|
|
|
//
|
|
// Is the ending Va below the top of the address to end at.
|
|
//
|
|
|
|
if (PreviousNode->EndingVpn < OptimalStartVpn) {
|
|
if ((SizeOfRange >> PAGE_SHIFT) <=
|
|
((ULONG_PTR)Node->StartingVpn -
|
|
(ULONG_PTR)MI_ROUND_TO_SIZE(1 + PreviousNode->EndingVpn,
|
|
AlignmentVpn))) {
|
|
|
|
//
|
|
// See if the optimal start will fit between these
|
|
// two VADs.
|
|
//
|
|
|
|
if ((OptimalStartVpn > PreviousNode->EndingVpn) &&
|
|
(HighestVpn < Node->StartingVpn)) {
|
|
*Base = OptimalStart;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Check to ensure that the ending address aligned upwards
|
|
// is not greater than the starting address.
|
|
//
|
|
|
|
if ((ULONG_PTR)Node->StartingVpn >
|
|
(ULONG_PTR)MI_ROUND_TO_SIZE(1 + PreviousNode->EndingVpn,
|
|
AlignmentVpn)) {
|
|
|
|
*Base = MI_ALIGN_TO_SIZE(
|
|
(ULONG_PTR)MI_VPN_TO_VA (Node->StartingVpn) - SizeOfRange,
|
|
Alignment);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// No more descriptors, check to see if this fits into the remainder
|
|
// of the address space.
|
|
//
|
|
|
|
if (Node->StartingVpn > MI_VA_TO_VPN (MM_LOWEST_USER_ADDRESS)) {
|
|
if ((SizeOfRange >> PAGE_SHIFT) <=
|
|
((ULONG_PTR)Node->StartingVpn - MI_VA_TO_VPN (MM_LOWEST_USER_ADDRESS))) {
|
|
|
|
//
|
|
// See if the optimal start will fit between these
|
|
// two VADs.
|
|
//
|
|
|
|
if (HighestVpn < Node->StartingVpn) {
|
|
*Base = OptimalStart;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
*Base = MI_ALIGN_TO_SIZE(
|
|
(ULONG_PTR)MI_VPN_TO_VA (Node->StartingVpn) - SizeOfRange,
|
|
Alignment);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
Node = PreviousNode;
|
|
}
|
|
}
|
|
#if DBG
|
|
VOID
|
|
NodeTreeWalk (
|
|
PMMADDRESS_NODE Start
|
|
)
|
|
|
|
{
|
|
if (Start == (PMMADDRESS_NODE)NULL) {
|
|
return;
|
|
}
|
|
|
|
NodeTreeWalk(Start->LeftChild);
|
|
|
|
DbgPrint("Node at 0x%p start 0x%p end 0x%p \n",
|
|
(ULONG_PTR)Start,
|
|
MI_VPN_TO_VA(Start->StartingVpn),
|
|
(ULONG_PTR)MI_VPN_TO_VA (Start->EndingVpn) | (PAGE_SIZE - 1));
|
|
|
|
|
|
NodeTreeWalk(Start->RightChild);
|
|
return;
|
|
}
|
|
#endif //DBG
|