Changed irq handler from C to assembler

Began work on holding information about active page operations

svn path=/trunk/; revision=1622
This commit is contained in:
David Welch 2001-02-16 18:32:20 +00:00
parent 727b62c27f
commit beae346469
5 changed files with 850 additions and 94 deletions

View file

@ -333,17 +333,24 @@ typedef struct
extern MM_STATS MmStats;
NTSTATUS MmWritePageSectionView(PMADDRESS_SPACE AddressSpace,
PMEMORY_AREA MArea,
PVOID Address);
NTSTATUS MmWritePageVirtualMemory(PMADDRESS_SPACE AddressSpace,
PMEMORY_AREA MArea,
PVOID Address);
PVOID MmGetDirtyPagesFromWorkingSet(struct _EPROCESS* Process);
NTSTATUS MmWriteToSwapPage(SWAPENTRY SwapEntry, PMDL Mdl);
NTSTATUS MmReadFromSwapPage(SWAPENTRY SwapEntry, PMDL Mdl);
VOID MmSetFlagsPage(PVOID PhysicalAddress, ULONG Flags);
ULONG MmGetFlagsPage(PVOID PhysicalAddress);
NTSTATUS
MmWritePageSectionView(PMADDRESS_SPACE AddressSpace,
PMEMORY_AREA MArea,
PVOID Address);
NTSTATUS
MmWritePageVirtualMemory(PMADDRESS_SPACE AddressSpace,
PMEMORY_AREA MArea,
PVOID Address);
PVOID
MmGetDirtyPagesFromWorkingSet(struct _EPROCESS* Process);
NTSTATUS
MmWriteToSwapPage(SWAPENTRY SwapEntry, PMDL Mdl);
NTSTATUS
MmReadFromSwapPage(SWAPENTRY SwapEntry, PMDL Mdl);
VOID
MmSetFlagsPage(PVOID PhysicalAddress, ULONG Flags);
ULONG
MmGetFlagsPage(PVOID PhysicalAddress);
VOID MmSetSavedSwapEntryPage(PVOID PhysicalAddress,
SWAPENTRY SavedSwapEntry);
SWAPENTRY MmGetSavedSwapEntryPage(PVOID PhysicalAddress);
@ -375,4 +382,33 @@ MmGetReferenceCountPage(PVOID PhysicalAddress);
BOOLEAN
MmIsUsablePage(PVOID PhysicalAddress);
typedef struct _MM_PAGEOP
{
/* Type of operation. */
ULONG OpType;
/* Number of threads interested in this operation. */
ULONG ReferenceCount;
/* Event that will be set when the operation is completed. */
KEVENT CompletionEvent;
/* Status of the operation once it is completed. */
NTSTATUS Status;
/* TRUE if the operation was abandoned. */
BOOLEAN Abandoned;
/* The memory area to be affected by the operation. */
PMEMORY_AREA MArea;
struct _MM_PAGEOP* Next;
/*
* These fields are used to identify the operation if it is against a
* virtual memory area.
*/
ULONG Pid;
PVOID Address;
/*
* These fields are used to identify the operation if it is against a
* section mapping.
*/
PMM_SECTION_SEGMENT Segment;
ULONG Offset;
} MM_PAGEOP, *PMM_PAGEOP;
#endif

219
reactos/ntoskrnl/kd/dlog.c Normal file
View file

