- Multiple Virtual Memory API fixes:
authorReactOS Portable Systems Group <ros-arm-bringup@svn.reactos.org>
Thu, 15 Oct 2009 16:50:49 +0000 (16:50 +0000)
committerReactOS Portable Systems Group <ros-arm-bringup@svn.reactos.org>
Thu, 15 Oct 2009 16:50:49 +0000 (16:50 +0000)
  - MiDoMappedcopy: The MDL should have 16 pages total, so MI_MAPPED_COPY_PAGES should be 14, not 16, to account for the MDL page itself, and the extra add-on page.
  - MiDoMappedCopy: Check for working set quota exception.
  - NtRead/WriteVirtualMemory: Do not attempt to do any work if the size is 0.
  - NtRead/WriteVirtualMemory: Do not return SEH status if we fail to write the number of bytes read/written -- return the function status.
  - NtProtectVirtualMemory: Protect the memory while attached to the target process.
  - NtProtectVirtualMemory: Do not return SEH status if we fail to write the number of bytes protected -- return the function status.
  - NtLock/UnlockVirtualMemory: Fix incorrect function definition. The last parameter is a bitfield. The middle two parameters are pointers, not values.
  - VirtualLock/Unlock: Fix calling NtLock/UnlockVirtualMemory with new correct function definitions. Call with MAP_PROCESS.
  - NtLock/UnlockVirtualMemory: Apply SEH. Validate flags. Validate parameters.
  - NtLock/UnlockVirtualMemory: Attach to the process while doing the operation. Reference the process.
  - NtLock/UnlockVirtualMemory: Check for SE_LOCK_MEMORY_PRIVILEGE if MAP_SYSTEM is specified.
  - Move MAP_SYSTEM and MAP_PROCESS from ntifs.h to mmtypes.h in NDK.
  - NtLock/UnlockVirtualMemory: Return success and semi-legitimate return values saying nothing was actually done.
  - NtFlushVirtualMemory: Apply SEH. Validate flags. Validate parameters. Call MmFlushVirtualMemory.
  - NtFlushVirtualMemory: Reference the process.
  - NtFlushVirtualMemory: Return success and semi-legitimate return values indicating nothing was flushed.
  - NtGetWriteWatch: Fix function prototype.
  - NtGet/ResetWriteWatch: Apply SEH instead of hacked parameter checks. Validate parameters.
  - NtGet/ResetWriteWatch: Reference the process.
  - NtGet/ResetWriteWatch: Return semi-legitimate return values indicating nothing was written to.
- These APIs are now owned by ARM3.

svn path=/trunk/; revision=43480

reactos/dll/win32/kernel32/mem/virtual.c
reactos/include/ddk/ntifs.h
reactos/include/ndk/mmfuncs.h
reactos/include/ndk/mmtypes.h
reactos/ntoskrnl/mm/ARM3/virtual.c [new file with mode: 0644]
reactos/ntoskrnl/mm/virtual.c
reactos/ntoskrnl/ntoskrnl-generic.rbuild

