mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1435 lines
37 KiB
1435 lines
37 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
wstree.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the routines which manipulate the working
|
|
set list tree.
|
|
|
|
Author:
|
|
|
|
Lou Perazzoli (loup) 15-May-1989
|
|
Landy Wang (landyw) 02-June-1997
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "mi.h"
|
|
|
|
extern ULONG MmSystemCodePage;
|
|
extern ULONG MmSystemCachePage;
|
|
extern ULONG MmPagedPoolPage;
|
|
extern ULONG MmSystemDriverPage;
|
|
|
|
#if DBG
|
|
ULONG MmNumberOfInserts;
|
|
#endif
|
|
|
|
VOID
|
|
MiRepointWsleHashIndex (
|
|
IN ULONG_PTR WsleEntry,
|
|
IN PMMWSL WorkingSetList,
|
|
IN WSLE_NUMBER NewWsIndex
|
|
);
|
|
|
|
VOID
|
|
MiCheckWsleHash (
|
|
IN PMMWSL WorkingSetList
|
|
);
|
|
|
|
|
|
VOID
|
|
FASTCALL
|
|
MiInsertWsleHash (
|
|
IN WSLE_NUMBER Entry,
|
|
IN PMMWSL WorkingSetList
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine inserts a Working Set List Entry (WSLE) into the
|
|
hash list for the specified working set.
|
|
|
|
Arguments:
|
|
|
|
Entry - The index number of the WSLE to insert.
|
|
|
|
WorkingSetList - Supplies the working set list to insert into.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Environment:
|
|
|
|
Kernel mode, APCs disabled, Working Set Mutex held.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG Tries;
|
|
PVOID VirtualAddress;
|
|
PMMWSLE Wsle;
|
|
PMMSUPPORT WsInfo;
|
|
WSLE_NUMBER Hash;
|
|
PMMWSLE_HASH Table;
|
|
WSLE_NUMBER j;
|
|
WSLE_NUMBER Index;
|
|
ULONG HashTableSize;
|
|
|
|
Wsle = WorkingSetList->Wsle;
|
|
|
|
ASSERT (Wsle[Entry].u1.e1.Valid == 1);
|
|
ASSERT (Wsle[Entry].u1.e1.Direct != 1);
|
|
|
|
if ((Table = WorkingSetList->HashTable) == NULL) {
|
|
return;
|
|
}
|
|
|
|
#if DBG
|
|
MmNumberOfInserts += 1;
|
|
#endif //DBG
|
|
|
|
VirtualAddress = PAGE_ALIGN(Wsle[Entry].u1.VirtualAddress);
|
|
|
|
Hash = MI_WSLE_HASH(Wsle[Entry].u1.Long, WorkingSetList);
|
|
|
|
HashTableSize = WorkingSetList->HashTableSize;
|
|
|
|
//
|
|
// Check hash table size and see if there is enough room to
|
|
// hash or if the table should be grown.
|
|
//
|
|
|
|
if ((WorkingSetList->NonDirectCount + 10 + (HashTableSize >> 4)) >
|
|
HashTableSize) {
|
|
|
|
if (WorkingSetList == MmWorkingSetList) {
|
|
WsInfo = &PsGetCurrentProcess()->Vm;
|
|
ASSERT (WsInfo->Flags.SessionSpace == 0);
|
|
}
|
|
else if (WorkingSetList == MmSystemCacheWorkingSetList) {
|
|
WsInfo = &MmSystemCacheWs;
|
|
ASSERT (WsInfo->Flags.SessionSpace == 0);
|
|
}
|
|
else {
|
|
WsInfo = &MmSessionSpace->Vm;
|
|
ASSERT (WsInfo->Flags.SessionSpace == 1);
|
|
}
|
|
|
|
if ((Table + HashTableSize + ((2*PAGE_SIZE) / sizeof (MMWSLE_HASH)) <= (PMMWSLE_HASH)WorkingSetList->HighestPermittedHashAddress) &&
|
|
(WsInfo->Flags.AllowWorkingSetAdjustment)) {
|
|
|
|
WsInfo->Flags.AllowWorkingSetAdjustment = MM_GROW_WSLE_HASH;
|
|
}
|
|
|
|
if ((WorkingSetList->NonDirectCount + (HashTableSize >> 4)) >
|
|
HashTableSize) {
|
|
|
|
//
|
|
// No more room in the hash table, remove one and add there.
|
|
//
|
|
// Note the actual WSLE is not removed - just its hash entry is
|
|
// so that we can use it for the entry now being inserted. This
|
|
// is nice because it preserves both entries in the working set
|
|
// (although it is a bit more costly to remove the original
|
|
// entry later since it won't have a hash entry).
|
|
//
|
|
|
|
j = Hash;
|
|
|
|
Tries = 0;
|
|
do {
|
|
if (Table[j].Key != 0) {
|
|
|
|
Index = WorkingSetList->HashTable[j].Index;
|
|
ASSERT (Wsle[Index].u1.e1.Direct == 0);
|
|
ASSERT (Wsle[Index].u1.e1.Valid == 1);
|
|
ASSERT (PAGE_ALIGN (Table[j].Key) == PAGE_ALIGN (Wsle[Index].u1.VirtualAddress));
|
|
|
|
Table[j].Key = 0;
|
|
Hash = j;
|
|
break;
|
|
}
|
|
|
|
j += 1;
|
|
|
|
if (j >= HashTableSize) {
|
|
j = 0;
|
|
ASSERT (Tries == 0);
|
|
Tries = 1;
|
|
}
|
|
|
|
if (j == Hash) {
|
|
return;
|
|
}
|
|
|
|
} while (TRUE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add to the hash table if there is space.
|
|
//
|
|
|
|
Tries = 0;
|
|
j = Hash;
|
|
|
|
while (Table[Hash].Key != 0) {
|
|
Hash += 1;
|
|
if (Hash >= HashTableSize) {
|
|
ASSERT (Tries == 0);
|
|
Hash = 0;
|
|
Tries = 1;
|
|
}
|
|
if (j == Hash) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
ASSERT (Hash < HashTableSize);
|
|
|
|
Table[Hash].Key = PAGE_ALIGN (Wsle[Entry].u1.Long);
|
|
Table[Hash].Index = Entry;
|
|
|
|
#if DBG
|
|
if ((MmNumberOfInserts % 1000) == 0) {
|
|
MiCheckWsleHash (WorkingSetList);
|
|
}
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
#if DBG
|
|
VOID
|
|
MiCheckWsleHash (
|
|
IN PMMWSL WorkingSetList
|
|
)
|
|
|
|
{
|
|
ULONG j;
|
|
ULONG found;
|
|
PMMWSLE Wsle;
|
|
|
|
found = 0;
|
|
Wsle = WorkingSetList->Wsle;
|
|
|
|
for (j = 0; j < WorkingSetList->HashTableSize; j += 1) {
|
|
if (WorkingSetList->HashTable[j].Key != 0) {
|
|
found += 1;
|
|
ASSERT (WorkingSetList->HashTable[j].Key ==
|
|
PAGE_ALIGN (Wsle[WorkingSetList->HashTable[j].Index].u1.Long));
|
|
}
|
|
}
|
|
if (found > WorkingSetList->NonDirectCount) {
|
|
DbgPrint("MMWSLE: Found %lx, nondirect %lx\n",
|
|
found, WorkingSetList->NonDirectCount);
|
|
DbgBreakPoint();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
WSLE_NUMBER
|
|
FASTCALL
|
|
MiLocateWsle (
|
|
IN PVOID VirtualAddress,
|
|
IN PMMWSL WorkingSetList,
|
|
IN WSLE_NUMBER WsPfnIndex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function locates the specified virtual address within the
|
|
working set list.
|
|
|
|
Arguments:
|
|
|
|
VirtualAddress - Supplies the virtual to locate within the working
|
|
set list.
|
|
|
|
WorkingSetList - Supplies the working set list to search.
|
|
|
|
WsPfnIndex - Supplies a hint to try before hashing or walking linearly.
|
|
|
|
Return Value:
|
|
|
|
Returns the index into the working set list which contains the entry.
|
|
|
|
Environment:
|
|
|
|
Kernel mode, APCs disabled, Working Set Mutex held.
|
|
|
|
--*/
|
|
|
|
{
|
|
PMMWSLE Wsle;
|
|
PMMWSLE LastWsle;
|
|
WSLE_NUMBER Hash;
|
|
PMMWSLE_HASH Table;
|
|
WSLE_NUMBER StartHash;
|
|
ULONG Tries;
|
|
#if defined (_WIN64)
|
|
WSLE_NUMBER WsPteIndex;
|
|
PMMPTE PointerPte;
|
|
#endif
|
|
|
|
Wsle = WorkingSetList->Wsle;
|
|
|
|
VirtualAddress = PAGE_ALIGN(VirtualAddress);
|
|
|
|
#if defined (_WIN64)
|
|
PointerPte = MiGetPteAddress (VirtualAddress);
|
|
WsPteIndex = MI_GET_WORKING_SET_FROM_PTE (PointerPte);
|
|
if (WsPteIndex != 0) {
|
|
while (WsPteIndex <= WorkingSetList->LastInitializedWsle) {
|
|
if ((VirtualAddress == PAGE_ALIGN(Wsle[WsPteIndex].u1.VirtualAddress)) &&
|
|
(Wsle[WsPteIndex].u1.e1.Valid == 1)) {
|
|
return WsPteIndex;
|
|
}
|
|
WsPteIndex += MI_MAXIMUM_PTE_WORKING_SET_INDEX;
|
|
}
|
|
|
|
//
|
|
// No working set index for this PTE !
|
|
//
|
|
|
|
KeBugCheckEx (MEMORY_MANAGEMENT,
|
|
0x41283,
|
|
(ULONG_PTR)VirtualAddress,
|
|
PointerPte->u.Long,
|
|
(ULONG_PTR)WorkingSetList);
|
|
}
|
|
#endif
|
|
|
|
if (WsPfnIndex <= WorkingSetList->LastInitializedWsle) {
|
|
if ((VirtualAddress == PAGE_ALIGN(Wsle[WsPfnIndex].u1.VirtualAddress)) &&
|
|
(Wsle[WsPfnIndex].u1.e1.Valid == 1)) {
|
|
return WsPfnIndex;
|
|
}
|
|
}
|
|
|
|
if (WorkingSetList->HashTable != NULL) {
|
|
Tries = 0;
|
|
Table = WorkingSetList->HashTable;
|
|
|
|
Hash = MI_WSLE_HASH(VirtualAddress, WorkingSetList);
|
|
StartHash = Hash;
|
|
|
|
while (Table[Hash].Key != VirtualAddress) {
|
|
Hash += 1;
|
|
if (Hash >= WorkingSetList->HashTableSize) {
|
|
ASSERT (Tries == 0);
|
|
Hash = 0;
|
|
Tries = 1;
|
|
}
|
|
if (Hash == StartHash) {
|
|
Tries = 2;
|
|
break;
|
|
}
|
|
}
|
|
if (Tries < 2) {
|
|
ASSERT (WorkingSetList->Wsle[Table[Hash].Index].u1.e1.Direct == 0);
|
|
return Table[Hash].Index;
|
|
}
|
|
}
|
|
|
|
LastWsle = Wsle + WorkingSetList->LastInitializedWsle;
|
|
|
|
do {
|
|
if ((Wsle->u1.e1.Valid == 1) &&
|
|
(VirtualAddress == PAGE_ALIGN(Wsle->u1.VirtualAddress))) {
|
|
|
|
ASSERT (Wsle->u1.e1.Direct == 0);
|
|
return (WSLE_NUMBER)(Wsle - WorkingSetList->Wsle);
|
|
}
|
|
Wsle += 1;
|
|
|
|
} while (Wsle <= LastWsle);
|
|
|
|
KeBugCheckEx (MEMORY_MANAGEMENT,
|
|
0x41284,
|
|
(ULONG_PTR)VirtualAddress,
|
|
WsPfnIndex,
|
|
(ULONG_PTR)WorkingSetList);
|
|
}
|
|
|
|
|
|
VOID
|
|
FASTCALL
|
|
MiRemoveWsle (
|
|
IN WSLE_NUMBER Entry,
|
|
IN PMMWSL WorkingSetList
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine removes a Working Set List Entry (WSLE) from the
|
|
working set.
|
|
|
|
Arguments:
|
|
|
|
Entry - The index number of the WSLE to remove.
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Environment:
|
|
|
|
Kernel mode, APCs disabled, Working Set Mutex held.
|
|
|
|
--*/
|
|
{
|
|
PMMWSLE Wsle;
|
|
PVOID VirtualAddress;
|
|
PMMWSLE_HASH Table;
|
|
WSLE_NUMBER Hash;
|
|
WSLE_NUMBER StartHash;
|
|
ULONG Tries;
|
|
|
|
Wsle = WorkingSetList->Wsle;
|
|
|
|
//
|
|
// Locate the entry in the tree.
|
|
//
|
|
|
|
#if DBG
|
|
if (MmDebug & MM_DBG_PTE_UPDATE) {
|
|
DbgPrint("removing wsle %p %p\n",
|
|
Entry, Wsle[Entry].u1.Long);
|
|
}
|
|
if (MmDebug & MM_DBG_DUMP_WSL) {
|
|
MiDumpWsl();
|
|
DbgPrint(" \n");
|
|
}
|
|
|
|
#endif //DBG
|
|
|
|
if (Entry > WorkingSetList->LastInitializedWsle) {
|
|
KeBugCheckEx (MEMORY_MANAGEMENT,
|
|
0x41785,
|
|
(ULONG_PTR)WorkingSetList,
|
|
Entry,
|
|
0);
|
|
}
|
|
|
|
ASSERT (Wsle[Entry].u1.e1.Valid == 1);
|
|
|
|
VirtualAddress = PAGE_ALIGN (Wsle[Entry].u1.VirtualAddress);
|
|
|
|
if (WorkingSetList == MmSystemCacheWorkingSetList) {
|
|
|
|
//
|
|
// count system space inserts and removals.
|
|
//
|
|
|
|
#if defined(_X86_)
|
|
if (MI_IS_SYSTEM_CACHE_ADDRESS(VirtualAddress)) {
|
|
MmSystemCachePage -= 1;
|
|
} else
|
|
#endif
|
|
if (VirtualAddress < MmSystemCacheStart) {
|
|
MmSystemCodePage -= 1;
|
|
} else if (VirtualAddress < MM_PAGED_POOL_START) {
|
|
MmSystemCachePage -= 1;
|
|
} else if (VirtualAddress < MmNonPagedSystemStart) {
|
|
MmPagedPoolPage -= 1;
|
|
} else {
|
|
MmSystemDriverPage -= 1;
|
|
}
|
|
}
|
|
|
|
Wsle[Entry].u1.e1.Valid = 0;
|
|
|
|
if (Wsle[Entry].u1.e1.Direct == 0) {
|
|
|
|
WorkingSetList->NonDirectCount -= 1;
|
|
|
|
if (WorkingSetList->HashTable) {
|
|
Hash = MI_WSLE_HASH(Wsle[Entry].u1.Long, WorkingSetList);
|
|
Table = WorkingSetList->HashTable;
|
|
Tries = 0;
|
|
|
|
StartHash = Hash;
|
|
|
|
while (Table[Hash].Key != VirtualAddress) {
|
|
Hash += 1;
|
|
if (Hash >= WorkingSetList->HashTableSize) {
|
|
ASSERT (Tries == 0);
|
|
Hash = 0;
|
|
Tries = 1;
|
|
}
|
|
if (Hash == StartHash) {
|
|
|
|
//
|
|
// The entry could not be found in the hash, it must
|
|
// never have been inserted. This is ok, we don't
|
|
// need to do anything more in this case.
|
|
//
|
|
|
|
return;
|
|
}
|
|
}
|
|
Table[Hash].Key = 0;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
MiSwapWslEntries (
|
|
IN WSLE_NUMBER SwapEntry,
|
|
IN WSLE_NUMBER Entry,
|
|
IN PMMSUPPORT WsInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine swaps the working set list entries Entry and SwapEntry
|
|
in the specified working set list (process or system cache).
|
|
|
|
Arguments:
|
|
|
|
SwapEntry - Supplies the first entry to swap. This entry must be
|
|
valid, i.e. in the working set at the current time.
|
|
|
|
Entry - Supplies the other entry to swap. This entry may be valid
|
|
or invalid.
|
|
|
|
WsInfo - Supplies the working set list.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Environment:
|
|
|
|
Kernel mode, Working set lock and PFN lock held (if system cache),
|
|
APCs disabled.
|
|
|
|
--*/
|
|
|
|
{
|
|
MMWSLE WsleEntry;
|
|
MMWSLE WsleSwap;
|
|
PMMPTE PointerPte;
|
|
PMMPFN Pfn1;
|
|
PMMWSLE Wsle;
|
|
PMMWSL WorkingSetList;
|
|
PMMWSLE_HASH Table;
|
|
|
|
WorkingSetList = WsInfo->VmWorkingSetList;
|
|
Wsle = WorkingSetList->Wsle;
|
|
|
|
WsleSwap = Wsle[SwapEntry];
|
|
|
|
ASSERT (WsleSwap.u1.e1.Valid != 0);
|
|
|
|
WsleEntry = Wsle[Entry];
|
|
|
|
Table = WorkingSetList->HashTable;
|
|
|
|
if (WsleEntry.u1.e1.Valid == 0) {
|
|
|
|
//
|
|
// Entry is not on any list. Remove it from the free list.
|
|
//
|
|
|
|
MiRemoveWsleFromFreeList (Entry, Wsle, WorkingSetList);
|
|
|
|
//
|
|
// Copy the Entry to this free one.
|
|
//
|
|
|
|
Wsle[Entry] = WsleSwap;
|
|
|
|
PointerPte = MiGetPteAddress (WsleSwap.u1.VirtualAddress);
|
|
|
|
if (WsleSwap.u1.e1.Direct) {
|
|
Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
|
|
Pfn1->u1.WsIndex = Entry;
|
|
} else {
|
|
|
|
//
|
|
// Update hash table.
|
|
//
|
|
|
|
if (Table) {
|
|
MiRepointWsleHashIndex (WsleSwap.u1.Long,
|
|
WorkingSetList,
|
|
Entry);
|
|
}
|
|
}
|
|
|
|
MI_SET_PTE_IN_WORKING_SET (PointerPte, Entry);
|
|
|
|
//
|
|
// Put entry on free list.
|
|
//
|
|
|
|
ASSERT ((WorkingSetList->FirstFree <= WorkingSetList->LastInitializedWsle) ||
|
|
(WorkingSetList->FirstFree == WSLE_NULL_INDEX));
|
|
|
|
Wsle[SwapEntry].u1.Long = WorkingSetList->FirstFree << MM_FREE_WSLE_SHIFT;
|
|
WorkingSetList->FirstFree = SwapEntry;
|
|
ASSERT ((WorkingSetList->FirstFree <= WorkingSetList->LastInitializedWsle) ||
|
|
(WorkingSetList->FirstFree == WSLE_NULL_INDEX));
|
|
|
|
} else {
|
|
|
|
//
|
|
// Both entries are valid.
|
|
//
|
|
|
|
Wsle[SwapEntry] = WsleEntry;
|
|
|
|
PointerPte = MiGetPteAddress (WsleEntry.u1.VirtualAddress);
|
|
|
|
if (WsleEntry.u1.e1.Direct) {
|
|
|
|
//
|
|
// Swap the PFN WsIndex element to point to the new slot.
|
|
//
|
|
|
|
Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
|
|
Pfn1->u1.WsIndex = SwapEntry;
|
|
} else {
|
|
|
|
//
|
|
// Update hash table.
|
|
//
|
|
|
|
if (Table) {
|
|
MiRepointWsleHashIndex (WsleEntry.u1.Long,
|
|
WorkingSetList,
|
|
SwapEntry);
|
|
}
|
|
}
|
|
|
|
MI_SET_PTE_IN_WORKING_SET (PointerPte, SwapEntry);
|
|
|
|
Wsle[Entry] = WsleSwap;
|
|
|
|
PointerPte = MiGetPteAddress (WsleSwap.u1.VirtualAddress);
|
|
|
|
if (WsleSwap.u1.e1.Direct) {
|
|
|
|
Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
|
|
Pfn1->u1.WsIndex = Entry;
|
|
} else {
|
|
if (Table) {
|
|
MiRepointWsleHashIndex (WsleSwap.u1.Long,
|
|
WorkingSetList,
|
|
Entry);
|
|
}
|
|
}
|
|
MI_SET_PTE_IN_WORKING_SET (PointerPte, Entry);
|
|
}
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
MiRepointWsleHashIndex (
|
|
IN ULONG_PTR WsleEntry,
|
|
IN PMMWSL WorkingSetList,
|
|
IN WSLE_NUMBER NewWsIndex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine repoints the working set list hash entry for the supplied
|
|
address so it points at the new working set index.
|
|
|
|
Arguments:
|
|
|
|
WsleEntry - Supplies the virtual address to look up.
|
|
|
|
WorkingSetList - Supplies the working set list to operate on.
|
|
|
|
NewWsIndex - Supplies the new working set list index to use.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Environment:
|
|
|
|
Kernel mode, Working set mutex held.
|
|
|
|
--*/
|
|
|
|
{
|
|
WSLE_NUMBER Hash;
|
|
WSLE_NUMBER StartHash;
|
|
PVOID VirtualAddress;
|
|
PMMWSLE_HASH Table;
|
|
ULONG Tries;
|
|
|
|
Tries = 0;
|
|
Table = WorkingSetList->HashTable;
|
|
VirtualAddress = PAGE_ALIGN (WsleEntry);
|
|
|
|
Hash = MI_WSLE_HASH (WsleEntry, WorkingSetList);
|
|
StartHash = Hash;
|
|
|
|
while (Table[Hash].Key != VirtualAddress) {
|
|
|
|
Hash += 1;
|
|
|
|
if (Hash >= WorkingSetList->HashTableSize) {
|
|
ASSERT (Tries == 0);
|
|
Hash = 0;
|
|
Tries = 1;
|
|
}
|
|
|
|
if (StartHash == Hash) {
|
|
|
|
//
|
|
// Didn't find the hash entry, so this virtual address must
|
|
// not have one. That's ok, just return as nothing needs to
|
|
// be done in this case.
|
|
//
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
Table[Hash].Index = NewWsIndex;
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
MiRemoveWsleFromFreeList (
|
|
IN WSLE_NUMBER Entry,
|
|
IN PMMWSLE Wsle,
|
|
IN PMMWSL WorkingSetList
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine removes a working set list entry from the free list.
|
|
It is used when the entry required is not the first element
|
|
in the free list.
|
|
|
|
Arguments:
|
|
|
|
Entry - Supplies the index of the entry to remove.
|
|
|
|
Wsle - Supplies a pointer to the array of WSLEs.
|
|
|
|
WorkingSetList - Supplies a pointer to the working set list.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Environment:
|
|
|
|
Kernel mode, Working set lock and PFN lock held, APCs disabled.
|
|
|
|
--*/
|
|
|
|
{
|
|
WSLE_NUMBER Free;
|
|
WSLE_NUMBER ParentFree;
|
|
|
|
Free = WorkingSetList->FirstFree;
|
|
|
|
if (Entry == Free) {
|
|
ASSERT ((Wsle[Entry].u1.Long >> MM_FREE_WSLE_SHIFT) <= WorkingSetList->LastInitializedWsle);
|
|
WorkingSetList->FirstFree = (WSLE_NUMBER)(Wsle[Entry].u1.Long >> MM_FREE_WSLE_SHIFT);
|
|
|
|
} else {
|
|
do {
|
|
ParentFree = Free;
|
|
ASSERT (Wsle[Free].u1.e1.Valid == 0);
|
|
Free = (WSLE_NUMBER)(Wsle[Free].u1.Long >> MM_FREE_WSLE_SHIFT);
|
|
} while (Free != Entry);
|
|
|
|
Wsle[ParentFree].u1.Long = Wsle[Entry].u1.Long;
|
|
}
|
|
ASSERT ((WorkingSetList->FirstFree <= WorkingSetList->LastInitializedWsle) ||
|
|
(WorkingSetList->FirstFree == WSLE_NULL_INDEX));
|
|
return;
|
|
}
|
|
|
|
|
|
#if 0
|
|
|
|
VOID
|
|
MiSwapWslEntries (
|
|
IN ULONG Entry,
|
|
IN ULONG Parent,
|
|
IN ULONG SwapEntry,
|
|
IN PMMWSL WorkingSetList
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function swaps the specified entry and updates its parent with
|
|
the specified swap entry.
|
|
|
|
The entry must be valid, i.e., the page is resident. The swap entry
|
|
can be valid or on the free list.
|
|
|
|
Arguments:
|
|
|
|
Entry - The index of the WSLE to swap.
|
|
|
|
Parent - The index of the parent of the WSLE to swap.
|
|
|
|
SwapEntry - The index to swap the entry with.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Environment:
|
|
|
|
Kernel mode, working set mutex held, APCs disabled.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG SwapParent;
|
|
ULONG SavedRight;
|
|
ULONG SavedLeft;
|
|
ULONG Free;
|
|
ULONG ParentFree;
|
|
ULONG SavedLong;
|
|
PVOID VirtualAddress;
|
|
PMMWSLE Wsle;
|
|
PMMPFN Pfn1;
|
|
PMMPTE PointerPte;
|
|
|
|
Wsle = WorkingSetList->Wsle;
|
|
|
|
if (Wsle[SwapEntry].u1.e1.Valid == 0) {
|
|
|
|
//
|
|
// This entry is not in use and must be removed from
|
|
// the free list.
|
|
//
|
|
|
|
Free = WorkingSetList->FirstFree;
|
|
|
|
if (SwapEntry == Free) {
|
|
WorkingSetList->FirstFree = Entry;
|
|
ASSERT ((WorkingSetList->FirstFree <= WorkingSetList->LastInitializedWsle) ||
|
|
(WorkingSetList->FirstFree == WSLE_NULL_INDEX));
|
|
|
|
} else {
|
|
|
|
while (Free != SwapEntry) {
|
|
ParentFree = Free;
|
|
Free = Wsle[Free].u2.s.LeftChild;
|
|
}
|
|
|
|
Wsle[ParentFree].u2.s.LeftChild = Entry;
|
|
}
|
|
|
|
//
|
|
// Swap the previous entry and the new unused entry.
|
|
//
|
|
|
|
SavedLeft = Wsle[Entry].u2.s.LeftChild;
|
|
Wsle[Entry].u2.s.LeftChild = Wsle[SwapEntry].u2.s.LeftChild;
|
|
Wsle[SwapEntry].u2.s.LeftChild = SavedLeft;
|
|
Wsle[SwapEntry].u2.s.RightChild = Wsle[Entry].u2.s.RightChild;
|
|
Wsle[SwapEntry].u1.Long = Wsle[Entry].u1.Long;
|
|
Wsle[Entry].u1.Long = 0;
|
|
|
|
//
|
|
// Make the parent point to the new entry.
|
|
//
|
|
|
|
if (Parent == WSLE_NULL_INDEX) {
|
|
|
|
//
|
|
// This entry is not in the tree.
|
|
//
|
|
|
|
PointerPte = MiGetPteAddress (Wsle[SwapEntry].u1.VirtualAddress);
|
|
Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
|
|
Pfn1->u1.WsIndex = SwapEntry;
|
|
return;
|
|
}
|
|
|
|
if (Parent == Entry) {
|
|
|
|
//
|
|
// This element is the root, update the root pointer.
|
|
//
|
|
|
|
WorkingSetList->Root = SwapEntry;
|
|
|
|
} else {
|
|
|
|
if (Wsle[Parent].u2.s.LeftChild == Entry) {
|
|
Wsle[Parent].u2.s.LeftChild = SwapEntry;
|
|
} else {
|
|
ASSERT (Wsle[Parent].u2.s.RightChild == Entry);
|
|
|
|
Wsle[Parent].u2.s.RightChild = SwapEntry;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
if ((Parent == WSLE_NULL_INDEX) &&
|
|
(Wsle[SwapEntry].u2.BothPointers == 0)) {
|
|
|
|
//
|
|
// Neither entry is in the tree, just swap their pointers.
|
|
//
|
|
|
|
SavedLong = Wsle[SwapEntry].u1.Long;
|
|
Wsle[SwapEntry].u1.Long = Wsle[Entry].u1.Long;
|
|
Wsle[Entry].u1.Long = SavedLong;
|
|
|
|
PointerPte = MiGetPteAddress (Wsle[Entry].u1.VirtualAddress);
|
|
Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
|
|
Pfn1->u1.WsIndex = Entry;
|
|
|
|
PointerPte = MiGetPteAddress (Wsle[SwapEntry].u1.VirtualAddress);
|
|
Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
|
|
Pfn1->u1.WsIndex = SwapEntry;
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// The entry at FirstDynamic is valid; swap it with this one and
|
|
// update both parents.
|
|
//
|
|
|
|
SwapParent = WorkingSetList->Root;
|
|
|
|
if (SwapParent == SwapEntry) {
|
|
|
|
//
|
|
// The entry we are swapping with is at the root.
|
|
//
|
|
|
|
if (Wsle[SwapEntry].u2.s.LeftChild == Entry) {
|
|
|
|
//
|
|
// The entry we are going to swap is the left child of this
|
|
// entry.
|
|
//
|
|
// R(SwapEntry)
|
|
// / \
|
|
// (entry)
|
|
//
|
|
|
|
WorkingSetList->Root = Entry;
|
|
|
|
Wsle[SwapEntry].u2.s.LeftChild = Wsle[Entry].u2.s.LeftChild;
|
|
Wsle[Entry].u2.s.LeftChild = SwapEntry;
|
|
SavedRight = Wsle[SwapEntry].u2.s.RightChild;
|
|
Wsle[SwapEntry].u2.s.RightChild = Wsle[Entry].u2.s.RightChild;
|
|
Wsle[Entry].u2.s.RightChild = SavedRight;
|
|
|
|
SavedLong = Wsle[Entry].u1.Long;
|
|
Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long;
|
|
Wsle[SwapEntry].u1.Long = SavedLong;
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
if (Wsle[SwapEntry].u2.s.RightChild == Entry) {
|
|
|
|
//
|
|
// The entry we are going to swap is the right child of this
|
|
// entry.
|
|
//
|
|
// R(SwapEntry)
|
|
// / \
|
|
// (entry)
|
|
//
|
|
|
|
WorkingSetList->Root = Entry;
|
|
|
|
Wsle[SwapEntry].u2.s.RightChild = Wsle[Entry].u2.s.RightChild;
|
|
Wsle[Entry].u2.s.RightChild = SwapEntry;
|
|
SavedLeft = Wsle[SwapEntry].u2.s.LeftChild;
|
|
Wsle[SwapEntry].u2.s.LeftChild = Wsle[Entry].u2.s.LeftChild;
|
|
Wsle[Entry].u2.s.LeftChild = SavedLeft;
|
|
|
|
|
|
SavedLong = Wsle[Entry].u1.Long;
|
|
Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long;
|
|
Wsle[SwapEntry].u1.Long = SavedLong;
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// The swap entry is the root, but the other entry is not
|
|
// its child.
|
|
//
|
|
//
|
|
// R(SwapEntry)
|
|
// / \
|
|
// .....
|
|
// Parent(Entry)
|
|
// \
|
|
// Entry (left or right)
|
|
//
|
|
//
|
|
|
|
WorkingSetList->Root = Entry;
|
|
|
|
SavedRight = Wsle[SwapEntry].u2.s.RightChild;
|
|
Wsle[SwapEntry].u2.s.RightChild = Wsle[Entry].u2.s.RightChild;
|
|
Wsle[Entry].u2.s.RightChild = SavedRight;
|
|
SavedLeft = Wsle[SwapEntry].u2.s.LeftChild;
|
|
Wsle[SwapEntry].u2.s.LeftChild = Wsle[Entry].u2.s.LeftChild;
|
|
Wsle[Entry].u2.s.LeftChild = SavedLeft;
|
|
|
|
SavedLong = Wsle[Entry].u1.Long;
|
|
Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long;
|
|
Wsle[SwapEntry].u1.Long = SavedLong;
|
|
|
|
if (Parent == WSLE_NULL_INDEX) {
|
|
|
|
//
|
|
// This entry is not in the tree.
|
|
//
|
|
|
|
PointerPte = MiGetPteAddress (Wsle[SwapEntry].u1.VirtualAddress);
|
|
Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
|
|
Pfn1->u1.WsIndex = SwapEntry;
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Change the parent of the entry to point to the swap entry.
|
|
//
|
|
|
|
if (Wsle[Parent].u2.s.RightChild == Entry) {
|
|
Wsle[Parent].u2.s.RightChild = SwapEntry;
|
|
} else {
|
|
Wsle[Parent].u2.s.LeftChild = SwapEntry;
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// The SwapEntry is not the root, find its parent.
|
|
//
|
|
|
|
if (Wsle[SwapEntry].u2.BothPointers == 0) {
|
|
|
|
//
|
|
// Entry is not in tree, therefore no parent.
|
|
|
|
SwapParent = WSLE_NULL_INDEX;
|
|
|
|
} else {
|
|
|
|
VirtualAddress = PAGE_ALIGN(Wsle[SwapEntry].u1.VirtualAddress);
|
|
|
|
for (;;) {
|
|
|
|
ASSERT (SwapParent != WSLE_NULL_INDEX);
|
|
|
|
if (Wsle[SwapParent].u2.s.LeftChild == SwapEntry) {
|
|
break;
|
|
}
|
|
if (Wsle[SwapParent].u2.s.RightChild == SwapEntry) {
|
|
break;
|
|
}
|
|
|
|
|
|
if (VirtualAddress < PAGE_ALIGN(Wsle[SwapParent].u1.VirtualAddress)) {
|
|
SwapParent = Wsle[SwapParent].u2.s.LeftChild;
|
|
} else {
|
|
SwapParent = Wsle[SwapParent].u2.s.RightChild;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Parent == WorkingSetList->Root) {
|
|
|
|
//
|
|
// The entry is at the root.
|
|
//
|
|
|
|
if (Wsle[Entry].u2.s.LeftChild == SwapEntry) {
|
|
|
|
//
|
|
// The entry we are going to swap is the left child of this
|
|
// entry.
|
|
//
|
|
// R(Entry)
|
|
// / \
|
|
// (SwapEntry)
|
|
//
|
|
|
|
WorkingSetList->Root = SwapEntry;
|
|
|
|
Wsle[Entry].u2.s.LeftChild = Wsle[SwapEntry].u2.s.LeftChild;
|
|
Wsle[SwapEntry].u2.s.LeftChild = Entry;
|
|
SavedRight = Wsle[Entry].u2.s.RightChild;
|
|
Wsle[Entry].u2.s.RightChild = Wsle[SwapEntry].u2.s.RightChild;
|
|
Wsle[SwapEntry].u2.s.RightChild = SavedRight;
|
|
|
|
SavedLong = Wsle[Entry].u1.Long;
|
|
Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long;
|
|
Wsle[SwapEntry].u1.Long = SavedLong;
|
|
|
|
return;
|
|
|
|
} else if (Wsle[SwapEntry].u2.s.RightChild == Entry) {
|
|
|
|
//
|
|
// The entry we are going to swap is the right child of this
|
|
// entry.
|
|
//
|
|
// R(SwapEntry)
|
|
// / \
|
|
// (entry)
|
|
//
|
|
|
|
WorkingSetList->Root = Entry;
|
|
|
|
Wsle[SwapEntry].u2.s.RightChild = Wsle[Entry].u2.s.RightChild;
|
|
Wsle[Entry].u2.s.RightChild = SwapEntry;
|
|
SavedLeft = Wsle[SwapEntry].u2.s.LeftChild;
|
|
Wsle[SwapEntry].u2.s.LeftChild = Wsle[Entry].u2.s.LeftChild;
|
|
Wsle[Entry].u2.s.LeftChild = SavedLeft;
|
|
|
|
|
|
SavedLong = Wsle[Entry].u1.Long;
|
|
Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long;
|
|
Wsle[SwapEntry].u1.Long = SavedLong;
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// The swap entry is the root, but the other entry is not
|
|
// its child.
|
|
//
|
|
//
|
|
// R(SwapEntry)
|
|
// / \
|
|
// .....
|
|
// Parent(Entry)
|
|
// \
|
|
// Entry (left or right)
|
|
//
|
|
//
|
|
|
|
WorkingSetList->Root = Entry;
|
|
|
|
SavedRight = Wsle[SwapEntry].u2.s.RightChild;
|
|
Wsle[SwapEntry].u2.s.RightChild = Wsle[Entry].u2.s.RightChild;
|
|
Wsle[Entry].u2.s.RightChild = SavedRight;
|
|
SavedLeft = Wsle[SwapEntry].u2.s.LeftChild;
|
|
Wsle[SwapEntry].u2.s.LeftChild = Wsle[Entry].u2.s.LeftChild;
|
|
Wsle[Entry].u2.s.LeftChild = SavedLeft;
|
|
|
|
SavedLong = Wsle[Entry].u1.Long;
|
|
Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long;
|
|
Wsle[SwapEntry].u1.Long = SavedLong;
|
|
|
|
if (SwapParent == WSLE_NULL_INDEX) {
|
|
|
|
//
|
|
// This entry is not in the tree.
|
|
//
|
|
|
|
PointerPte = MiGetPteAddress (Wsle[Entry].u1.VirtualAddress);
|
|
Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
|
|
ASSERT (Pfn1->u1.WsIndex == SwapEntry);
|
|
Pfn1->u1.WsIndex = Entry;
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Change the parent of the entry to point to the swap entry.
|
|
//
|
|
|
|
if (Wsle[SwapParent].u2.s.RightChild == SwapEntry) {
|
|
Wsle[SwapParent].u2.s.RightChild = Entry;
|
|
} else {
|
|
Wsle[SwapParent].u2.s.LeftChild = Entry;
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// Neither entry is the root.
|
|
//
|
|
|
|
if (Parent == SwapEntry) {
|
|
|
|
//
|
|
// The parent of the entry is the swap entry.
|
|
//
|
|
//
|
|
// R
|
|
// .....
|
|
//
|
|
// (SwapParent)
|
|
// |
|
|
// (SwapEntry)
|
|
// |
|
|
// (Entry)
|
|
//
|
|
|
|
//
|
|
// Update the parent pointer for the swapentry.
|
|
//
|
|
|
|
if (Wsle[SwapParent].u2.s.LeftChild == SwapEntry) {
|
|
Wsle[SwapParent].u2.s.LeftChild = Entry;
|
|
} else {
|
|
Wsle[SwapParent].u2.s.RightChild = Entry;
|
|
}
|
|
|
|
//
|
|
// Determine if this goes left or right.
|
|
//
|
|
|
|
if (Wsle[SwapEntry].u2.s.LeftChild == Entry) {
|
|
|
|
//
|
|
// The entry we are going to swap is the left child of this
|
|
// entry.
|
|
//
|
|
// R
|
|
// .....
|
|
//
|
|
// (SwapParent)
|
|
//
|
|
// (SwapEntry) [Parent(entry)]
|
|
// / \
|
|
// (entry)
|
|
//
|
|
|
|
Wsle[SwapEntry].u2.s.LeftChild = Wsle[Entry].u2.s.LeftChild;
|
|
Wsle[Entry].u2.s.LeftChild = SwapEntry;
|
|
SavedRight = Wsle[SwapEntry].u2.s.RightChild;
|
|
Wsle[SwapEntry].u2.s.RightChild = Wsle[Entry].u2.s.RightChild;
|
|
Wsle[Entry].u2.s.RightChild = SavedRight;
|
|
|
|
SavedLong = Wsle[Entry].u1.Long;
|
|
Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long;
|
|
Wsle[SwapEntry].u1.Long = SavedLong;
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
ASSERT (Wsle[SwapEntry].u2.s.RightChild == Entry);
|
|
|
|
//
|
|
// The entry we are going to swap is the right child of this
|
|
// entry.
|
|
//
|
|
// R
|
|
// .....
|
|
//
|
|
// (SwapParent)
|
|
// \
|
|
// (SwapEntry)
|
|
// / \
|
|
// (entry)
|
|
//
|
|
|
|
Wsle[SwapEntry].u2.s.RightChild = Wsle[Entry].u2.s.RightChild;
|
|
Wsle[Entry].u2.s.RightChild = SwapEntry;
|
|
SavedLeft = Wsle[SwapEntry].u2.s.LeftChild;
|
|
Wsle[SwapEntry].u2.s.LeftChild = Wsle[Entry].u2.s.LeftChild;
|
|
Wsle[Entry].u2.s.LeftChild = SavedLeft;
|
|
|
|
|
|
SavedLong = Wsle[Entry].u1.Long;
|
|
Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long;
|
|
Wsle[SwapEntry].u1.Long = SavedLong;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
}
|
|
if (SwapParent == Entry) {
|
|
|
|
|
|
//
|
|
// The parent of the swap entry is the entry.
|
|
//
|
|
// R
|
|
// .....
|
|
//
|
|
// (Parent)
|
|
// |
|
|
// (Entry)
|
|
// |
|
|
// (SwapEntry)
|
|
//
|
|
|
|
//
|
|
// Update the parent pointer for the entry.
|
|
//
|
|
|
|
if (Wsle[Parent].u2.s.LeftChild == Entry) {
|
|
Wsle[Parent].u2.s.LeftChild = SwapEntry;
|
|
} else {
|
|
Wsle[Parent].u2.s.RightChild = SwapEntry;
|
|
}
|
|
|
|
//
|
|
// Determine if this goes left or right.
|
|
//
|
|
|
|
if (Wsle[Entry].u2.s.LeftChild == SwapEntry) {
|
|
|
|
//
|
|
// The entry we are going to swap is the left child of this
|
|
// entry.
|
|
//
|
|
// R
|
|
// .....
|
|
//
|
|
// (Parent)
|
|
// |
|
|
// (Entry)
|
|
// /
|
|
// (SwapEntry)
|
|
//
|
|
|
|
Wsle[Entry].u2.s.LeftChild = Wsle[SwapEntry].u2.s.LeftChild;
|
|
Wsle[SwapEntry].u2.s.LeftChild = Entry;
|
|
SavedRight = Wsle[Entry].u2.s.RightChild;
|
|
Wsle[Entry].u2.s.RightChild = Wsle[SwapEntry].u2.s.RightChild;
|
|
Wsle[SwapEntry].u2.s.RightChild = SavedRight;
|
|
|
|
SavedLong = Wsle[Entry].u1.Long;
|
|
Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long;
|
|
Wsle[SwapEntry].u1.Long = SavedLong;
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
ASSERT (Wsle[Entry].u2.s.RightChild == SwapEntry);
|
|
|
|
//
|
|
// The entry we are going to swap is the right child of this
|
|
// entry.
|
|
//
|
|
// R(Entry)
|
|
// / \
|
|
// (SwapEntry)
|
|
//
|
|
|
|
Wsle[Entry].u2.s.RightChild = Wsle[SwapEntry].u2.s.RightChild;
|
|
Wsle[SwapEntry].u2.s.RightChild = Entry;
|
|
SavedLeft = Wsle[SwapEntry].u2.s.LeftChild;
|
|
Wsle[SwapEntry].u2.s.LeftChild = Wsle[Entry].u2.s.LeftChild;
|
|
Wsle[Entry].u2.s.LeftChild = SavedLeft;
|
|
|
|
SavedLong = Wsle[Entry].u1.Long;
|
|
Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long;
|
|
Wsle[SwapEntry].u1.Long = SavedLong;
|
|
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Neither entry is the parent of the other. Just swap them
|
|
// and update the parent entries.
|
|
//
|
|
|
|
if (Parent == WSLE_NULL_INDEX) {
|
|
|
|
//
|
|
// This entry is not in the tree.
|
|
//
|
|
|
|
PointerPte = MiGetPteAddress (Wsle[Entry].u1.VirtualAddress);
|
|
Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
|
|
ASSERT (Pfn1->u1.WsIndex == Entry);
|
|
Pfn1->u1.WsIndex = SwapEntry;
|
|
|
|
} else {
|
|
|
|
if (Wsle[Parent].u2.s.LeftChild == Entry) {
|
|
Wsle[Parent].u2.s.LeftChild = SwapEntry;
|
|
} else {
|
|
Wsle[Parent].u2.s.RightChild = SwapEntry;
|
|
}
|
|
}
|
|
|
|
if (SwapParent == WSLE_NULL_INDEX) {
|
|
|
|
//
|
|
// This entry is not in the tree.
|
|
//
|
|
|
|
PointerPte = MiGetPteAddress (Wsle[SwapEntry].u1.VirtualAddress);
|
|
Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
|
|
ASSERT (Pfn1->u1.WsIndex == SwapEntry);
|
|
Pfn1->u1.WsIndex = Entry;
|
|
} else {
|
|
|
|
if (Wsle[SwapParent].u2.s.LeftChild == SwapEntry) {
|
|
Wsle[SwapParent].u2.s.LeftChild = Entry;
|
|
} else {
|
|
Wsle[SwapParent].u2.s.RightChild = Entry;
|
|
}
|
|
}
|
|
|
|
SavedRight = Wsle[SwapEntry].u2.s.RightChild;
|
|
Wsle[SwapEntry].u2.s.RightChild = Wsle[Entry].u2.s.RightChild;
|
|
Wsle[Entry].u2.s.RightChild = SavedRight;
|
|
SavedLeft = Wsle[SwapEntry].u2.s.LeftChild;
|
|
Wsle[SwapEntry].u2.s.LeftChild = Wsle[Entry].u2.s.LeftChild;
|
|
Wsle[Entry].u2.s.LeftChild = SavedLeft;
|
|
|
|
SavedLong = Wsle[Entry].u1.Long;
|
|
Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long;
|
|
Wsle[SwapEntry].u1.Long = SavedLong;
|
|
|
|
return;
|
|
}
|
|
}
|
|
#endif //0
|