@ -0,0 +1,219 @@
/* $Id: dlog.c,v 1.1 2001/02/16 18:32:20 dwelch Exp $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/kd/kdebug.c
* PURPOSE: Kernel debugger
* PROGRAMMER: Eric Kohl (ekohl@abo.rhein-zeitung.de)
* UPDATE HISTORY:
* 21/10/99: Created
*/
/* INCLUDES ******************************************************************/
#include <ddk/ntddk.h>
#include <internal/ntoskrnl.h>
#include <internal/kd.h>
#include <ntos/minmax.h>
/* GLOBALS *******************************************************************/
#define DEBUGLOG_SIZE (32*1024)
#ifdef DBGPRINT_FILE_LOG
static CHAR DebugLog[DEBUGLOG_SIZE];
static ULONG DebugLogStart;
static ULONG DebugLogEnd;
static KSPIN_LOCK DebugLogLock;
static ULONG DebugLogOverflow;
static HANDLE DebugLogThreadHandle;
static CLIENT_ID DebugLogThreadCid;
static HANDLE DebugLogFile;
static KSEMAPHORE DebugLogSem;
#endif /* DBGPRINT_FILE_LOG */
/* FUNCTIONS *****************************************************************/
#ifdef DBGPRINT_FILE_LOG
VOID
DebugLogInit(VOID)
{
KeInitializeSpinLock(&DebugLogLock);
DebugLogStart = -1;
DebugLogEnd = 0;
DebugLogOverflow = 0;
KeInitializeSemaphore(&DebugLogSem, 0, 255);
}
NTSTATUS
DebugLogThreadMain(PVOID Context)
{
KIRQL oldIrql;
IO_STATUS_BLOCK Iosb;
CHAR Buffer[256];
ULONG WLen;
for (;;)
{
KeWaitForSingleObject(&DebugLogSem,
0,
KernelMode,
FALSE,
NULL);
KeAcquireSpinLock(&DebugLogLock, &oldIrql);
while (DebugLogStart != -1)
{
if (DebugLogStart > DebugLogEnd)
{
WLen = min(256, DEBUGLOG_SIZE - DebugLogStart);
memcpy(Buffer, &DebugLog[DebugLogStart], WLen);
DebugLogStart =
(DebugLogStart + WLen) % DEBUGLOG_SIZE;
if (DebugLogStart == DebugLogEnd)
{
DebugLogStart = -1;
}
KeReleaseSpinLock(&DebugLogLock, oldIrql);
NtWriteFile(DebugLogFile,
NULL,
NULL,
NULL,
&Iosb,
Buffer,
WLen,
NULL,
NULL);
}
else
{
WLen = min(256, DebugLogEnd - DebugLogStart);
memcpy(Buffer, &DebugLog[DebugLogStart], WLen);
DebugLogStart =
(DebugLogStart + WLen) % DEBUGLOG_SIZE;
if (DebugLogStart == DebugLogEnd)
{
DebugLogStart = -1;
}
KeReleaseSpinLock(&DebugLogLock, oldIrql);
NtWriteFile(DebugLogFile,
NULL,
NULL,
NULL,
&Iosb,
Buffer,
WLen,
NULL,
NULL);
}
KeAcquireSpinLock(&DebugLogLock, &oldIrql);
}
KeReleaseSpinLock(&DebugLogLock, oldIrql);
}
}
VOID
DebugLogInit2(VOID)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING FileName;
IO_STATUS_BLOCK Iosb;
RtlInitUnicodeString(&FileName, L"\\SystemRoot\\debug.log");
InitializeObjectAttributes(&ObjectAttributes,
&FileName,
0,
NULL,
NULL);
Status = NtCreateFile(&DebugLogFile,
FILE_ALL_ACCESS,
&ObjectAttributes,
&Iosb,
NULL,
FILE_ATTRIBUTE_NORMAL,
0,
FILE_SUPERSEDE,
FILE_WRITE_THROUGH | FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
if (!NT_SUCCESS(Status))
{
DbgPrint("Failed to create debug log file\n");
return;
}
Status = PsCreateSystemThread(&DebugLogThreadHandle,
THREAD_ALL_ACCESS,
NULL,
NULL,
&DebugLogThreadCid,
DebugLogThreadMain,
NULL);
}
VOID
DebugLogWrite(PCH String)
{
KIRQL oldIrql;
if (KeGetCurrentIrql() > DISPATCH_LEVEL)
{
DebugLogOverflow++;
return;
}
KeAcquireSpinLock(&DebugLogLock, &oldIrql);
if (DebugLogEnd == DebugLogStart)
{
DebugLogOverflow++;
KeReleaseSpinLock(&DebugLogLock, oldIrql);
KeReleaseSemaphore(&DebugLogSem, IO_NO_INCREMENT, 1, FALSE);
return;
}
if (DebugLogStart == -1)
{
DebugLogStart = DebugLogEnd;
}
while ((*String) != 0)
{
DebugLog[DebugLogEnd] = *String;
String++;
if (((DebugLogEnd + 1) % DEBUGLOG_SIZE) == DebugLogStart)
{
DebugLogOverflow++;
KeReleaseSpinLock(&DebugLogLock, oldIrql);
KeReleaseSemaphore(&DebugLogSem, IO_NO_INCREMENT, 1, FALSE);
return;
}
DebugLogEnd = (DebugLogEnd + 1) % DEBUGLOG_SIZE;
}
KeReleaseSpinLock(&DebugLogLock, oldIrql);
KeReleaseSemaphore(&DebugLogSem, IO_NO_INCREMENT, 1, FALSE);
}
#else /* not DBGPRINT_FILE_LOG */
VOID
DebugLogInit(VOID)
{
}
VOID
DebugLogInit2(VOID)
{
}
VOID
DebugLogWrite(PCH String)
{
}
#endif /* DBGPRINT_FILE_LOG */