index f7a1e02..5ccc3df 100644 (file)
@@ -170,14 +170,15 @@ NTAPI
 VirtualLock(IN LPVOID lpAddress,
             IN SIZE_T dwSize)
 {
-    ULONG BytesLocked;
     NTSTATUS Status;
+    ULONG RegionSize = dwSize;
+    PVOID BaseAddress = lpAddress;
 
     /* Lock the memory */
     Status = NtLockVirtualMemory(NtCurrentProcess(),
-                                 lpAddress,
-                                 dwSize,
-                                 &BytesLocked);
+                                 &BaseAddress,
+                                 &RegionSize,
+                                 MAP_PROCESS);
     if (!NT_SUCCESS(Status))
     {
         /* We failed */
@@ -244,14 +245,15 @@ NTAPI
 VirtualUnlock(IN LPVOID lpAddress,
               IN SIZE_T dwSize)
 {
-    ULONG BytesLocked;
     NTSTATUS Status;
-
-    /* Unlock the memory */
+    ULONG RegionSize = dwSize;
+    PVOID BaseAddress = lpAddress;
+    
+    /* Lock the memory */
     Status = NtUnlockVirtualMemory(NtCurrentProcess(),
-                                   lpAddress,
-                                   dwSize,
-                                   &BytesLocked);
+                                   &BaseAddress,
+                                   &RegionSize,
+                                   MAP_PROCESS);
     if (!NT_SUCCESS(Status))
     {
         /* We failed */
index 4a76578..62d2915 100644 (file)
@@ -329,8 +329,6 @@ typedef enum _SECURITY_LOGON_TYPE
 
 #define MAILSLOT_SIZE_AUTO              0
 
-#define MAP_PROCESS                     1L
-#define MAP_SYSTEM                      2L
 #define MEM_DOS_LIM                     0x40000000
 
 #define MCB_FLAG_RAISE_ON_ALLOCATION_FAILURE 1
index a1c7e8b..3034706 100644 (file)
@@ -173,10 +173,10 @@ NTSYSCALLAPI
 NTSTATUS
 NTAPI
 NtLockVirtualMemory(
-    HANDLE ProcessHandle,
-    PVOID BaseAddress,
-    SIZE_T NumberOfBytesToLock,
-    PSIZE_T NumberOfBytesLocked
+    IN HANDLE ProcessHandle,
+    IN OUT PVOID *BaseAddress,
+    IN OUT PSIZE_T NumberOfBytesToLock,
+    IN ULONG MapType
 );
 
 NTSTATUS
@@ -278,9 +278,9 @@ NTSTATUS
 NTAPI
 NtUnlockVirtualMemory(
     IN HANDLE ProcessHandle,
-    IN PVOID BaseAddress,
-    IN SIZE_T  NumberOfBytesToUnlock,
-    OUT PSIZE_T NumberOfBytesUnlocked OPTIONAL
+    IN OUT PVOID *BaseAddress,
+    IN OUT PSIZE_T NumberOfBytesToUnlock,
+    IN ULONG MapType
 );
 
 NTSYSCALLAPI
@@ -367,10 +367,10 @@ NTSYSAPI
 NTSTATUS
 NTAPI
 ZwLockVirtualMemory(
-    HANDLE ProcessHandle,
-    PVOID BaseAddress,
-    SIZE_T NumberOfBytesToLock,
-    PSIZE_T NumberOfBytesLocked
+    IN HANDLE ProcessHandle,
+    IN OUT PVOID *BaseAddress,
+    IN OUT PSIZE_T NumberOfBytesToLock,
+    IN ULONG MapType
 );
 
 NTSYSAPI
@@ -448,9 +448,9 @@ NTSTATUS
 NTAPI
 ZwUnlockVirtualMemory(
     IN HANDLE ProcessHandle,
-    IN PVOID BaseAddress,
-    IN SIZE_T  NumberOfBytesToUnlock,
-    OUT PSIZE_T NumberOfBytesUnlocked OPTIONAL
+    IN OUT PVOID *BaseAddress,
+    IN OUT PSIZE_T NumberOfBytesToUnlock,
+    IN ULONG MapType
 );
 
 NTSYSAPI
index fcc8faa..05f4cbe 100644 (file)
@@ -57,6 +57,12 @@ Author:
 #define MMPFNUSE_DRIVERLOCKPAGE                             10
 #define MMPFNUSE_KERNELSTACK                                11
 
+//
+// Lock/Unlock Virtuam Memory Flags
+//
+#define MAP_PROCESS                                         1
+#define MAP_SYSTEM                                          2
+
 #ifndef NTOS_MODE_USER
 
 //
diff --git a/reactos/ntoskrnl/mm/ARM3/virtual.c b/reactos/ntoskrnl/mm/ARM3/virtual.c
new file mode 100644 (file)
index 0000000..d10bf87
--- /dev/null
@@ -0,0 +1,1757 @@
+/*
+ * PROJECT:         ReactOS Kernel
+ * LICENSE:         BSD - See COPYING.ARM in the top level directory
+ * FILE:            ntoskrnl/mm/ARM3/virtual.c
+ * PURPOSE:         ARM Memory Manager Virtual Memory Management
+ * PROGRAMMERS:     ReactOS Portable Systems Group
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include <ntoskrnl.h>
+#define NDEBUG
+#include <debug.h>
+
+#line 15 "ARMĀ³::VIRTUAL"
+#define MODULE_INVOLVED_IN_ARM3
+#include "../ARM3/miarm.h"
+
+#define MI_MAPPED_COPY_PAGES  14
+#define MI_POOL_COPY_BYTES    512
+#define MI_MAX_TRANSFER_SIZE  64 * 1024
+
+NTSTATUS NTAPI
+MiProtectVirtualMemory(IN PEPROCESS Process,
+                       IN OUT PVOID *BaseAddress,
+                       IN OUT PSIZE_T NumberOfBytesToProtect,
+                       IN ULONG NewAccessProtection,
+                       OUT PULONG OldAccessProtection  OPTIONAL);
+
+/* PRIVATE FUNCTIONS **********************************************************/
+
+LONG
+MiGetExceptionInfo(IN PEXCEPTION_POINTERS ExceptionInfo,
+                   OUT PBOOLEAN HaveBadAddress, 
+                   OUT PULONG_PTR BadAddress)
+{
+    PEXCEPTION_RECORD ExceptionRecord;
+    PAGED_CODE();
+
+    //
+    // Assume default
+    //
+    *HaveBadAddress = FALSE;
+
+    //
+    // Get the exception record
+    //
+    ExceptionRecord = ExceptionInfo->ExceptionRecord;
+
+    //
+    // Look at the exception code
+    //
+    if ((ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION) ||
+        (ExceptionRecord->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION) ||
+        (ExceptionRecord->ExceptionCode == STATUS_IN_PAGE_ERROR))
+    {
+        //
+        // We can tell the address if we have more than one parameter
+        //
+        if (ExceptionRecord->NumberParameters > 1)
+        {
+            //
+            // Return the address
+            //
+            *HaveBadAddress = TRUE;
+            *BadAddress = ExceptionRecord->ExceptionInformation[1];
+        }
+    }
+
+    //
+    // Continue executing the next handler
+    //
+    return EXCEPTION_EXECUTE_HANDLER;
+}
+
+NTSTATUS
+NTAPI
+MiDoMappedCopy(IN PEPROCESS SourceProcess,
+               IN PVOID SourceAddress,
+               IN PEPROCESS TargetProcess,
+               OUT PVOID TargetAddress,
+               IN SIZE_T BufferSize,
+               IN KPROCESSOR_MODE PreviousMode,
+               OUT PSIZE_T ReturnSize)
+{
+    PFN_NUMBER MdlBuffer[(sizeof(MDL) / sizeof(PFN_NUMBER)) + MI_MAPPED_COPY_PAGES + 1];
+    PMDL Mdl = (PMDL)MdlBuffer;
+    SIZE_T TotalSize, CurrentSize, RemainingSize;
+    volatile BOOLEAN FailedInProbe = FALSE, FailedInMapping = FALSE, FailedInMoving;
+    volatile BOOLEAN PagesLocked;
+    PVOID CurrentAddress = SourceAddress, CurrentTargetAddress = TargetAddress;
+    volatile PVOID MdlAddress;
+    KAPC_STATE ApcState;
+    BOOLEAN HaveBadAddress;
+    ULONG_PTR BadAddress;
+    NTSTATUS Status = STATUS_SUCCESS;
+    PAGED_CODE();
+
+    //
+    // Calculate the maximum amount of data to move
+    //
+    TotalSize = MI_MAPPED_COPY_PAGES * PAGE_SIZE;
+    if (BufferSize <= TotalSize) TotalSize = BufferSize;
+    CurrentSize = TotalSize;
+    RemainingSize = BufferSize;
+
+    //
+    // Loop as long as there is still data
+    //
+    while (RemainingSize > 0)
+    {
+        //
+        // Check if this transfer will finish everything off
+        //
+        if (RemainingSize < CurrentSize) CurrentSize = RemainingSize;
+
+        //
+        // Attach to the source address space
+        //
+        KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
+
+        //
+        // Reset state for this pass
+        //
+        MdlAddress = NULL;
+        PagesLocked = FALSE;
+        FailedInMoving = FALSE;
+        ASSERT(FailedInProbe == FALSE);
+
+        //
+        // Protect user-mode copy
+        //
+        _SEH2_TRY
+        {
+            //
+            // If this is our first time, probe the buffer
+            //
+            if ((CurrentAddress == SourceAddress) && (PreviousMode != KernelMode))
+            {
+                //
+                // Catch a failure here
+                //
+                FailedInProbe = TRUE;
+
+                //
+                // Do the probe
+                //
+                ProbeForRead(SourceAddress, BufferSize, sizeof(CHAR));
+
+                //
+                // Passed
+                //
+                FailedInProbe = FALSE;
+            }
+
+            //
+            // Initialize and probe and lock the MDL
+            //
+            MmInitializeMdl(Mdl, CurrentAddress, CurrentSize);
+            MmProbeAndLockPages(Mdl, PreviousMode, IoReadAccess);
+            PagesLocked = TRUE;
+
+            //
+            // Now map the pages
+            //
+            MdlAddress = MmMapLockedPagesSpecifyCache(Mdl,
+                                                      KernelMode,
+                                                      MmCached,
+                                                      NULL,
+                                                      FALSE,
+                                                      HighPagePriority);
+            if (!MdlAddress)
+            {
+                //
+                // Use our SEH handler to pick this up
+                //
+                FailedInMapping = TRUE;
+                ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
+            }
+
+            //
+            // Now let go of the source and grab to the target process
+            //
+            KeUnstackDetachProcess(&ApcState);
+            KeStackAttachProcess(&TargetProcess->Pcb, &ApcState);
+
+            //
+            // Check if this is our first time through
+            //
+            if ((CurrentAddress == SourceAddress) && (PreviousMode != KernelMode))
+            {
+                //
+                // Catch a failure here
+                //
+                FailedInProbe = TRUE;
+
+                //
+                // Do the probe
+                //
+                ProbeForWrite(TargetAddress, BufferSize, sizeof(CHAR));
+
+                //
+                // Passed
+                //
+                FailedInProbe = FALSE;
+            }
+
+            //
+            // Now do the actual move
+            //
+            FailedInMoving = TRUE;
+            RtlCopyMemory(CurrentTargetAddress, MdlAddress, CurrentSize);
+        }
+        _SEH2_EXCEPT(MiGetExceptionInfo(_SEH2_GetExceptionInformation(),
+                                        &HaveBadAddress,
+                                        &BadAddress))
+        {
+            //
+            // Detach from whoever we may be attached to
+            //
+            KeUnstackDetachProcess(&ApcState);
+
+            //
+            // Check if we had mapped the pages
+            //
+            if (MdlAddress) MmUnmapLockedPages(MdlAddress, Mdl);
+
+            //
+            // Check if we had locked the pages
+            //
+            if (PagesLocked) MmUnlockPages(Mdl);
+            
+            //
+            // Check if we hit working set quota
+            //
+            if (_SEH2_GetExceptionCode() == STATUS_WORKING_SET_QUOTA)
+            {
+                //
+                // Return the error
+                //
+                return STATUS_WORKING_SET_QUOTA;
+            }
+
+            //
+            // Check if we failed during the probe or mapping
+            //
+            if ((FailedInProbe) || (FailedInMapping))
+            {
+                //
+                // Exit
+                //
+                Status = _SEH2_GetExceptionCode();
+                _SEH2_YIELD(return Status);
+            }
+
+            //
+            // Otherwise, we failed  probably during the move
+            //
+            *ReturnSize = BufferSize - RemainingSize;
+            if (FailedInMoving)
+            {
+                //
+                // Check if we know exactly where we stopped copying
+                //
+                if (HaveBadAddress)
+                {
+                    //
+                    // Return the exact number of bytes copied
+                    //
+                    *ReturnSize = BadAddress - (ULONG_PTR)SourceAddress;
+                }
+            }
+
+            //
+            // Return partial copy
+            //
+            Status = STATUS_PARTIAL_COPY;
+        }
+        _SEH2_END;
+
+        //
+        // Check for SEH status
+        //
+        if (Status != STATUS_SUCCESS) return Status;
+
+        //
+        // Detach from target
+        //
+        KeUnstackDetachProcess(&ApcState);
+
+        //
+        // Unmap and unlock
+        //
+        MmUnmapLockedPages(MdlAddress, Mdl);
+        MmUnlockPages(Mdl);
+
+        //
+        // Update location and size
+        //
+        RemainingSize -= CurrentSize;
+        CurrentAddress = (PVOID)((ULONG_PTR)CurrentAddress + CurrentSize);
+        CurrentTargetAddress = (PVOID)((ULONG_PTR)CurrentTargetAddress + CurrentSize);
+    }
+
+    //
+    // All bytes read
+    //
+    *ReturnSize = BufferSize;
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+MiDoPoolCopy(IN PEPROCESS SourceProcess,
+             IN PVOID SourceAddress,
+             IN PEPROCESS TargetProcess,
+             OUT PVOID TargetAddress,
+             IN SIZE_T BufferSize,
+             IN KPROCESSOR_MODE PreviousMode,
+             OUT PSIZE_T ReturnSize)
+{
+    UCHAR StackBuffer[MI_POOL_COPY_BYTES];
+    SIZE_T TotalSize, CurrentSize, RemainingSize;
+    volatile BOOLEAN FailedInProbe = FALSE, FailedInMoving, HavePoolAddress = FALSE;
+    PVOID CurrentAddress = SourceAddress, CurrentTargetAddress = TargetAddress;
+    PVOID PoolAddress;
+    KAPC_STATE ApcState;
+    BOOLEAN HaveBadAddress;
+    ULONG_PTR BadAddress;
+    NTSTATUS Status = STATUS_SUCCESS;
+    PAGED_CODE();
+
+    //
+    // Calculate the maximum amount of data to move
+    //
+    TotalSize = MI_MAX_TRANSFER_SIZE;
+    if (BufferSize <= MI_MAX_TRANSFER_SIZE) TotalSize = BufferSize;
+    CurrentSize = TotalSize;
+    RemainingSize = BufferSize;
+
+    //
+    // Check if we can use the stack
+    //
+    if (BufferSize <= MI_POOL_COPY_BYTES)
+    {
+        //
+        // Use it
+        //
+        PoolAddress = (PVOID)StackBuffer;
+    }
+    else
+    {
+        //
+        // Allocate pool
+        //
+        PoolAddress = ExAllocatePoolWithTag(NonPagedPool, TotalSize, 'VmRw');
+        if (!PoolAddress) ASSERT(FALSE);
+        HavePoolAddress = TRUE;
+    }
+
+    //
+    // Loop as long as there is still data
+    //
+    while (RemainingSize > 0)
+    {
+        //
+        // Check if this transfer will finish everything off
+        //
+        if (RemainingSize < CurrentSize) CurrentSize = RemainingSize;
+
+        //
+        // Attach to the source address space
+        //
+        KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
+
+        //
+        // Reset state for this pass
+        //
+        FailedInMoving = FALSE;
+        ASSERT(FailedInProbe == FALSE);
+
+        //
+        // Protect user-mode copy
+        //
+        _SEH2_TRY
+        {
+            //
+            // If this is our first time, probe the buffer
+            //
+            if ((CurrentAddress == SourceAddress) && (PreviousMode != KernelMode))
+            {
+                //
+                // Catch a failure here
+                //
+                FailedInProbe = TRUE;
+
+                //
+                // Do the probe
+                //
+                ProbeForRead(SourceAddress, BufferSize, sizeof(CHAR));
+
+                //
+                // Passed
+                //
+                FailedInProbe = FALSE;
+            }
+
+            //
+            // Do the copy
+            //
+            RtlCopyMemory(PoolAddress, CurrentAddress, CurrentSize);
+
+            //
+            // Now let go of the source and grab to the target process
+            //
+            KeUnstackDetachProcess(&ApcState);
+            KeStackAttachProcess(&TargetProcess->Pcb, &ApcState);
+
+            //
+            // Check if this is our first time through
+            //
+            if ((CurrentAddress == SourceAddress) && (PreviousMode != KernelMode))
+            {
+                //
+                // Catch a failure here
+                //
+                FailedInProbe = TRUE;
+
+                //
+                // Do the probe
+                //
+                ProbeForWrite(TargetAddress, BufferSize, sizeof(CHAR));
+
+                //
+                // Passed
+                //
+                FailedInProbe = FALSE;
+            }
+
+            //
+            // Now do the actual move
+            //
+            FailedInMoving = TRUE;
+            RtlCopyMemory(CurrentTargetAddress, PoolAddress, CurrentSize);
+        }
+        _SEH2_EXCEPT(MiGetExceptionInfo(_SEH2_GetExceptionInformation(),
+                                        &HaveBadAddress,
+                                        &BadAddress))
+        {
+            //
+            // Detach from whoever we may be attached to
+            //
+            KeUnstackDetachProcess(&ApcState);
+
+            //
+            // Check if we had allocated pool
+            //
+            if (HavePoolAddress) ExFreePool(PoolAddress);
+
+            //
+            // Check if we failed during the probe
+            //
+            if (FailedInProbe)
+            {
+                //
+                // Exit
+                //
+                Status = _SEH2_GetExceptionCode();
+                _SEH2_YIELD(return Status);
+            }
+
+            //
+            // Otherwise, we failed, probably during the move
+            //
+            *ReturnSize = BufferSize - RemainingSize;
+            if (FailedInMoving)
+            {
+                //
+                // Check if we know exactly where we stopped copying
+                //
+                if (HaveBadAddress)
+                {
+                    //
+                    // Return the exact number of bytes copied
+                    //
+                    *ReturnSize = BadAddress - (ULONG_PTR)SourceAddress;
+                }
+            }
+
+            //
+            // Return partial copy
+            //
+            Status = STATUS_PARTIAL_COPY;
+        }
+        _SEH2_END;
+
+        //
+        // Check for SEH status
+        //
+        if (Status != STATUS_SUCCESS) return Status;
+
+        //
+        // Detach from target
+        //
+        KeUnstackDetachProcess(&ApcState);
+
+        //
+        // Update location and size
+        //
+        RemainingSize -= CurrentSize;
+        CurrentAddress = (PVOID)((ULONG_PTR)CurrentAddress + CurrentSize);
+        CurrentTargetAddress = (PVOID)((ULONG_PTR)CurrentTargetAddress +
+                                       CurrentSize);
+    }
+
+    //
+    // Check if we had allocated pool
+    //
+    if (HavePoolAddress) ExFreePool(PoolAddress);
+
+    //
+    // All bytes read
+    //
+    *ReturnSize = BufferSize;
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+MmCopyVirtualMemory(IN PEPROCESS SourceProcess,
+                    IN PVOID SourceAddress,
+                    IN PEPROCESS TargetProcess,
+                    OUT PVOID TargetAddress,
+                    IN SIZE_T BufferSize,
+                    IN KPROCESSOR_MODE PreviousMode,
+                    OUT PSIZE_T ReturnSize)
+{
+    NTSTATUS Status;
+    PEPROCESS Process = SourceProcess;
+
+    //
+    // Don't accept zero-sized buffers
+    //
+    if (!BufferSize) return STATUS_SUCCESS;
+
+    //
+    // If we are copying from ourselves, lock the target instead
+    //
+    if (SourceProcess == PsGetCurrentProcess()) Process = TargetProcess;
+
+    //
+    // Acquire rundown protection
+    //
+    if (!ExAcquireRundownProtection(&Process->RundownProtect))
+    {
+        //
+        // Fail
+        //
+        return STATUS_PROCESS_IS_TERMINATING;
+    }
+
+    //
+    // See if we should use the pool copy
+    //
+    if (BufferSize > MI_POOL_COPY_BYTES)
+    {
+        //
+        // Use MDL-copy
+        //
+        Status = MiDoMappedCopy(SourceProcess,
+                                SourceAddress,
+                                TargetProcess,
+                                TargetAddress,
+                                BufferSize,
+                                PreviousMode,
+                                ReturnSize);
+    }
+    else
+    {
+        //
+        // Do pool copy
+        //
+        Status = MiDoPoolCopy(SourceProcess,
+                              SourceAddress,
+                              TargetProcess,
+                              TargetAddress,
+                              BufferSize,
+                              PreviousMode,
+                              ReturnSize);
+    }
+
+    //
+    // Release the lock
+    //
+    ExReleaseRundownProtection(&Process->RundownProtect);
+    return Status;
+}
+                                                               
+NTSTATUS
+NTAPI
+MmFlushVirtualMemory(IN PEPROCESS Process,
+                     IN OUT PVOID *BaseAddress,
+                     IN OUT PSIZE_T RegionSize,
+                     OUT PIO_STATUS_BLOCK IoStatusBlock)
+{
+    PAGED_CODE();
+    UNIMPLEMENTED;
+    
+    //
+    // Fake success
+    //
+    return STATUS_SUCCESS;
+}
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+/*
+ * @unimplemented
+ */
+PVOID
+NTAPI
+MmGetVirtualForPhysical(IN PHYSICAL_ADDRESS PhysicalAddress)
+{
+    UNIMPLEMENTED;
+    return 0;
+}
+
+/*
+ * @unimplemented
+ */
+PVOID
+NTAPI
+MmSecureVirtualMemory(IN PVOID Address,
+                      IN SIZE_T Length,
+                      IN ULONG Mode)
+{
+    UNIMPLEMENTED;
+    return NULL;
+}
+
+/*
+ * @unimplemented
+ */
+VOID
+NTAPI
+MmUnsecureVirtualMemory(IN PVOID SecureMem)
+{
+    UNIMPLEMENTED;
+}
+
+/* SYSTEM CALLS ***************************************************************/
+
+NTSTATUS
+NTAPI
+NtReadVirtualMemory(IN HANDLE ProcessHandle,
+                    IN PVOID BaseAddress,
+                    OUT PVOID Buffer,
+                    IN SIZE_T NumberOfBytesToRead,
+                    OUT PSIZE_T NumberOfBytesRead OPTIONAL)
+{
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    PEPROCESS Process;
+    NTSTATUS Status = STATUS_SUCCESS;
+    SIZE_T BytesRead = 0;
+    PAGED_CODE();
+
+    //
+    // Check if we came from user mode
+    //
+    if (PreviousMode != KernelMode)
+    {
+        //
+        // Validate the read addresses
+        //
+        if ((((ULONG_PTR)BaseAddress + NumberOfBytesToRead) < (ULONG_PTR)BaseAddress) ||
+            (((ULONG_PTR)Buffer + NumberOfBytesToRead) < (ULONG_PTR)Buffer) ||
+            (((ULONG_PTR)BaseAddress + NumberOfBytesToRead) > MmUserProbeAddress) ||
+            (((ULONG_PTR)Buffer + NumberOfBytesToRead) > MmUserProbeAddress))
+        {
+            //
+            // Don't allow to write into kernel space
+            //
+            return STATUS_ACCESS_VIOLATION;
+        }
+
+        //
+        // Enter SEH for probe
+        //
+        _SEH2_TRY
+        {
+            //
+            // Probe the output value
+            //
+            if (NumberOfBytesRead) ProbeForWriteSize_t(NumberOfBytesRead);
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            //
+            // Get exception code
+            //
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
+    }
+    
+    //
+    // Don't do zero-byte transfers
+    //
+    if (NumberOfBytesToRead)
+    {
+        //
+        // Reference the process
+        //
+        Status = ObReferenceObjectByHandle(ProcessHandle,
+                                           PROCESS_VM_READ,
+                                           PsProcessType,
+                                           PreviousMode,
+                                           (PVOID*)(&Process),
+                                           NULL);
+        if (NT_SUCCESS(Status))
+        {
+            //
+            // Do the copy
+            //
+            Status = MmCopyVirtualMemory(Process,
+                                         BaseAddress,
+                                         PsGetCurrentProcess(),
+                                         Buffer,
+                                         NumberOfBytesToRead,
+                                         PreviousMode,
+                                         &BytesRead);
+            
+            //
+            // Dereference the process
+            //
+            ObDereferenceObject(Process);
+        }
+    }
+
+    //
+    // Check if the caller sent this parameter
+    //
+    if (NumberOfBytesRead)
+    {
+        //
+        // Enter SEH to guard write
+        //
+        _SEH2_TRY
+        {
+            //
+            // Return the number of bytes read
+            //
+            *NumberOfBytesRead = BytesRead;
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+        }
+        _SEH2_END;
+    }
+
+    //
+    // Return status
+    //
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+NtWriteVirtualMemory(IN HANDLE ProcessHandle,
+                     IN PVOID BaseAddress,
+                     IN PVOID Buffer,
+                     IN SIZE_T NumberOfBytesToWrite,
+                     OUT PSIZE_T NumberOfBytesWritten OPTIONAL)
+{
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    PEPROCESS Process;
+    NTSTATUS Status = STATUS_SUCCESS;
+    ULONG BytesWritten = 0;
+    PAGED_CODE();
+
+    //
+    // Check if we came from user mode
+    //
+    if (PreviousMode != KernelMode)
+    {
+        //
+        // Validate the read addresses
+        //
+        if ((((ULONG_PTR)BaseAddress + NumberOfBytesToWrite) < (ULONG_PTR)BaseAddress) ||
+            (((ULONG_PTR)Buffer + NumberOfBytesToWrite) < (ULONG_PTR)Buffer) ||
+            (((ULONG_PTR)BaseAddress + NumberOfBytesToWrite) > MmUserProbeAddress) ||
+            (((ULONG_PTR)Buffer + NumberOfBytesToWrite) > MmUserProbeAddress))
+        {
+            //
+            // Don't allow to write into kernel space
+            //
+            return STATUS_ACCESS_VIOLATION;
+        }
+
+        //
+        // Enter SEH for probe
+        //
+        _SEH2_TRY
+        {
+            //
+            // Probe the output value
+            //
+            if (NumberOfBytesWritten) ProbeForWriteSize_t(NumberOfBytesWritten);
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            //
+            // Get exception code
+            //
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
+    }
+
+    //
+    // Don't do zero-byte transfers
+    //
+    if (NumberOfBytesToWrite)
+    {
+        //
+        // Reference the process
+        //
+        Status = ObReferenceObjectByHandle(ProcessHandle,
+                                           PROCESS_VM_WRITE,
+                                           PsProcessType,
+                                           PreviousMode,
+                                           (PVOID*)&Process,
+                                           NULL);
+        if (NT_SUCCESS(Status))
+        {
+            //
+            // Do the copy
+            //
+            Status = MmCopyVirtualMemory(PsGetCurrentProcess(),
+                                         Buffer,
+                                         Process,
+                                         BaseAddress,
+                                         NumberOfBytesToWrite,
+                                         PreviousMode,
+                                         &BytesWritten);
+            
+            //
+            // Dereference the process
+            //
+            ObDereferenceObject(Process);
+        }
+    }
+
+    //
+    // Check if the caller sent this parameter
+    //
+    if (NumberOfBytesWritten)
+    {
+        //
+        // Enter SEH to guard write
+        //
+        _SEH2_TRY
+        {
+            //
+            // Return the number of bytes written
+            //
+            *NumberOfBytesWritten = BytesWritten;
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+        }
+        _SEH2_END;
+    }
+
+    //
+    // Return status
+    //
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+NtProtectVirtualMemory(IN HANDLE ProcessHandle,
+                       IN OUT PVOID *UnsafeBaseAddress,
+                       IN OUT SIZE_T *UnsafeNumberOfBytesToProtect,
+                       IN ULONG NewAccessProtection,
+                       OUT PULONG UnsafeOldAccessProtection)
+{
+    PEPROCESS Process;
+    ULONG OldAccessProtection;
+    ULONG Protection;
+    PEPROCESS CurrentProcess = PsGetCurrentProcess();
+    PVOID BaseAddress = NULL;
+    SIZE_T NumberOfBytesToProtect = 0;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    NTSTATUS Status;
+    BOOLEAN Attached = FALSE;
+    KAPC_STATE ApcState;
+    PAGED_CODE();
+
+    //
+    // Check for valid protection flags
+    //
+    Protection = NewAccessProtection & ~(PAGE_GUARD|PAGE_NOCACHE);
+    if (Protection != PAGE_NOACCESS &&
+        Protection != PAGE_READONLY &&
+        Protection != PAGE_READWRITE &&
+        Protection != PAGE_WRITECOPY &&
+        Protection != PAGE_EXECUTE &&
+        Protection != PAGE_EXECUTE_READ &&
+        Protection != PAGE_EXECUTE_READWRITE &&
+        Protection != PAGE_EXECUTE_WRITECOPY)
+    {
+        //
+        // Fail
+        //
+        return STATUS_INVALID_PAGE_PROTECTION;
+    }
+
+    //
+    // Check if we came from user mode
+    //
+    if (PreviousMode != KernelMode)
+    {
+        //
+        // Enter SEH for probing
+        //
+        _SEH2_TRY
+        {
+            //
+            // Validate all outputs
+            //
+            ProbeForWritePointer(UnsafeBaseAddress);
+            ProbeForWriteSize_t(UnsafeNumberOfBytesToProtect);
+            ProbeForWriteUlong(UnsafeOldAccessProtection);
+
+            //
+            // Capture them
+            //
+            BaseAddress = *UnsafeBaseAddress;
+            NumberOfBytesToProtect = *UnsafeNumberOfBytesToProtect;
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            //
+            // Get exception code
+            //
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
+    }
+    else
+    {
+        //
+        // Capture directly
+        //
+        BaseAddress = *UnsafeBaseAddress;
+        NumberOfBytesToProtect = *UnsafeNumberOfBytesToProtect;
+    }
+
+    //
+    // Catch illegal base address
+    //
+    if (BaseAddress > MM_HIGHEST_USER_ADDRESS) return STATUS_INVALID_PARAMETER_2;
+
+    //
+    // Catch illegal region size
+    //
+    if ((MmUserProbeAddress - (ULONG_PTR)BaseAddress) < NumberOfBytesToProtect)
+    {
+        //
+        // Fail
+        //
+        return STATUS_INVALID_PARAMETER_3;
+    }
+
+    //
+    // 0 is also illegal
+    //
+    if (!NumberOfBytesToProtect) return STATUS_INVALID_PARAMETER_3;
+
+    //
+    // Get a reference to the process
+    //
+    Status = ObReferenceObjectByHandle(ProcessHandle,
+                                       PROCESS_VM_OPERATION,
+                                       PsProcessType,
+                                       PreviousMode,
+                                       (PVOID*)(&Process),
+                                       NULL);
+    if (!NT_SUCCESS(Status)) return Status;
+    
+    //
+    // Check if we should attach
+    //
+    if (CurrentProcess != Process)
+    {
+        //
+        // Do it
+        //
+        KeStackAttachProcess(&Process->Pcb, &ApcState);
+        Attached = TRUE;
+    }
+
+    //
+    // Do the actual work
+    //
+    Status = MiProtectVirtualMemory(Process,
+                                    &BaseAddress,
+                                    &NumberOfBytesToProtect,
+                                    NewAccessProtection,
+                                    &OldAccessProtection);
+    
+    //
+    // Detach if needed
+    //
+    if (Attached) KeUnstackDetachProcess(&ApcState);
+
+    //
+    // Release reference
+    //
+    ObDereferenceObject(Process);
+
+    //
+    // Enter SEH to return data
+    //
+    _SEH2_TRY
+    {
+        //
+        // Return data to user
+        //
+        *UnsafeOldAccessProtection = OldAccessProtection;
+        *UnsafeBaseAddress = BaseAddress;
+        *UnsafeNumberOfBytesToProtect = NumberOfBytesToProtect;
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+    }
+    _SEH2_END;
+
+    //
+    // Return status
+    //
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+NtLockVirtualMemory(IN HANDLE ProcessHandle,
+                    IN OUT PVOID *BaseAddress,
+                    IN OUT PSIZE_T NumberOfBytesToLock,
+                    IN ULONG MapType)
+{
+    PEPROCESS Process;
+    PEPROCESS CurrentProcess = PsGetCurrentProcess();
+    NTSTATUS Status;
+    BOOLEAN Attached = FALSE;
+    KAPC_STATE ApcState;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    PVOID CapturedBaseAddress;
+    SIZE_T CapturedBytesToLock;
+    PAGED_CODE();
+    
+    //
+    // Validate flags
+    //
+    if ((MapType & ~(MAP_PROCESS | MAP_SYSTEM)))
+    {
+        //
+        // Invalid set of flags
+        //
+        return STATUS_INVALID_PARAMETER;
+    }
+    
+    //
+    // At least one flag must be specified
+    //
+    if (!(MapType & (MAP_PROCESS | MAP_SYSTEM)))
+    {
+        //
+        // No flag given
+        //
+        return STATUS_INVALID_PARAMETER;
+    }
+    
+    //
+    // Enter SEH for probing
+    //
+    _SEH2_TRY
+    {
+        //
+        // Validate output data
+        //
+        ProbeForWritePointer(BaseAddress);
+        ProbeForWriteSize_t(NumberOfBytesToLock);
+        
+        //
+        // Capture it
+        //
+        CapturedBaseAddress = *BaseAddress;
+        CapturedBytesToLock = *NumberOfBytesToLock;
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        //
+        // Get exception code
+        //
+        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+    }
+    _SEH2_END;
+    
+    //
+    // Catch illegal base address
+    //
+    if (CapturedBaseAddress > MM_HIGHEST_USER_ADDRESS) return STATUS_INVALID_PARAMETER;
+    
+    //
+    // Catch illegal region size
+    //
+    if ((MmUserProbeAddress - (ULONG_PTR)CapturedBaseAddress) < CapturedBytesToLock)
+    {
+        //
+        // Fail
+        //
+        return STATUS_INVALID_PARAMETER;
+    }
+    
+    //
+    // 0 is also illegal
+    //
+    if (!CapturedBytesToLock) return STATUS_INVALID_PARAMETER;
+    
+    //
+    // Get a reference to the process
+    //
+    Status = ObReferenceObjectByHandle(ProcessHandle,
+                                       PROCESS_VM_OPERATION,
+                                       PsProcessType,
+                                       PreviousMode,
+                                       (PVOID*)(&Process),
+                                       NULL);
+    if (!NT_SUCCESS(Status)) return Status;
+    
+    //
+    // Check if this is is system-mapped
+    //
+    if (MapType & MAP_SYSTEM)
+    {
+        //
+        // Check for required privilege
+        //
+        if (!SeSinglePrivilegeCheck(SeLockMemoryPrivilege, PreviousMode))
+        {
+            //
+            // Fail: Don't have it
+            //
+            ObDereferenceObject(Process);
+            return STATUS_PRIVILEGE_NOT_HELD;
+        }
+    }
+    
+    //
+    // Check if we should attach
+    //
+    if (CurrentProcess != Process)
+    {
+        //
+        // Do it
+        //
+        KeStackAttachProcess(&Process->Pcb, &ApcState);
+        Attached = TRUE;
+    }
+    
+    //
+    // Oops :(
+    //
+    UNIMPLEMENTED;
+    
+    //
+    // Detach if needed
+    //
+    if (Attached) KeUnstackDetachProcess(&ApcState);
+    
+    //
+    // Release reference
+    //
+    ObDereferenceObject(Process);
+    
+    //
+    // Enter SEH to return data
+    //
+    _SEH2_TRY
+    {
+        //
+        // Return data to user
+        //
+        *BaseAddress = CapturedBaseAddress;
+        *NumberOfBytesToLock = 0;
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        //
+        // Get exception code
+        //
+        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+    }
+    _SEH2_END;
+    
+    //
+    // Return status
+    //
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+NtUnlockVirtualMemory(IN HANDLE ProcessHandle,
+                      IN OUT PVOID *BaseAddress,
+                      IN OUT PSIZE_T NumberOfBytesToUnlock,
+                      IN ULONG MapType)
+{
+    PEPROCESS Process;
+    PEPROCESS CurrentProcess = PsGetCurrentProcess();
+    NTSTATUS Status;
+    BOOLEAN Attached = FALSE;
+    KAPC_STATE ApcState;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    PVOID CapturedBaseAddress;
+    SIZE_T CapturedBytesToUnlock;
+    PAGED_CODE();
+    
+    //
+    // Validate flags
+    //
+    if ((MapType & ~(MAP_PROCESS | MAP_SYSTEM)))
+    {
+        //
+        // Invalid set of flags
+        //
+        return STATUS_INVALID_PARAMETER;
+    }
+    
+    //
+    // At least one flag must be specified
+    //
+    if (!(MapType & (MAP_PROCESS | MAP_SYSTEM)))
+    {
+        //
+        // No flag given
+        //
+        return STATUS_INVALID_PARAMETER;
+    }
+    
+    //
+    // Enter SEH for probing
+    //
+    _SEH2_TRY
+    {
+        //
+        // Validate output data
+        //
+        ProbeForWritePointer(BaseAddress);
+        ProbeForWriteSize_t(NumberOfBytesToUnlock);
+        
+        //
+        // Capture it
+        //
+        CapturedBaseAddress = *BaseAddress;
+        CapturedBytesToUnlock = *NumberOfBytesToUnlock;
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        //
+        // Get exception code
+        //
+        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+    }
+    _SEH2_END;
+    
+    //
+    // Catch illegal base address
+    //
+    if (CapturedBaseAddress > MM_HIGHEST_USER_ADDRESS) return STATUS_INVALID_PARAMETER;
+    
+    //
+    // Catch illegal region size
+    //
+    if ((MmUserProbeAddress - (ULONG_PTR)CapturedBaseAddress) < CapturedBytesToUnlock)
+    {
+        //
+        // Fail
+        //
+        return STATUS_INVALID_PARAMETER;
+    }
+    
+    //
+    // 0 is also illegal
+    //
+    if (!CapturedBytesToUnlock) return STATUS_INVALID_PARAMETER;
+    
+    //
+    // Get a reference to the process
+    //
+    Status = ObReferenceObjectByHandle(ProcessHandle,
+                                       PROCESS_VM_OPERATION,
+                                       PsProcessType,
+                                       PreviousMode,
+                                       (PVOID*)(&Process),
+                                       NULL);
+    if (!NT_SUCCESS(Status)) return Status;
+    
+    //
+    // Check if this is is system-mapped
+    //
+    if (MapType & MAP_SYSTEM)
+    {
+        //
+        // Check for required privilege
+        //
+        if (!SeSinglePrivilegeCheck(SeLockMemoryPrivilege, PreviousMode))
+        {
+            //
+            // Fail: Don't have it
+            //
+            ObDereferenceObject(Process);
+            return STATUS_PRIVILEGE_NOT_HELD;
+        }
+    }
+    
+    //
+    // Check if we should attach
+    //
+    if (CurrentProcess != Process)
+    {
+        //
+        // Do it
+        //
+        KeStackAttachProcess(&Process->Pcb, &ApcState);
+        Attached = TRUE;
+    }
+    
+    //
+    // Oops :(
+    //
+    UNIMPLEMENTED;
+    
+    //
+    // Detach if needed
+    //
+    if (Attached) KeUnstackDetachProcess(&ApcState);
+    
+    //
+    // Release reference
+    //
+    ObDereferenceObject(Process);
+    
+    //
+    // Enter SEH to return data
+    //
+    _SEH2_TRY
+    {
+        //
+        // Return data to user
+        //
+        *BaseAddress = PAGE_ALIGN(CapturedBaseAddress);
+        *NumberOfBytesToUnlock = 0;
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        //
+        // Get exception code
+        //
+        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+    }
+    _SEH2_END;
+    
+    //
+    // Return status
+    //
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+NtFlushVirtualMemory(IN HANDLE ProcessHandle,
+                     IN OUT PVOID *BaseAddress,
+                     IN OUT PSIZE_T NumberOfBytesToFlush,
+                     OUT PIO_STATUS_BLOCK IoStatusBlock)
+{
+    PEPROCESS Process;
+    NTSTATUS Status;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    PVOID CapturedBaseAddress;
+    SIZE_T CapturedBytesToFlush;
+    IO_STATUS_BLOCK LocalStatusBlock;
+    PAGED_CODE();
+    
+    //
+    // Check if we came from user mode
+    //
+    if (PreviousMode != KernelMode)
+    {
+        //
+        // Enter SEH for probing
+        //
+        _SEH2_TRY
+        {
+            //
+            // Validate all outputs
+            //
+            ProbeForWritePointer(BaseAddress);
+            ProbeForWriteSize_t(NumberOfBytesToFlush);
+            ProbeForWriteIoStatusBlock(IoStatusBlock);
+            
+            //
+            // Capture them
+            //
+            CapturedBaseAddress = *BaseAddress;
+            CapturedBytesToFlush = *NumberOfBytesToFlush;
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            //
+            // Get exception code
+            //
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
+    }
+    else
+    {
+        //
+        // Capture directly
+        //
+        CapturedBaseAddress = *BaseAddress;
+        CapturedBytesToFlush = *NumberOfBytesToFlush;
+    }
+    
+    //
+    // Catch illegal base address
+    //
+    if (CapturedBaseAddress > MM_HIGHEST_USER_ADDRESS) return STATUS_INVALID_PARAMETER;
+    
+    //
+    // Catch illegal region size
+    //
+    if ((MmUserProbeAddress - (ULONG_PTR)CapturedBaseAddress) < CapturedBytesToFlush)
+    {
+        //
+        // Fail
+        //
+        return STATUS_INVALID_PARAMETER;
+    }
+    
+    //
+    // Get a reference to the process
+    //
+    Status = ObReferenceObjectByHandle(ProcessHandle,
+                                       PROCESS_VM_OPERATION,
+                                       PsProcessType,
+                                       PreviousMode,
+                                       (PVOID*)(&Process),
+                                       NULL);
+    if (!NT_SUCCESS(Status)) return Status;
+    
+    //
+    // Do it
+    //
+    Status = MmFlushVirtualMemory(Process,
+                                  &CapturedBaseAddress,
+                                  &CapturedBytesToFlush,
+                                  &LocalStatusBlock);
+    
+    //
+    // Release reference
+    //
+    ObDereferenceObject(Process);
+    
+    //
+    // Enter SEH to return data
+    //
+    _SEH2_TRY
+    {
+        //
+        // Return data to user
+        //
+        *BaseAddress = PAGE_ALIGN(CapturedBaseAddress);
+        *NumberOfBytesToFlush = 0;
+        *IoStatusBlock = LocalStatusBlock;
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+    }
+    _SEH2_END;
+    
+    //
+    // Return status
+    //
+    return Status;
+}
+
+/*
+ * @unimplemented
+ */
+NTSTATUS
+NTAPI
+NtGetWriteWatch(IN HANDLE ProcessHandle,
+                IN ULONG Flags,
+                IN PVOID BaseAddress,
+                IN SIZE_T RegionSize,
+                IN PVOID *UserAddressArray,
+                OUT PULONG_PTR EntriesInUserAddressArray,
+                OUT PULONG Granularity)
+{
+    PEPROCESS Process;
+    NTSTATUS Status;
+    PVOID EndAddress;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    ULONG_PTR CapturedEntryCount;
+    PAGED_CODE();
+    
+    //
+    // Check if we came from user mode
+    //
+    if (PreviousMode != KernelMode)
+    {
+        //
+        // Enter SEH for probing
+        //
+        _SEH2_TRY
+        {
+            //
+            // Catch illegal base address
+            //
+            if (BaseAddress > MM_HIGHEST_USER_ADDRESS) return STATUS_INVALID_PARAMETER_2;
+            
+            //
+            // Catch illegal region size
+            //
+            if ((MmUserProbeAddress - (ULONG_PTR)BaseAddress) < RegionSize)
+            {
+                //
+                // Fail
+                //
+                return STATUS_INVALID_PARAMETER_3;
+            }
+            
+            //
+            // Validate all data
+            //
+            ProbeForWriteSize_t(EntriesInUserAddressArray);
+            ProbeForWriteUlong(Granularity);
+            
+            //
+            // Capture them
+            //
+            CapturedEntryCount = *EntriesInUserAddressArray;
+            
+            //
+            // Must have a count
+            //
+            if (CapturedEntryCount == 0) return STATUS_INVALID_PARAMETER_5;
+            
+            //
+            // Can't be larger than the maximum
+            //
+            if (CapturedEntryCount > (MAXULONG_PTR / sizeof(ULONG_PTR)))
+            {
+                //
+                // Fail
+                //
+                return STATUS_INVALID_PARAMETER_5;
+            }
+            
+            //
+            // Probe the actual array
+            //
+            ProbeForWrite(UserAddressArray,
+                          CapturedEntryCount * sizeof(PVOID),
+                          sizeof(PVOID));
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            //
+            // Get exception code
+            //
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
+    }
+    else
+    {
+        //
+        // Capture directly
+        //
+        CapturedEntryCount = *EntriesInUserAddressArray;
+        ASSERT(CapturedEntryCount != 0);
+    }
+    
+    //
+    // Check if this is a local request
+    //
+    if (ProcessHandle == NtCurrentProcess())
+    {
+        //
+        // No need to reference the process
+        //
+        Process = PsGetCurrentProcess();
+    }
+    else 
+    {
+        //
+        // Reference the target
+        //
+        Status = ObReferenceObjectByHandle(ProcessHandle,
+                                           PROCESS_VM_OPERATION,
+                                           PsProcessType,
+                                           PreviousMode,
+                                           (PVOID *)&Process,
+                                           NULL);
+        if (!NT_SUCCESS(Status)) return Status;
+    }
+    
+    //
+    // Compute the last address and validate it
+    //
+    EndAddress = (PVOID)((ULONG_PTR)BaseAddress + RegionSize - 1);
+    if (BaseAddress > EndAddress)
+    {
+        //
+        // Fail
+        //
+        if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
+        return STATUS_INVALID_PARAMETER_4;
+    }
+    
+    //
+    // Oops :(
+    //
+    UNIMPLEMENTED;
+    
+    //
+    // Dereference if needed
+    //
+    if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
+    
+    //
+    // Enter SEH to return data
+    //
+    _SEH2_TRY
+    {
+        //
+        // Return data to user
+        //
+        *EntriesInUserAddressArray = 0;
+        *Granularity = PAGE_SIZE;
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        //
+        // Get exception code
+        //
+        Status = _SEH2_GetExceptionCode();
+    }
+    _SEH2_END;
+    
+    //
+    // Return success
+    //
+    return STATUS_SUCCESS;
+}
+
+/*
+ * @unimplemented
+ */
+NTSTATUS
+NTAPI
+NtResetWriteWatch(IN HANDLE ProcessHandle,
+                  IN PVOID BaseAddress,
+                  IN SIZE_T RegionSize)
+{
+    PVOID EndAddress;
+    PEPROCESS Process;
+    NTSTATUS Status;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL);
+    
+    //
+    // Catch illegal base address
+    //
+    if (BaseAddress > MM_HIGHEST_USER_ADDRESS) return STATUS_INVALID_PARAMETER_2;
+    
+    //
+    // Catch illegal region size
+    //
+    if ((MmUserProbeAddress - (ULONG_PTR)BaseAddress) < RegionSize)
+    {
+        //
+        // Fail
+        //
+        return STATUS_INVALID_PARAMETER_3;
+    }
+    
+    //
+    // Check if this is a local request
+    //
+    if (ProcessHandle == NtCurrentProcess())
+    {
+        //
+        // No need to reference the process
+        //
+        Process = PsGetCurrentProcess();
+    }
+    else 
+    {
+        //
+        // Reference the target
+        //
+        Status = ObReferenceObjectByHandle(ProcessHandle,
+                                           PROCESS_VM_OPERATION,
+                                           PsProcessType,
+                                           PreviousMode,
+                                           (PVOID *)&Process,
+                                           NULL);
+        if (!NT_SUCCESS(Status)) return Status;
+    }
+    
+    //
+    // Compute the last address and validate it
+    //
+    EndAddress = (PVOID)((ULONG_PTR)BaseAddress + RegionSize - 1);
+    if (BaseAddress > EndAddress)
+    {
+        //
+        // Fail
+        //
+        if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
+        return STATUS_INVALID_PARAMETER_3;
+    }
+    
+    //
+    // Oops :(
+    //
+    UNIMPLEMENTED;
+    
+    //
+    // Dereference if needed
+    //
+    if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
+    
+    //
+    // Return success
+    //
+    return STATUS_SUCCESS;
+}
+
+/* EOF */
index cc94649..8e6e845 100644 (file)
 #define NDEBUG
 #include <debug.h>
 
-#define MI_MAPPED_COPY_PAGES  16
-#define MI_POOL_COPY_BYTES    512
-#define MI_MAX_TRANSFER_SIZE  64 * 1024
-#define TAG_VM 'wRmV'
-
 /* PRIVATE FUNCTIONS **********************************************************/
 
-LONG
-MiGetExceptionInfo(EXCEPTION_POINTERS *ExceptionInfo, BOOLEAN * HaveBadAddress, ULONG_PTR * BadAddress)
-{
-    PEXCEPTION_RECORD ExceptionRecord;
-    PAGED_CODE();
-
-    /* Assume default */
-    *HaveBadAddress = FALSE;
-
-    /* Get the exception record */
-    ExceptionRecord = ExceptionInfo->ExceptionRecord;
-
-    /* Look at the exception code */
-    if ((ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION) ||
-        (ExceptionRecord->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION) ||
-        (ExceptionRecord->ExceptionCode == STATUS_IN_PAGE_ERROR))
-    {
-        /* We can tell the address if we have more than one parameter */
-        if (ExceptionRecord->NumberParameters > 1)
-        {
-            /* Return the address */
-            *HaveBadAddress = TRUE;
-            *BadAddress = ExceptionRecord->ExceptionInformation[1];
-        }
-    }
-
-    /* Continue executing the next handler */
-    return EXCEPTION_EXECUTE_HANDLER;
-}
-
-NTSTATUS
-NTAPI
-MiDoMappedCopy(IN PEPROCESS SourceProcess,
-               IN PVOID SourceAddress,
-               IN PEPROCESS TargetProcess,
-               OUT PVOID TargetAddress,
-               IN SIZE_T BufferSize,
-               IN KPROCESSOR_MODE PreviousMode,
-               OUT PSIZE_T ReturnSize)
-{
-    PFN_NUMBER MdlBuffer[(sizeof(MDL) / sizeof(PFN_NUMBER)) + MI_MAPPED_COPY_PAGES + 1];
-    PMDL Mdl = (PMDL)MdlBuffer;
-    SIZE_T TotalSize, CurrentSize, RemainingSize;
-    volatile BOOLEAN FailedInProbe = FALSE, FailedInMapping = FALSE, FailedInMoving;
-    volatile BOOLEAN PagesLocked;
-    PVOID CurrentAddress = SourceAddress, CurrentTargetAddress = TargetAddress;
-    volatile PVOID MdlAddress;
-    KAPC_STATE ApcState;
-    BOOLEAN HaveBadAddress;
-    ULONG_PTR BadAddress;
-    PAGED_CODE();
-
-    /* Calculate the maximum amount of data to move */
-    TotalSize = (MI_MAPPED_COPY_PAGES - 2) * PAGE_SIZE;
-    if (BufferSize <= TotalSize) TotalSize = BufferSize;
-    CurrentSize = TotalSize;
-    RemainingSize = BufferSize;
-
-    /* Loop as long as there is still data */
-    while (RemainingSize > 0)
-    {
-        /* Check if this transfer will finish everything off */
-        if (RemainingSize < CurrentSize) CurrentSize = RemainingSize;
-
-        /* Attach to the source address space */
-        KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
-
-        /* Reset state for this pass */
-        MdlAddress = NULL;
-        PagesLocked = FALSE;
-        FailedInMoving = FALSE;
-        ASSERT(FailedInProbe == FALSE);
-
-        /* Protect user-mode copy */
-        _SEH2_TRY
-        {
-            /* If this is our first time, probe the buffer */
-            if ((CurrentAddress == SourceAddress) && (PreviousMode != KernelMode))
-            {
-                /* Catch a failure here */
-                FailedInProbe = TRUE;
-
-                /* Do the probe */
-                ProbeForRead(SourceAddress, BufferSize, sizeof(CHAR));
-
-                /* Passed */
-                FailedInProbe = FALSE;
-            }
-
-            /* Initialize and probe and lock the MDL */
-            MmInitializeMdl (Mdl, CurrentAddress, CurrentSize);
-            MmProbeAndLockPages (Mdl, PreviousMode, IoReadAccess);
-            PagesLocked = TRUE;
-
-            /* Now map the pages */
-            MdlAddress = MmMapLockedPagesSpecifyCache(Mdl,
-                                                      KernelMode,
-                                                      MmCached,
-                                                      NULL,
-                                                      FALSE,
-                                                      HighPagePriority);
-            if (!MdlAddress)
-            {
-                /* Use our SEH handler to pick this up */
-                FailedInMapping = TRUE;
-                ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
-            }
-
-            /* Now let go of the source and grab to the target process */
-            KeUnstackDetachProcess(&ApcState);
-            KeStackAttachProcess(&TargetProcess->Pcb, &ApcState);
-
-            /* Check if this is our first time through */
-            if ((CurrentAddress == SourceAddress) && (PreviousMode != KernelMode))
-            {
-                /* Catch a failure here */
-                FailedInProbe = TRUE;
-
-                /* Do the probe */
-                ProbeForWrite(TargetAddress, BufferSize, sizeof(CHAR));
-
-                /* Passed */
-                FailedInProbe = FALSE;
-            }
-
-            /* Now do the actual move */
-            FailedInMoving = TRUE;
-            RtlCopyMemory(CurrentTargetAddress, MdlAddress, CurrentSize);
-        }
-        _SEH2_EXCEPT(MiGetExceptionInfo(_SEH2_GetExceptionInformation(), &HaveBadAddress, &BadAddress))
-        {
-            /* Detach from whoever we may be attached to */
-            KeUnstackDetachProcess(&ApcState);
-
-            /* Check if we had mapped the pages */
-            if (MdlAddress) MmUnmapLockedPages(MdlAddress, Mdl);
-
-            /* Check if we had locked the pages */
-            if (PagesLocked) MmUnlockPages(Mdl);
-
-            /* Check if we failed during the probe or mapping */
-            if ((FailedInProbe) || (FailedInMapping))
-            {
-                /* Exit */
-                _SEH2_YIELD(return _SEH2_GetExceptionCode());
-            }
-
-            /* Otherwise, we failed  probably during the move */
-            *ReturnSize = BufferSize - RemainingSize;
-            if (FailedInMoving)
-            {
-                /* Check if we know exactly where we stopped copying */
-                if (HaveBadAddress)
-                {
-                    /* Return the exact number of bytes copied */
-                    *ReturnSize = BadAddress - (ULONG_PTR)SourceAddress;
-                }
-            }
-
-            /* Return partial copy */
-            _SEH2_YIELD(return STATUS_PARTIAL_COPY);
-        }
-        _SEH2_END;
-
-        /* Detach from target */
-        KeUnstackDetachProcess(&ApcState);
-
-        /* Unmap and unlock */
-        MmUnmapLockedPages(MdlAddress, Mdl);
-        MmUnlockPages(Mdl);
-
-        /* Update location and size */
-        RemainingSize -= CurrentSize;
-        CurrentAddress = (PVOID)((ULONG_PTR)CurrentAddress + CurrentSize);
-        CurrentTargetAddress = (PVOID)((ULONG_PTR)CurrentTargetAddress + CurrentSize);
-    }
-
-    /* All bytes read */
-    *ReturnSize = BufferSize;
-    return STATUS_SUCCESS;
-}
-
-NTSTATUS
-NTAPI
-MiDoPoolCopy(IN PEPROCESS SourceProcess,
-             IN PVOID SourceAddress,
-             IN PEPROCESS TargetProcess,
-             OUT PVOID TargetAddress,
-             IN SIZE_T BufferSize,
-             IN KPROCESSOR_MODE PreviousMode,
-             OUT PSIZE_T ReturnSize)
-{
-    UCHAR StackBuffer[MI_POOL_COPY_BYTES];
-    SIZE_T TotalSize, CurrentSize, RemainingSize;
-    volatile BOOLEAN FailedInProbe = FALSE, FailedInMoving, HavePoolAddress = FALSE;
-    PVOID CurrentAddress = SourceAddress, CurrentTargetAddress = TargetAddress;
-    PVOID PoolAddress;
-    KAPC_STATE ApcState;
-    BOOLEAN HaveBadAddress;
-    ULONG_PTR BadAddress;
-    PAGED_CODE();
-
-    /* Calculate the maximum amount of data to move */
-    TotalSize = MI_MAX_TRANSFER_SIZE;
-    if (BufferSize <= MI_MAX_TRANSFER_SIZE) TotalSize = BufferSize;
-    CurrentSize = TotalSize;
-    RemainingSize = BufferSize;
-
-    /* Check if we can use the stack */
-    if (BufferSize <= MI_POOL_COPY_BYTES)
-    {
-        /* Use it */
-        PoolAddress = (PVOID)StackBuffer;
-    }
-    else
-    {
-        /* Allocate pool */
-        PoolAddress = ExAllocatePoolWithTag(NonPagedPool, TotalSize, TAG_VM);
-        if (!PoolAddress) ASSERT(FALSE);
-        HavePoolAddress = TRUE;
-    }
-
-    /* Loop as long as there is still data */
-    while (RemainingSize > 0)
-    {
-        /* Check if this transfer will finish everything off */
-        if (RemainingSize < CurrentSize) CurrentSize = RemainingSize;
-
-        /* Attach to the source address space */
-        KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
-
-        /* Reset state for this pass */
-        FailedInMoving = FALSE;
-        ASSERT(FailedInProbe == FALSE);
-
-        /* Protect user-mode copy */
-        _SEH2_TRY
-        {
-            /* If this is our first time, probe the buffer */
-            if ((CurrentAddress == SourceAddress) && (PreviousMode != KernelMode))
-            {
-                /* Catch a failure here */
-                FailedInProbe = TRUE;
-
-                /* Do the probe */
-                ProbeForRead(SourceAddress, BufferSize, sizeof(CHAR));
-
-                /* Passed */
-                FailedInProbe = FALSE;
-            }
-
-            /* Do the copy */
-            RtlCopyMemory(PoolAddress, CurrentAddress, CurrentSize);
-
-            /* Now let go of the source and grab to the target process */
-            KeUnstackDetachProcess(&ApcState);
-            KeStackAttachProcess(&TargetProcess->Pcb, &ApcState);
-
-            /* Check if this is our first time through */
-            if ((CurrentAddress == SourceAddress) && (PreviousMode != KernelMode))
-            {
-                /* Catch a failure here */
-                FailedInProbe = TRUE;
-
-                /* Do the probe */
-                ProbeForWrite(TargetAddress, BufferSize, sizeof(CHAR));
-
-                /* Passed */
-                FailedInProbe = FALSE;
-            }
-
-            /* Now do the actual move */
-            FailedInMoving = TRUE;
-            RtlCopyMemory(CurrentTargetAddress, PoolAddress, CurrentSize);
-        }
-        _SEH2_EXCEPT(MiGetExceptionInfo(_SEH2_GetExceptionInformation(), &HaveBadAddress, &BadAddress))
-        {
-            /* Detach from whoever we may be attached to */
-            KeUnstackDetachProcess(&ApcState);
-
-            /* Check if we had allocated pool */
-            if (HavePoolAddress) ExFreePool(PoolAddress);
-
-            /* Check if we failed during the probe */
-            if (FailedInProbe)
-            {
-                /* Exit */
-                _SEH2_YIELD(return _SEH2_GetExceptionCode());
-            }
-
-            /* Otherwise, we failed  probably during the move */
-            *ReturnSize = BufferSize - RemainingSize;
-            if (FailedInMoving)
-            {
-                /* Check if we know exactly where we stopped copying */
-                if (HaveBadAddress)
-                {
-                    /* Return the exact number of bytes copied */
-                    *ReturnSize = BadAddress - (ULONG_PTR)SourceAddress;
-                }
-            }
-
-            /* Return partial copy */
-            _SEH2_YIELD(return STATUS_PARTIAL_COPY);
-        }
-        _SEH2_END;
-
-        /* Detach from target */
-        KeUnstackDetachProcess(&ApcState);
-
-        /* Update location and size */
-        RemainingSize -= CurrentSize;
-        CurrentAddress = (PVOID)((ULONG_PTR)CurrentAddress + CurrentSize);
-        CurrentTargetAddress = (PVOID)((ULONG_PTR)CurrentTargetAddress + CurrentSize);
-    }
-
-    /* Check if we had allocated pool */
-    if (HavePoolAddress) ExFreePool(PoolAddress);
-
-    /* All bytes read */
-    *ReturnSize = BufferSize;
-    return STATUS_SUCCESS;
-}
-
-NTSTATUS
-NTAPI
-MmCopyVirtualMemory(IN PEPROCESS SourceProcess,
-                    IN PVOID SourceAddress,
-                    IN PEPROCESS TargetProcess,
-                    OUT PVOID TargetAddress,
-                    IN SIZE_T BufferSize,
-                    IN KPROCESSOR_MODE PreviousMode,
-                    OUT PSIZE_T ReturnSize)
-{
-    NTSTATUS Status;
-    PEPROCESS Process = SourceProcess;
-
-    /* Don't accept zero-sized buffers */
-    if (!BufferSize) return STATUS_SUCCESS;
-
-    /* If we are copying from ourselves, lock the target instead */
-    if (SourceProcess == PsGetCurrentProcess()) Process = TargetProcess;
-
-    /* Acquire rundown protection */
-    if (!ExAcquireRundownProtection(&Process->RundownProtect))
-    {
-        /* Fail */
-        return STATUS_PROCESS_IS_TERMINATING;
-    }
-
-    /* See if we should use the pool copy */
-    if (BufferSize > MI_POOL_COPY_BYTES)
-    {
-        /* Use MDL-copy */
-        Status = MiDoMappedCopy(SourceProcess,
-                                SourceAddress,
-                                TargetProcess,
-                                TargetAddress,
-                                BufferSize,
-                                PreviousMode,
-                                ReturnSize);
-    }
-    else
-    {
-        /* Do pool copy */
-        Status = MiDoPoolCopy(SourceProcess,
-                              SourceAddress,
-                              TargetProcess,
-                              TargetAddress,
-                              BufferSize,
-                              PreviousMode,
-                              ReturnSize);
-    }
-
-    /* Release the lock */
-    ExReleaseRundownProtection(&Process->RundownProtect);
-    return Status;
-}
-
 NTSTATUS FASTCALL
 MiQueryVirtualMemory(IN HANDLE ProcessHandle,
                      IN PVOID Address,
@@ -721,323 +337,8 @@ MiUnmapLockedPagesInUserSpace(IN PVOID BaseAddress,
                      NULL);    
 }
 
-/* PUBLIC FUNCTIONS ***********************************************************/
-
-/*
- * @unimplemented
- */
-PVOID
-NTAPI
-MmGetVirtualForPhysical(IN PHYSICAL_ADDRESS PhysicalAddress)
-{
-    UNIMPLEMENTED;
-    return 0;
-}
-
-/*
- * @unimplemented
- */
-PVOID
-NTAPI
-MmSecureVirtualMemory(IN PVOID Address,
-                      IN SIZE_T Length,
-                      IN ULONG Mode)
-{
-    UNIMPLEMENTED;
-    return NULL;
-}
-
-/*
- * @unimplemented
- */
-VOID
-NTAPI
-MmUnsecureVirtualMemory(IN PVOID SecureMem)
-{
-    UNIMPLEMENTED;
-}
-
 /* SYSTEM CALLS ***************************************************************/
 
-NTSTATUS
-NTAPI
-NtReadVirtualMemory(IN HANDLE ProcessHandle,
-                    IN PVOID BaseAddress,
-                    OUT PVOID Buffer,
-                    IN SIZE_T NumberOfBytesToRead,
-                    OUT PSIZE_T NumberOfBytesRead OPTIONAL)
-{
-    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
-    PEPROCESS Process;
-    NTSTATUS Status;
-    SIZE_T BytesRead = 0;
-    PAGED_CODE();
-
-    /* Check if we came from user mode */
-    if (PreviousMode != KernelMode)
-    {
-        /* Validate the read addresses */
-        if ((((ULONG_PTR)BaseAddress + NumberOfBytesToRead) < (ULONG_PTR)BaseAddress) ||
-            (((ULONG_PTR)Buffer + NumberOfBytesToRead) < (ULONG_PTR)Buffer) ||
-            (((ULONG_PTR)BaseAddress + NumberOfBytesToRead) > MmUserProbeAddress) ||
-            (((ULONG_PTR)Buffer + NumberOfBytesToRead) > MmUserProbeAddress))
-        {
-            /* Don't allow to write into kernel space */
-            return STATUS_ACCESS_VIOLATION;
-        }
-
-        /* Enter SEH for probe */
-        _SEH2_TRY
-        {
-            /* Probe the output value */
-            if (NumberOfBytesRead) ProbeForWriteSize_t(NumberOfBytesRead);
-        }
-        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-        {
-            /* Return the exception code */
-            _SEH2_YIELD(return _SEH2_GetExceptionCode());
-        }
-        _SEH2_END;
-    }
-
-    /* Reference the process */
-    Status = ObReferenceObjectByHandle(ProcessHandle,
-                                       PROCESS_VM_READ,
-                                       PsProcessType,
-                                       PreviousMode,
-                                       (PVOID*)(&Process),
-                                       NULL);
-    if (NT_SUCCESS(Status))
-    {
-        /* Do the copy */
-        Status = MmCopyVirtualMemory(Process,
-                                     BaseAddress,
-                                     PsGetCurrentProcess(),
-                                     Buffer,
-                                     NumberOfBytesToRead,
-                                     PreviousMode,
-                                     &BytesRead);
-
-        /* Dereference the process */
-        ObDereferenceObject(Process);
-    }
-
-    /* Check if the caller sent this parameter */
-    if (NumberOfBytesRead)
-    {
-        /* Enter SEH to guard write */
-        _SEH2_TRY
-        {
-            /* Return the number of bytes read */
-            *NumberOfBytesRead = BytesRead;
-        }
-        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-        {
-            /* Handle exception */
-            Status = _SEH2_GetExceptionCode();
-        }
-        _SEH2_END;
-    }
-
-    /* Return status */
-    return Status;
-}
-
-NTSTATUS
-NTAPI
-NtWriteVirtualMemory(IN HANDLE ProcessHandle,
-                     IN PVOID BaseAddress,
-                     IN PVOID Buffer,
-                     IN SIZE_T NumberOfBytesToWrite,
-                     OUT PSIZE_T NumberOfBytesWritten OPTIONAL)
-{
-    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
-    PEPROCESS Process;
-    NTSTATUS Status;
-    ULONG BytesWritten = 0;
-    PAGED_CODE();
-
-    /* Check if we came from user mode */
-    if (PreviousMode != KernelMode)
-    {
-        /* Validate the read addresses */
-        if ((((ULONG_PTR)BaseAddress + NumberOfBytesToWrite) < (ULONG_PTR)BaseAddress) ||
-            (((ULONG_PTR)Buffer + NumberOfBytesToWrite) < (ULONG_PTR)Buffer) ||
-            (((ULONG_PTR)BaseAddress + NumberOfBytesToWrite) > MmUserProbeAddress) ||
-            (((ULONG_PTR)Buffer + NumberOfBytesToWrite) > MmUserProbeAddress))
-        {
-            /* Don't allow to write into kernel space */
-            return STATUS_ACCESS_VIOLATION;
-        }
-
-        /* Enter SEH for probe */
-        _SEH2_TRY
-        {
-            /* Probe the output value */
-            if (NumberOfBytesWritten) ProbeForWriteSize_t(NumberOfBytesWritten);
-        }
-        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-        {
-            /* Return the exception code */
-            _SEH2_YIELD(return _SEH2_GetExceptionCode());
-        }
-        _SEH2_END;
-    }
-
-    /* Reference the process */
-    Status = ObReferenceObjectByHandle(ProcessHandle,
-                                       PROCESS_VM_WRITE,
-                                       PsProcessType,
-                                       PreviousMode,
-                                       (PVOID*)&Process,
-                                       NULL);
-    if (NT_SUCCESS(Status))
-    {
-        /* Do the copy */
-        Status = MmCopyVirtualMemory(PsGetCurrentProcess(),
-                                     Buffer,
-                                     Process,
-                                     BaseAddress,
-                                     NumberOfBytesToWrite,
-                                     PreviousMode,
-                                     &BytesWritten);
-
-        /* Dereference the process */
-        ObDereferenceObject(Process);
-    }
-
-    /* Check if the caller sent this parameter */
-    if (NumberOfBytesWritten)
-    {
-        /* Enter SEH to guard write */
-        _SEH2_TRY
-        {
-            /* Return the number of bytes read */
-            *NumberOfBytesWritten = BytesWritten;
-        }
-        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-        {
-            /* Handle exception */
-            Status = _SEH2_GetExceptionCode();
-        }
-        _SEH2_END;
-    }
-
-    /* Return status */
-    return Status;
-}
-
-NTSTATUS
-NTAPI
-NtProtectVirtualMemory(IN HANDLE ProcessHandle,
-                       IN OUT PVOID *UnsafeBaseAddress,
-                       IN OUT SIZE_T *UnsafeNumberOfBytesToProtect,
-                       IN ULONG NewAccessProtection,
-                       OUT PULONG UnsafeOldAccessProtection)
-{
-    PEPROCESS Process;
-    ULONG OldAccessProtection;
-    ULONG Protection;
-    PVOID BaseAddress = NULL;
-    SIZE_T NumberOfBytesToProtect = 0;
-    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
-    NTSTATUS Status;
-    PAGED_CODE();
-
-    /* Check for valid protection flags */
-    Protection = NewAccessProtection & ~(PAGE_GUARD|PAGE_NOCACHE);
-    if (Protection != PAGE_NOACCESS &&
-        Protection != PAGE_READONLY &&
-        Protection != PAGE_READWRITE &&
-        Protection != PAGE_WRITECOPY &&
-        Protection != PAGE_EXECUTE &&
-        Protection != PAGE_EXECUTE_READ &&
-        Protection != PAGE_EXECUTE_READWRITE &&
-        Protection != PAGE_EXECUTE_WRITECOPY)
-    {
-        return STATUS_INVALID_PAGE_PROTECTION;
-    }
-
-    /* Check if we came from user mode */
-    if (PreviousMode != KernelMode)
-    {
-        /* Enter SEH for probing */
-        _SEH2_TRY
-        {
-            /* Validate all outputs */
-            ProbeForWritePointer(UnsafeBaseAddress);
-            ProbeForWriteSize_t(UnsafeNumberOfBytesToProtect);
-            ProbeForWriteUlong(UnsafeOldAccessProtection);
-
-            /* Capture them */
-            BaseAddress = *UnsafeBaseAddress;
-            NumberOfBytesToProtect = *UnsafeNumberOfBytesToProtect;
-        }
-        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-        {
-            /* Return the exception code */
-            _SEH2_YIELD(return _SEH2_GetExceptionCode());
-        }
-        _SEH2_END;
-    }
-    else
-    {
-        /* Capture directly */
-        BaseAddress = *UnsafeBaseAddress;
-        NumberOfBytesToProtect = *UnsafeNumberOfBytesToProtect;
-    }
-
-    /* Catch illegal base address */
-    if (BaseAddress > (PVOID)MmUserProbeAddress) return STATUS_INVALID_PARAMETER_2;
-
-    /* Catch illegal region size  */
-    if ((MmUserProbeAddress - (ULONG_PTR)BaseAddress) < NumberOfBytesToProtect)
-    {
-        /* Fail */
-        return STATUS_INVALID_PARAMETER_3;
-    }
-
-    /* 0 is also illegal */
-    if (!NumberOfBytesToProtect) return STATUS_INVALID_PARAMETER_3;
-
-    /* Get a reference to the process */
-    Status = ObReferenceObjectByHandle(ProcessHandle,
-                                       PROCESS_VM_OPERATION,
-                                       PsProcessType,
-                                       PreviousMode,
-                                       (PVOID*)(&Process),
-                                       NULL);
-    if (!NT_SUCCESS(Status)) return Status;
-
-    /* Do the actual work */
-    Status = MiProtectVirtualMemory(Process,
-                                    &BaseAddress,
-                                    &NumberOfBytesToProtect,
-                                    NewAccessProtection,
-                                    &OldAccessProtection);
-
-    /* Release reference */
-    ObDereferenceObject(Process);
-
-    /* Enter SEH to return data */
-    _SEH2_TRY
-    {
-        /* Return data to user */
-        *UnsafeOldAccessProtection = OldAccessProtection;
-        *UnsafeBaseAddress = BaseAddress;
-        *UnsafeNumberOfBytesToProtect = NumberOfBytesToProtect;
-    }
-    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-    {
-        /* Catch exception */
-        Status = _SEH2_GetExceptionCode();
-    }
-    _SEH2_END;
-
-    /* Return status */
-    return Status;
-}
-
 NTSTATUS NTAPI
 NtQueryVirtualMemory(IN HANDLE ProcessHandle,
                      IN PVOID Address,
@@ -1202,92 +503,4 @@ NtQueryVirtualMemory(IN HANDLE ProcessHandle,
     return(Status);
 }
 
-NTSTATUS
-NTAPI
-NtLockVirtualMemory(IN HANDLE ProcessHandle,
-                    IN PVOID BaseAddress,
-                    IN SIZE_T NumberOfBytesToLock,
-                    OUT PSIZE_T NumberOfBytesLocked OPTIONAL)
-{
-    UNIMPLEMENTED;
-    if (NumberOfBytesLocked) *NumberOfBytesLocked = 0;
-    return STATUS_SUCCESS;
-}
-
-NTSTATUS
-NTAPI
-NtUnlockVirtualMemory(IN HANDLE ProcessHandle,
-                      IN PVOID BaseAddress,
-                      IN SIZE_T NumberOfBytesToUnlock,
-                      OUT PSIZE_T NumberOfBytesUnlocked OPTIONAL)
-{
-    UNIMPLEMENTED;
-    if (NumberOfBytesUnlocked) *NumberOfBytesUnlocked = 0;
-    return STATUS_SUCCESS;
-}
-
-NTSTATUS
-NTAPI
-NtFlushVirtualMemory(IN HANDLE ProcessHandle,
-                     IN OUT PVOID *BaseAddress,
-                     IN OUT PSIZE_T NumberOfBytesToFlush,
-                     OUT PIO_STATUS_BLOCK IoStatusBlock)
-{
-    UNIMPLEMENTED;
-    return STATUS_SUCCESS;
-}
-
-/*
- * @unimplemented
- */
-NTSTATUS
-NTAPI
-NtGetWriteWatch(IN HANDLE ProcessHandle,
-                IN ULONG Flags,
-                IN PVOID BaseAddress,
-                IN ULONG RegionSize,
-                IN PVOID *UserAddressArray,
-                OUT PULONG EntriesInUserAddressArray,
-                OUT PULONG Granularity)
-{
-    if (!EntriesInUserAddressArray || !Granularity)
-    {
-        return STATUS_ACCESS_VIOLATION;
-    }
-    
-    if (!*EntriesInUserAddressArray || !RegionSize)
-    {
-        return STATUS_INVALID_PARAMETER;
-    }
-    
-    if (!UserAddressArray)
-    {
-        return STATUS_ACCESS_VIOLATION;
-    }
-    
-    /* HACK: Set granularity to PAGE_SIZE */
-    *Granularity = PAGE_SIZE;
-    
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
-}
-
-/*
- * @unimplemented
- */
-NTSTATUS
-NTAPI
-NtResetWriteWatch(IN HANDLE ProcessHandle,
-                  IN PVOID BaseAddress,
-                  IN ULONG RegionSize)
-{
-    if (!RegionSize)
-    {
-        return STATUS_INVALID_PARAMETER;
-    }
-    
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
-}
-
 /* EOF */
index 10c672c..bf90c3b 100644 (file)
                        <file>pool.c</file>
                        <file>procsup.c</file>
                        <file>syspte.c</file>
+                       <file>virtual.c</file>
                </directory>
                <file>anonmem.c</file>
                <file>balance.c</file>