2004-03-05 11:31:59 +00:00
|
|
|
/* $Id: pageop.c,v 1.19 2004/03/05 11:31:59 hbirr Exp $
|
2001-02-16 18:32:20 +00:00
|
|
|
*
|
|
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
|
|
* PROJECT: ReactOS kernel
|
|
|
|
* FILE: ntoskrnl/mm/pageop.c
|
|
|
|
* PROGRAMMER: David Welch (welch@cwcom.net)
|
|
|
|
* UPDATE HISTORY:
|
|
|
|
* 27/05/98: Created
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES ****************************************************************/
|
|
|
|
|
2002-09-08 10:23:54 +00:00
|
|
|
#include <ddk/ntddk.h>
|
|
|
|
#include <internal/ps.h>
|
|
|
|
#include <internal/mm.h>
|
|
|
|
#include <internal/pool.h>
|
2001-02-16 18:32:20 +00:00
|
|
|
|
|
|
|
#define NDEBUG
|
|
|
|
#include <internal/debug.h>
|
|
|
|
|
|
|
|
/* GLOBALS *******************************************************************/
|
|
|
|
|
|
|
|
#define PAGEOP_HASH_TABLE_SIZE (32)
|
|
|
|
|
2003-01-11 15:26:59 +00:00
|
|
|
static KSPIN_LOCK MmPageOpHashTableLock;
|
|
|
|
static PMM_PAGEOP MmPageOpHashTable[PAGEOP_HASH_TABLE_SIZE];
|
|
|
|
static NPAGED_LOOKASIDE_LIST MmPageOpLookasideList;
|
2001-02-16 18:32:20 +00:00
|
|
|
|
2001-03-07 16:48:45 +00:00
|
|
|
#define TAG_MM_PAGEOP TAG('M', 'P', 'O', 'P')
|
|
|
|
|
2001-02-16 18:32:20 +00:00
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
|
|
|
|
VOID
|
2002-05-14 21:19:21 +00:00
|
|
|
MmReleasePageOp(PMM_PAGEOP PageOp)
|
2001-03-13 16:25:55 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Release a reference to a page operation descriptor
|
|
|
|
*/
|
2001-02-16 18:32:20 +00:00
|
|
|
{
|
|
|
|
KIRQL oldIrql;
|
2001-03-13 16:25:55 +00:00
|
|
|
PMM_PAGEOP PrevPageOp;
|
2001-02-16 18:32:20 +00:00
|
|
|
|
2002-01-09 03:00:21 +00:00
|
|
|
KeAcquireSpinLock(&MmPageOpHashTableLock, &oldIrql);
|
2001-02-16 18:32:20 +00:00
|
|
|
PageOp->ReferenceCount--;
|
|
|
|
if (PageOp->ReferenceCount > 0)
|
|
|
|
{
|
2002-01-09 03:00:21 +00:00
|
|
|
KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
|
2001-02-16 18:32:20 +00:00
|
|
|
return;
|
|
|
|
}
|
My biggest commit so far (everything compiles and apparently runs fine):
- replaced DWORD with ULONG in a couple of places
- replaced some ULONGs with LONGs in the KD GDB stub
- replaced INITIAL_TEB with USER_STACK, as per Nebbet's book, to support both fixed size and expandable stacks
- added InterlockedExchangePointer
- added the ASM_BREAKPOINT macro as the architecture-dependent assembler code to raise a breakpoint exception
- corrected definitions of INT, LONG, DWORD, UINT, ULONG and ULONG32
- corrected IoSetCancelRoutine to use InterlockedExchangePointer
- corrected definition of NtCurrentTeb and NtCurrentPeb
- corrected DbgBreakPoint and DbgUserBreakPoint not to set up a stack frame (temporary fix with inline assembler - why doesn't GCC understand __declspec(naked)?)
- corrected various calls to Interlocked* functions to cast OUT operands to LONG *
- corrected various printf format strings
- corrected DbgUiIssueRemoteBreakin to use the smallest possible stack (this is what started everything)
- removed a DPRINT that accessed pageable memory at non-PASSIVE_LEVEL IRQL
- beautified CreateProcessA (another temporary fix - all the new functions will be isolated in the upcoming stand-alone RTL)
- prefixed LdrInitializeThunk with a nop that can be overwritten with a breakpoint for debugging purposes (temporary debugging aid until we have user-mode debugger support). Will add support for this to the breakin utility soon
- thread creation code rewritten from scratch (some glitches documented inline, but works fine)
- thread creation code now duplicated just twice, as opposed to five times (temporary fix - three new, non standard functions have been exported from NTDLL.DLL, will fix later)
svn path=/trunk/; revision=4595
2003-04-26 23:13:33 +00:00
|
|
|
InterlockedDecrement((LONG *)&PageOp->MArea->PageOpCount);
|
2001-03-13 16:25:55 +00:00
|
|
|
PrevPageOp = MmPageOpHashTable[PageOp->Hash];
|
|
|
|
if (PrevPageOp == PageOp)
|
2001-02-16 18:32:20 +00:00
|
|
|
{
|
2001-03-13 16:25:55 +00:00
|
|
|
MmPageOpHashTable[PageOp->Hash] = PageOp->Next;
|
2001-02-16 18:32:20 +00:00
|
|
|
KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
|
2003-01-11 15:26:59 +00:00
|
|
|
ExFreeToNPagedLookasideList(&MmPageOpLookasideList, PageOp);
|
2001-02-16 18:32:20 +00:00
|
|
|
return;
|
|
|
|
}
|
2002-02-18 18:41:23 +00:00
|
|
|
while (PrevPageOp->Next != NULL)
|
2001-02-16 18:32:20 +00:00
|
|
|
{
|
2002-02-18 18:41:23 +00:00
|
|
|
if (PrevPageOp->Next == PageOp)
|
2001-02-16 18:32:20 +00:00
|
|
|
{
|
2001-03-13 16:25:55 +00:00
|
|
|
PrevPageOp->Next = PageOp->Next;
|
2001-02-16 18:32:20 +00:00
|
|
|
KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
|
2003-01-11 15:26:59 +00:00
|
|
|
ExFreeToNPagedLookasideList(&MmPageOpLookasideList, PageOp);
|
2001-02-16 18:32:20 +00:00
|
|
|
return;
|
|
|
|
}
|
2001-03-13 16:25:55 +00:00
|
|
|
PrevPageOp = PrevPageOp->Next;
|
2001-02-16 18:32:20 +00:00
|
|
|
}
|
|
|
|
KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
|
2003-07-21 21:53:53 +00:00
|
|
|
KEBUGCHECK(0);
|
2001-02-16 18:32:20 +00:00
|
|
|
}
|
|
|
|
|
2002-06-11 22:09:03 +00:00
|
|
|
PMM_PAGEOP
|
|
|
|
MmCheckForPageOp(PMEMORY_AREA MArea, ULONG Pid, PVOID Address,
|
|
|
|
PMM_SECTION_SEGMENT Segment, ULONG Offset)
|
|
|
|
{
|
|
|
|
ULONG Hash;
|
|
|
|
KIRQL oldIrql;
|
|
|
|
PMM_PAGEOP PageOp;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Calcuate the hash value for pageop structure
|
|
|
|
*/
|
2002-08-10 16:41:20 +00:00
|
|
|
if (MArea->Type == MEMORY_AREA_SECTION_VIEW)
|
2002-06-11 22:09:03 +00:00
|
|
|
{
|
2002-10-01 19:27:25 +00:00
|
|
|
Hash = (((ULONG)Segment) | (((ULONG)Offset) / PAGE_SIZE));
|
2002-06-11 22:09:03 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2002-10-01 19:27:25 +00:00
|
|
|
Hash = (((ULONG)Pid) | (((ULONG)Address) / PAGE_SIZE));
|
2002-06-11 22:09:03 +00:00
|
|
|
}
|
|
|
|
Hash = Hash % PAGEOP_HASH_TABLE_SIZE;
|
|
|
|
|
|
|
|
KeAcquireSpinLock(&MmPageOpHashTableLock, &oldIrql);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check for an existing pageop structure
|
|
|
|
*/
|
|
|
|
PageOp = MmPageOpHashTable[Hash];
|
|
|
|
while (PageOp != NULL)
|
|
|
|
{
|
2002-08-10 16:41:20 +00:00
|
|
|
if (MArea->Type == MEMORY_AREA_SECTION_VIEW)
|
2002-06-11 22:09:03 +00:00
|
|
|
{
|
|
|
|
if (PageOp->Segment == Segment &&
|
|
|
|
PageOp->Offset == Offset)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (PageOp->Pid == Pid &&
|
|
|
|
PageOp->Address == Address)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
PageOp = PageOp->Next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we found an existing pageop then increment the reference count
|
|
|
|
* and return it.
|
|
|
|
*/
|
|
|
|
if (PageOp != NULL)
|
|
|
|
{
|
|
|
|
PageOp->ReferenceCount++;
|
|
|
|
KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
|
|
|
|
return(PageOp);
|
|
|
|
}
|
|
|
|
KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
|
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
|
2001-02-16 18:32:20 +00:00
|
|
|
PMM_PAGEOP
|
2002-05-14 21:19:21 +00:00
|
|
|
MmGetPageOp(PMEMORY_AREA MArea, ULONG Pid, PVOID Address,
|
2004-03-05 11:31:59 +00:00
|
|
|
PMM_SECTION_SEGMENT Segment, ULONG Offset, ULONG OpType, BOOL First)
|
2002-05-14 21:19:21 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Get a page operation descriptor corresponding to
|
|
|
|
* the memory area and either the segment, offset pair or the
|
|
|
|
* pid, address pair.
|
|
|
|
*/
|
2001-02-16 18:32:20 +00:00
|
|
|
{
|
2001-03-13 16:25:55 +00:00
|
|
|
ULONG Hash;
|
2001-02-16 18:32:20 +00:00
|
|
|
KIRQL oldIrql;
|
|
|
|
PMM_PAGEOP PageOp;
|
|
|
|
|
|
|
|
/*
|
2002-05-14 21:19:21 +00:00
|
|
|
* Calcuate the hash value for pageop structure
|
2001-02-16 18:32:20 +00:00
|
|
|
*/
|
2002-08-10 16:41:20 +00:00
|
|
|
if (MArea->Type == MEMORY_AREA_SECTION_VIEW)
|
2001-02-16 18:32:20 +00:00
|
|
|
{
|
2002-10-01 19:27:25 +00:00
|
|
|
Hash = (((ULONG)Segment) | (((ULONG)Offset) / PAGE_SIZE));
|
2001-02-16 18:32:20 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2002-10-01 19:27:25 +00:00
|
|
|
Hash = (((ULONG)Pid) | (((ULONG)Address) / PAGE_SIZE));
|
2001-02-16 18:32:20 +00:00
|
|
|
}
|
2001-03-13 16:25:55 +00:00
|
|
|
Hash = Hash % PAGEOP_HASH_TABLE_SIZE;
|
2001-02-16 18:32:20 +00:00
|
|
|
|
|
|
|
KeAcquireSpinLock(&MmPageOpHashTableLock, &oldIrql);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check for an existing pageop structure
|
|
|
|
*/
|
2001-03-13 16:25:55 +00:00
|
|
|
PageOp = MmPageOpHashTable[Hash];
|
2001-02-16 18:32:20 +00:00
|
|
|
while (PageOp != NULL)
|
|
|
|
{
|
2002-08-10 16:41:20 +00:00
|
|
|
if (MArea->Type == MEMORY_AREA_SECTION_VIEW)
|
2001-02-16 18:32:20 +00:00
|
|
|
{
|
|
|
|
if (PageOp->Segment == Segment &&
|
|
|
|
PageOp->Offset == Offset)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (PageOp->Pid == Pid &&
|
|
|
|
PageOp->Address == Address)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
PageOp = PageOp->Next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we found an existing pageop then increment the reference count
|
|
|
|
* and return it.
|
|
|
|
*/
|
|
|
|
if (PageOp != NULL)
|
|
|
|
{
|
2004-03-05 11:31:59 +00:00
|
|
|
if (First)
|
|
|
|
{
|
|
|
|
PageOp = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
PageOp->ReferenceCount++;
|
|
|
|
}
|
2001-02-16 18:32:20 +00:00
|
|
|
KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
|
|
|
|
return(PageOp);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Otherwise add a new pageop.
|
|
|
|
*/
|
2003-01-11 15:26:59 +00:00
|
|
|
PageOp = ExAllocateFromNPagedLookasideList(&MmPageOpLookasideList);
|
2001-02-16 18:32:20 +00:00
|
|
|
if (PageOp == NULL)
|
|
|
|
{
|
|
|
|
KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
|
2004-03-05 11:31:59 +00:00
|
|
|
KEBUGCHECK(0);
|
2001-02-16 18:32:20 +00:00
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
|
2002-08-10 16:41:20 +00:00
|
|
|
if (MArea->Type != MEMORY_AREA_SECTION_VIEW)
|
2001-02-16 18:32:20 +00:00
|
|
|
{
|
|
|
|
PageOp->Pid = Pid;
|
|
|
|
PageOp->Address = Address;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
PageOp->Segment = Segment;
|
|
|
|
PageOp->Offset = Offset;
|
|
|
|
}
|
|
|
|
PageOp->ReferenceCount = 1;
|
2001-03-13 16:25:55 +00:00
|
|
|
PageOp->Next = MmPageOpHashTable[Hash];
|
|
|
|
PageOp->Hash = Hash;
|
|
|
|
PageOp->Thread = PsGetCurrentThread();
|
|
|
|
PageOp->Abandoned = FALSE;
|
|
|
|
PageOp->Status = STATUS_PENDING;
|
2001-04-04 22:21:32 +00:00
|
|
|
PageOp->OpType = OpType;
|
2002-06-11 22:09:03 +00:00
|
|
|
PageOp->MArea = MArea;
|
2001-03-13 16:25:55 +00:00
|
|
|
KeInitializeEvent(&PageOp->CompletionEvent, NotificationEvent, FALSE);
|
|
|
|
MmPageOpHashTable[Hash] = PageOp;
|
My biggest commit so far (everything compiles and apparently runs fine):
- replaced DWORD with ULONG in a couple of places
- replaced some ULONGs with LONGs in the KD GDB stub
- replaced INITIAL_TEB with USER_STACK, as per Nebbet's book, to support both fixed size and expandable stacks
- added InterlockedExchangePointer
- added the ASM_BREAKPOINT macro as the architecture-dependent assembler code to raise a breakpoint exception
- corrected definitions of INT, LONG, DWORD, UINT, ULONG and ULONG32
- corrected IoSetCancelRoutine to use InterlockedExchangePointer
- corrected definition of NtCurrentTeb and NtCurrentPeb
- corrected DbgBreakPoint and DbgUserBreakPoint not to set up a stack frame (temporary fix with inline assembler - why doesn't GCC understand __declspec(naked)?)
- corrected various calls to Interlocked* functions to cast OUT operands to LONG *
- corrected various printf format strings
- corrected DbgUiIssueRemoteBreakin to use the smallest possible stack (this is what started everything)
- removed a DPRINT that accessed pageable memory at non-PASSIVE_LEVEL IRQL
- beautified CreateProcessA (another temporary fix - all the new functions will be isolated in the upcoming stand-alone RTL)
- prefixed LdrInitializeThunk with a nop that can be overwritten with a breakpoint for debugging purposes (temporary debugging aid until we have user-mode debugger support). Will add support for this to the breakin utility soon
- thread creation code rewritten from scratch (some glitches documented inline, but works fine)
- thread creation code now duplicated just twice, as opposed to five times (temporary fix - three new, non standard functions have been exported from NTDLL.DLL, will fix later)
svn path=/trunk/; revision=4595
2003-04-26 23:13:33 +00:00
|
|
|
InterlockedIncrement((LONG *)&MArea->PageOpCount);
|
2001-02-16 18:32:20 +00:00
|
|
|
|
|
|
|
KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
|
|
|
|
return(PageOp);
|
|
|
|
}
|
2001-03-13 16:25:55 +00:00
|
|
|
|
2003-10-12 17:05:50 +00:00
|
|
|
VOID INIT_FUNCTION
|
2003-01-11 15:26:59 +00:00
|
|
|
MmInitializePageOp(VOID)
|
|
|
|
{
|
|
|
|
memset(MmPageOpHashTable, 0, sizeof(MmPageOpHashTable));
|
|
|
|
KeInitializeSpinLock(&MmPageOpHashTableLock);
|
|
|
|
|
|
|
|
ExInitializeNPagedLookasideList (&MmPageOpLookasideList,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
sizeof(MM_PAGEOP),
|
|
|
|
TAG_MM_PAGEOP,
|
|
|
|
50);
|
|
|
|
}
|
2001-03-13 16:25:55 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|