View file

@ -1,83 +0,0 @@
#include <ddk/ntddk.h>
#include <internal/ntoskrnl.h>
#include <internal/ke.h>
#include <internal/i386/segment.h>
#define _STR(x) #x
#define STR(x) _STR(x)
#define IRQ_HANDLER_FIRST(x,y) \
void irq_handler_##y (void); \
__asm__("\n\t.global _irq_handler_"##x"\n\t_irq_handler_"##x":\n\t" \
"pusha\n\t" \
"pushl %ds\n\t" \
"pushl %es\n\t" \
"pushl %fs\n\t" \
"movl $0xceafbeef,%eax\n\t" \
"pushl %eax\n\t" \
"movw $"STR(KERNEL_DS)",%ax\n\t" \
"movw %ax,%ds\n\t" \
"movw %ax,%es\n\t" \
"inb $0x21,%al\n\t" \
"orb $1<<"##x",%al\n\t" \
"outb %al,$0x21\n\t" \
"pushl %esp\n\t" \
"pushl $"##x"\n\t" \
"call _KiInterruptDispatch\n\t"\
"popl %eax\n\t" \
"popl %eax\n\t" \
"popl %eax\n\t" \
"popl %fs\n\t" \
"popl %es\n\t" \
"popl %ds\n\t" \
"popa\n\t" \
"iret\n\t")
#define IRQ_HANDLER_SECOND(x,y) \
void irq_handler_##y (void); \
__asm__("\n\t.global _irq_handler_"##x"\n\t_irq_handler_"##x":\n\t" \
"pusha\n\t" \
"pushl %ds\n\t" \
"pushl %es\n\t" \
"pushl %fs\n\t" \
"movl $0xceafbeef,%eax\n\t" \
"pushl %eax\n\t" \
"movw $"STR(KERNEL_DS)",%ax\n\t" \
"movw %ax,%ds\n\t" \
"movw %ax,%es\n\t" \
"inb $0xa1,%al\n\t" \
"orb $1<<("##x"-8),%al\n\t" \
"outb %al,$0xa1\n\t" \
"pushl %esp\n\t" \
"pushl $"##x"\n\t" \
"call _KiInterruptDispatch\n\t"\
"popl %eax\n\t" \
"popl %eax\n\t" \
"popl %eax\n\t" \
"popl %fs\n\t" \
"popl %es\n\t" \
"popl %ds\n\t" \
"popa\n\t" \
"iret\n\t")
IRQ_HANDLER_FIRST ("0",0);
IRQ_HANDLER_FIRST ("1",1);
IRQ_HANDLER_FIRST ("2",2);
IRQ_HANDLER_FIRST ("3",3);
IRQ_HANDLER_FIRST ("4",4);
IRQ_HANDLER_FIRST ("5",5);
IRQ_HANDLER_FIRST ("6",6);
IRQ_HANDLER_FIRST ("7",7);
IRQ_HANDLER_SECOND ("8",8);
IRQ_HANDLER_SECOND ("9",9);
IRQ_HANDLER_SECOND ("10",10);
IRQ_HANDLER_SECOND ("11",11);
IRQ_HANDLER_SECOND ("12",12);
IRQ_HANDLER_SECOND ("13",13);
IRQ_HANDLER_SECOND ("14",14);
IRQ_HANDLER_SECOND ("15",15);

View file

@ -0,0 +1,420 @@
#include <internal/i386/segment.h>
.global _irq_handler_0
_irq_handler_0:
pusha
pushl %ds
pushl %es
pushl %fs
movl $0xceafbeef,%eax
pushl %eax
movw $KERNEL_DS,%ax
movw %ax,%ds
movw %ax,%es
inb $0x21,%al
orb $1<<0,%al
outb %al,$0x21
pushl %esp
pushl $0
call _KiInterruptDispatch
popl %eax
popl %eax
popl %eax
popl %fs
popl %es
popl %ds
popa
iret
.global _irq_handler_1
_irq_handler_1:
pusha
pushl %ds
pushl %es
pushl %fs
movl $0xceafbeef,%eax
pushl %eax
movw $KERNEL_DS,%ax
movw %ax,%ds
movw %ax,%es
inb $0x21,%al
orb $1<<1,%al
outb %al,$0x21
pushl %esp
pushl $1
call _KiInterruptDispatch
popl %eax
popl %eax
popl %eax
popl %fs
popl %es
popl %ds
popa
iret
.global _irq_handler_2
_irq_handler_2:
pusha
pushl %ds
pushl %es
pushl %fs
movl $0xceafbeef,%eax
pushl %eax
movw $KERNEL_DS,%ax
movw %ax,%ds
movw %ax,%es
inb $0x21,%al
orb $1<<2,%al
outb %al,$0x21
pushl %esp
pushl $2
call _KiInterruptDispatch
popl %eax
popl %eax
popl %eax
popl %fs
popl %es
popl %ds
popa
iret
.global _irq_handler_3
_irq_handler_3:
pusha
pushl %ds
pushl %es
pushl %fs
movl $0xceafbeef,%eax
pushl %eax
movw $KERNEL_DS,%ax
movw %ax,%ds
movw %ax,%es
inb $0x21,%al
orb $1<<3,%al
outb %al,$0x21
pushl %esp
pushl $3
call _KiInterruptDispatch
popl %eax
popl %eax
popl %eax
popl %fs
popl %es
popl %ds
popa
iret
.global _irq_handler_4
_irq_handler_4:
pusha
pushl %ds
pushl %es
pushl %fs
movl $0xceafbeef,%eax
pushl %eax
movw $KERNEL_DS,%ax
movw %ax,%ds
movw %ax,%es
inb $0x21,%al
orb $1<<4,%al
outb %al,$0x21
pushl %esp
pushl $4
call _KiInterruptDispatch
popl %eax
popl %eax
popl %eax
popl %fs
popl %es
popl %ds
popa
iret
.global _irq_handler_5
_irq_handler_5:
pusha
pushl %ds
pushl %es
pushl %fs
movl $0xceafbeef,%eax
pushl %eax
movw $KERNEL_DS,%ax
movw %ax,%ds
movw %ax,%es
inb $0x21,%al
orb $1<<5,%al
outb %al,$0x21
pushl %esp
pushl $5
call _KiInterruptDispatch
popl %eax
popl %eax
popl %eax
popl %fs
popl %es
popl %ds
popa
iret
.global _irq_handler_6
_irq_handler_6:
pusha
pushl %ds
pushl %es
pushl %fs
movl $0xceafbeef,%eax
pushl %eax
movw $KERNEL_DS,%ax
movw %ax,%ds
movw %ax,%es
inb $0x21,%al
orb $1<<6,%al
outb %al,$0x21
pushl %esp
pushl $6
call _KiInterruptDispatch
popl %eax
popl %eax
popl %eax
popl %fs
popl %es
popl %ds
popa
iret
.global _irq_handler_7
_irq_handler_7:
pusha
pushl %ds
pushl %es
pushl %fs
movl $0xceafbeef,%eax
pushl %eax
movw $KERNEL_DS,%ax
movw %ax,%ds
movw %ax,%es
inb $0x21,%al
orb $1<<7,%al
outb %al,$0x21
pushl %esp
pushl $7
call _KiInterruptDispatch
popl %eax
popl %eax
popl %eax
popl %fs
popl %es
popl %ds
popa
iret
.global _irq_handler_8
_irq_handler_8:
pusha
pushl %ds
pushl %es
pushl %fs
movl $0xceafbeef,%eax
pushl %eax
movw $KERNEL_DS,%ax
movw %ax,%ds
movw %ax,%es
inb $0xa1,%al
orb $1<<(8-8),%al
outb %al,$0xa1
pushl %esp
pushl $8
call _KiInterruptDispatch
popl %eax
popl %eax
popl %eax
popl %fs
popl %es
popl %ds
popa
iret
.global _irq_handler_9
_irq_handler_9:
pusha
pushl %ds
pushl %es
pushl %fs
movl $0xceafbeef,%eax
pushl %eax
movw $KERNEL_DS,%ax
movw %ax,%ds
movw %ax,%es
inb $0xa1,%al
orb $1<<(9-8),%al
outb %al,$0xa1
pushl %esp
pushl $9
call _KiInterruptDispatch
popl %eax
popl %eax
popl %eax
popl %fs
popl %es
popl %ds
popa
iret
.global _irq_handler_10
_irq_handler_10:
pusha
pushl %ds
pushl %es
pushl %fs
movl $0xceafbeef,%eax
pushl %eax
movw $KERNEL_DS,%ax
movw %ax,%ds
movw %ax,%es
inb $0xa1,%al
orb $1<<(10-8),%al
outb %al,$0xa1
pushl %esp
pushl $10
call _KiInterruptDispatch
popl %eax
popl %eax
popl %eax
popl %fs
popl %es
popl %ds
popa
iret
.global _irq_handler_11
_irq_handler_11:
pusha
pushl %ds
pushl %es
pushl %fs
movl $0xceafbeef,%eax
pushl %eax
movw $KERNEL_DS,%ax
movw %ax,%ds
movw %ax,%es
inb $0xa1,%al
orb $1<<(11-8),%al
outb %al,$0xa1
pushl %esp
pushl $11
call _KiInterruptDispatch
popl %eax
popl %eax
popl %eax
popl %fs
popl %es
popl %ds
popa
iret
.global _irq_handler_12
_irq_handler_12:
pusha
pushl %ds
pushl %es
pushl %fs
movl $0xceafbeef,%eax
pushl %eax
movw $KERNEL_DS,%ax
movw %ax,%ds
movw %ax,%es
inb $0xa1,%al
orb $1<<(12-8),%al
outb %al,$0xa1
pushl %esp
pushl $12
call _KiInterruptDispatch
popl %eax
popl %eax
popl %eax
popl %fs
popl %es
popl %ds
popa
iret
.global _irq_handler_13
_irq_handler_13:
pusha
pushl %ds
pushl %es
pushl %fs
movl $0xceafbeef,%eax
pushl %eax
movw $KERNEL_DS,%ax
movw %ax,%ds
movw %ax,%es
inb $0xa1,%al
orb $1<<(13-8),%al
outb %al,$0xa1
pushl %esp
pushl $13
call _KiInterruptDispatch
popl %eax
popl %eax
popl %eax
popl %fs
popl %es
popl %ds
popa
iret
.global _irq_handler_14
_irq_handler_14:
pusha
pushl %ds
pushl %es
pushl %fs
movl $0xceafbeef,%eax
pushl %eax
movw $KERNEL_DS,%ax
movw %ax,%ds
movw %ax,%es
inb $0xa1,%al
orb $1<<(14-8),%al
outb %al,$0xa1
pushl %esp
pushl $14
call _KiInterruptDispatch
popl %eax
popl %eax
popl %eax
popl %fs
popl %es
popl %ds
popa
iret
.global _irq_handler_15
_irq_handler_15:
pusha
pushl %ds
pushl %es
pushl %fs
movl $0xceafbeef,%eax
pushl %eax
movw $KERNEL_DS,%ax
movw %ax,%ds
movw %ax,%es
inb $0xa1,%al
orb $1<<(15-8),%al
outb %al,$0xa1
pushl %esp
pushl $15
call _KiInterruptDispatch
popl %eax
popl %eax
popl %eax
popl %fs
popl %es
popl %ds
popa
iret

View file

@ -0,0 +1,164 @@
/* $Id: pageop.c,v 1.1 2001/02/16 18:32:20 dwelch Exp $
*
* 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 ****************************************************************/
#include <ddk/ntddk.h>
#include <internal/ps.h>
#include <internal/mm.h>
#include <internal/mmhal.h>
#define NDEBUG
#include <internal/debug.h>
/* GLOBALS *******************************************************************/
#define PAGEOP_HASH_TABLE_SIZE (32)
KSPIN_LOCK MmPageOpHashTableLock;
PMM_PAGEOP MmPageOpHashTable[PAGEOP_HASH_TABLE_SIZE];
/* FUNCTIONS *****************************************************************/
VOID
MmReleasePageOp(PMM_PAGEOP PageOp)
{
ULONG h;
KIRQL oldIrql;
PMM_PAGEOP PPageOp;
PageOp->ReferenceCount--;
if (PageOp->ReferenceCount > 0)
{
return;
}
/*
* Calcuate the hash value for pageop structure
*/
if (MArea->Type == MEMORY_AREA_SECTION_VIEW_COMMIT)
{
h = (((ULONG)Segment) | Offset) % PAGEOP_HASH_TABLE_SIZE;
}
else
{
h = (((ULONG)Pid) | (ULONG)Address) % PAGEOP_HASH_TABLE_SIZE;
}
KeAcquireSpinLock(&MmPageOpHashTableLock, &oldIrql);
PPageOp = MmPageOpHashTable[h];
if (PPageOp == PageOp)
{
MmPageOpHashTable[h] = PageOp->Next;
KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
ExFreePool(PageOp);
return;
}
PPageOp = PPageOp->Next;
while (PPageOp != NULL)
{
if (PPageOp == PageOp)
{
PPageOp->Next = PageOp->Next;
KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
ExFreePool(PageOp);
return;
}
PPageOp = PPageOp->Next;
}
KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
KeBugCheck(0);
}
PMM_PAGEOP
MmGetPageOp(PMEMORY_AREA MArea, ULONG Pid, PVOID Address,
PMM_SECTION_SEGMENT Segment, ULONG Offset)
{
ULONG h;
KIRQL oldIrql;
PMM_PAGEOP PageOp;
/*
* Calcuate the hash value for pageop structure
*/
if (MArea->Type == MEMORY_AREA_SECTION_VIEW_COMMIT)
{
h = (((ULONG)Segment) | Offset) % PAGEOP_HASH_TABLE_SIZE;
}
else
{
h = (((ULONG)Pid) | (ULONG)Address) % PAGEOP_HASH_TABLE_SIZE;
}
KeAcquireSpinLock(&MmPageOpHashTableLock, &oldIrql);
/*
* Check for an existing pageop structure
*/
PageOp = MmPageOpHashTable[h];
while (PageOp != NULL)
{
if (MArea->Type == MEMORY_AREA_SECTION_VIEW_COMMIT)
{
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);
}
/*
* Otherwise add a new pageop.
*/
PageOp = ExAllocatePool(NonPagedPool, sizeof(MM_PAGEOP));
if (PageOp == NULL)
{
KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
return(NULL);
}
if (MArea->Type == MEMORY_AREA_SECTION_VIEW_COMMIT)
{
PageOp->Pid = Pid;
PageOp->Address = Address;
}
else
{
PageOp->Segment = Segment;
PageOp->Offset = Offset;
}
PageOp->ReferenceCount = 1;
PageOp->Next = MmPageOpHashTable[h];
MmPageOpHashTable[h] = PageOp;
KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
return(PageOp);
}