[ros-diffs] [fireball] 33133: - Rewrite NtRead/WriteVirtualMemory around MiCopyVirtualMemory, and use MmMapLockedPagesSpecifyCache to do the bulk of the work, instead of the MDL hacks that were previously used. - Reformat and cleanup the entire file, deprecate NtVirtualLock/Unlock which didn't really work (and aren't really required for any apps for now) - Major perf optimizations to NtRead/VirtualMemory: Use pool memory transfer when more efficient than MDL, and use local stack buffer when size permits. - This patch provides up to 109% improvement (more than twice as fast) in certain virtual memory operations. - Thanks to Alex for researching this issue, and providing the internal information on the various optimizations and behaviors the NT implementation uses.

fireball at svn.reactos.org fireball at svn.reactos.org
Thu Apr 24 23:26:01 CEST 2008


Author: fireball
Date: Thu Apr 24 16:26:01 2008
New Revision: 33133

URL: http://svn.reactos.org/svn/reactos?rev=33133&view=rev
Log:
- Rewrite NtRead/WriteVirtualMemory around MiCopyVirtualMemory, and use MmMapLockedPagesSpecifyCache to do the bulk of the work, instead of the MDL hacks that were previously used.
- Reformat and cleanup the entire file, deprecate NtVirtualLock/Unlock which didn't really work (and aren't really required for any apps for now)
- Major perf optimizations to NtRead/VirtualMemory: Use pool memory transfer when more efficient than MDL, and use local stack buffer when size permits.
- This patch provides up to 109% improvement (more than twice as fast) in certain virtual memory operations.
- Thanks to Alex for researching this issue, and providing the internal information on the various optimizations and behaviors the NT implementation uses.

Modified:
    trunk/reactos/ntoskrnl/ex/exintrin.c
    trunk/reactos/ntoskrnl/mm/virtual.c

Modified: trunk/reactos/ntoskrnl/ex/exintrin.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ex/exintrin.c?rev=33133&r1=33132&r2=33133&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/ex/exintrin.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ex/exintrin.c [iso-8859-1] Thu Apr 24 16:26:01 2008
@@ -25,6 +25,9 @@
 
 /* FUNCTIONS ******************************************************************/
 
+/*
+ * @implemented
+ */
 LONG
 FASTCALL
 InterlockedIncrement(IN LONG volatile *Addend)
@@ -35,6 +38,9 @@
     return _InterlockedIncrement(Addend);    
 }
 
+/*
+ * @implemented
+ */
 LONG
 FASTCALL
 InterlockedDecrement(IN LONG volatile *Addend)
@@ -45,6 +51,9 @@
     return _InterlockedDecrement(Addend);
 }
 
+/*
+ * @implemented
+ */
 LONG
 FASTCALL
 InterlockedCompareExchange(IN OUT LONG volatile *Destination,
@@ -57,6 +66,9 @@
     return _InterlockedCompareExchange(Destination, Exchange, Comperand);
 }
 
+/*
+ * @implemented
+ */
 LONG
 FASTCALL
 InterlockedExchange(IN OUT LONG volatile *Destination,
@@ -68,6 +80,9 @@
     return _InterlockedExchange(Destination, Value);
 }
 
+/*
+ * @implemented
+ */
 LONG
 FASTCALL
 InterlockedExchangeAdd(IN OUT LONG volatile *Addend,
@@ -78,3 +93,89 @@
     //
     return _InterlockedExchangeAdd(Addend, Increment);
 }
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+ProbeForRead(IN CONST VOID *Address,
+             IN ULONG Length,
+             IN ULONG Alignment)
+{
+    PAGED_CODE();
+
+    /* Only probe if we have a valid length */
+    if (Length != 0)
+    {
+        /* Sanity check */
+        ASSERT((Alignment == 1) ||
+               (Alignment == 2) ||
+               (Alignment == 4) ||
+               (Alignment == 8) ||
+               (Alignment == 16));
+
+        /* Check for correct alignment */
+        if (((ULONG_PTR)Address & (Alignment - 1)) != 0)
+        {
+            /* Incorrect alignment */
+            ExRaiseDatatypeMisalignment();
+        }
+        else if (((ULONG_PTR)Address + Length) < (ULONG_PTR)Address ||
+                 ((ULONG_PTR)Address + Length) > (ULONG_PTR)MmUserProbeAddress)
+        {
+            /* Attempt a read */
+            *(volatile CHAR* const)MmUserProbeAddress = 0;
+        }
+    }
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+ProbeForWrite(IN PVOID Address,
+              IN ULONG Length,
+              IN ULONG Alignment)
+{
+    ULONG_PTR Last, Current = (ULONG_PTR)Address;
+    PAGED_CODE();
+
+    /* Only probe if we have a valid length */
+    if (Length != 0)
+    {
+        /* Sanity check */
+        ASSERT((Alignment == 1) ||
+               (Alignment == 2) ||
+               (Alignment == 4) ||
+               (Alignment == 8) ||
+               (Alignment == 16));
+
+        /* Check the alignment */
+        if ((Current & (Alignment - 1)) != 0)
+        {
+            /* Incorrect alignment */
+            ExRaiseDatatypeMisalignment();
+        }
+
+        /* Get the end address */
+        Last = Current + Length - 1;
+        if ((Last < Current) || (Last >= (ULONG_PTR)MmUserProbeAddress))
+        {
+            /* Raise an access violation */
+            ExRaiseAccessViolation();
+        }
+
+        /* Round down to the last page */
+        Last = PAGE_ROUND_DOWN(Last) + PAGE_SIZE;
+        do
+        {
+            /* Attempt a write */
+            *(volatile CHAR*)Current = *(volatile CHAR*)Current;
+
+            /* Go to the next address */
+            Current = PAGE_ROUND_DOWN(Current) + PAGE_SIZE;
+        } while (Current != Last);
+    }
+}

Modified: trunk/reactos/ntoskrnl/mm/virtual.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/virtual.c?rev=33133&r1=33132&r2=33133&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/mm/virtual.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/virtual.c [iso-8859-1] Thu Apr 24 16:26:01 2008
@@ -7,107 +7,412 @@
  * PROGRAMMERS:     David Welch
  */
 
-/* INCLUDE *****************************************************************/
+/* INCLUDE ********************************************************************/
 
 #include <ntoskrnl.h>
-
 #define NDEBUG
-#include <internal/debug.h>
-
-/* FUNCTIONS *****************************************************************/
-
-NTSTATUS STDCALL
-NtFlushVirtualMemory(IN HANDLE ProcessHandle,
-                     IN OUT PVOID *BaseAddress,
-                     IN OUT PSIZE_T NumberOfBytesToFlush,
-                     OUT PIO_STATUS_BLOCK IoStatusBlock)
-/*
- * FUNCTION: Flushes virtual memory to file
- * ARGUMENTS:
- *        ProcessHandle = Points to the process that allocated the virtual
- *                        memory
- *        BaseAddress = Points to the memory address
- *        NumberOfBytesToFlush = Limits the range to flush,
- *        NumberOfBytesFlushed = Actual number of bytes flushed
- * RETURNS: Status
- */
-{
-    /* This should be implemented once we support network filesystems */
-    DPRINT("NtFlushVirtualMemory is UNIMPLEMENTED\n");
-    return(STATUS_SUCCESS);
-}
-
-
-NTSTATUS STDCALL
-MiLockVirtualMemory(HANDLE ProcessHandle,
-                    PVOID BaseAddress,
-                    ULONG NumberOfBytesToLock,
-                    PULONG NumberOfBytesLocked,
-                    PObReferenceObjectByHandle pObReferenceObjectByHandle,
-                    PMmCreateMdl pMmCreateMdl,
-                    PObDereferenceObject pObDereferenceObject,
-                    PMmProbeAndLockPages pMmProbeAndLockPages,
-                    PExFreePool pExFreePool)
-{
-    PEPROCESS Process;
+#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 TAG('V', 'm', 'R', 'w')
+
+/* PRIVATE FUNCTIONS **********************************************************/
+
+_SEH_DEFINE_LOCALS(MiGetExceptionInfo)
+{
+    volatile BOOLEAN HaveBadAddress;
+    volatile ULONG_PTR BadAddress;
+};
+
+_SEH_FILTER(MiGetExceptionInfo)
+{
+    _SEH_ACCESS_LOCALS(MiGetExceptionInfo);
+    EXCEPTION_POINTERS *ExceptionInfo = _SEH_GetExceptionPointers();
+    PEXCEPTION_RECORD ExceptionRecord;
+    PAGED_CODE();
+    
+    /* Assume default */
+    _SEH_VAR(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 */
+            _SEH_VAR(HaveBadAddress) = TRUE;
+            _SEH_VAR(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 ULONG BufferSize,
+               IN KPROCESSOR_MODE PreviousMode,
+               OUT PULONG ReturnSize)
+{
+    PFN_NUMBER MdlBuffer[(sizeof(MDL) / sizeof(PFN_NUMBER)) + (MI_MAPPED_COPY_PAGES >> PAGE_SHIFT) + 1];
+    PMDL Mdl = (PMDL)MdlBuffer;
+    ULONG TotalSize, CurrentSize, RemainingSize;
+    BOOLEAN FailedInProbe = FALSE, FailedInMapping = FALSE, FailedInMoving;
+    BOOLEAN PagesLocked;
+    PVOID CurrentAddress = SourceAddress, CurrentTargetAddress = TargetAddress;
+    PVOID MdlAddress;
+    KAPC_STATE ApcState;
+    _SEH_DECLARE_LOCALS(MiGetExceptionInfo);
+    NTSTATUS Status = STATUS_SUCCESS;
+    PAGED_CODE();
+    
+    /* Calculate the maximum amount of data to move */
+    TotalSize = MI_MAPPED_COPY_PAGES - 2;
+    if (TotalSize <= (MI_MAPPED_COPY_PAGES - 2)) TotalSize = BufferSize;
+    CurrentSize = BufferSize;
+    RemainingSize = TotalSize;
+    
+    /* 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 */
+        _SEH_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);
+        }
+        _SEH_EXCEPT(MiGetExceptionInfo)
+        {
+            /* 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 */
+                Status = _SEH_GetExceptionCode();
+                _SEH_YIELD();
+            }
+            
+            /* Otherwise, we failed  probably during the move */
+            *ReturnSize = BufferSize - RemainingSize;
+            if (FailedInMoving)
+            {
+                /* Check if we know exactly where we stopped copying */
+                if (_SEH_VAR(HaveBadAddress))
+                {
+                    /* Return the exact number of bytes copied */
+                    *ReturnSize = _SEH_VAR(BadAddress) - (ULONG_PTR)SourceAddress;
+                }
+            }
+            
+            /* Return partial copy */
+            Status = STATUS_PARTIAL_COPY;
+        }
+        _SEH_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 ULONG BufferSize,
+             IN KPROCESSOR_MODE PreviousMode,
+             OUT PULONG ReturnSize)
+{
+    UCHAR StackBuffer[MI_POOL_COPY_BYTES];
+    ULONG TotalSize, CurrentSize, RemainingSize;
+    BOOLEAN FailedInProbe = FALSE, FailedInMoving, HavePoolAddress = FALSE;
+    PVOID CurrentAddress = SourceAddress, CurrentTargetAddress = TargetAddress;
+    PVOID PoolAddress;
+    KAPC_STATE ApcState;
+    _SEH_DECLARE_LOCALS(MiGetExceptionInfo);
+    NTSTATUS Status = STATUS_SUCCESS;
+    PAGED_CODE();
+    
+    /* Calculate the maximum amount of data to move */
+    TotalSize = MI_MAX_TRANSFER_SIZE;
+    if (TotalSize <= MI_MAX_TRANSFER_SIZE) TotalSize = BufferSize;
+    CurrentSize = BufferSize;
+    RemainingSize = TotalSize;
+    
+    /* 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 */
+        _SEH_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);
+        }
+        _SEH_EXCEPT(MiGetExceptionInfo)
+        {
+            /* 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 = _SEH_GetExceptionCode();
+                _SEH_YIELD();
+            }
+            
+            /* Otherwise, we failed  probably during the move */
+            *ReturnSize = BufferSize - RemainingSize;
+            if (FailedInMoving)
+            {
+                /* Check if we know exactly where we stopped copying */
+                if (_SEH_VAR(HaveBadAddress))
+                {
+                    /* Return the exact number of bytes copied */
+                    *ReturnSize = _SEH_VAR(BadAddress) - (ULONG_PTR)SourceAddress;
+                }
+            }
+            
+            /* Return partial copy */
+            Status = STATUS_PARTIAL_COPY;
+        }
+        _SEH_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 ULONG BufferSize,
+                    IN KPROCESSOR_MODE PreviousMode,
+                    OUT PULONG ReturnSize)
+{
     NTSTATUS Status;
-    PMDL Mdl;
-
-    Status = pObReferenceObjectByHandle(ProcessHandle,
-                                        PROCESS_VM_WRITE,
-                                        NULL,
-                                        UserMode,
-                                        (PVOID*)(&Process),
-                                        NULL);
-    if (!NT_SUCCESS(Status))
-        return(Status);
-
-    Mdl = pMmCreateMdl(NULL,
-                       BaseAddress,
-                       NumberOfBytesToLock);
-    if (Mdl == NULL)
-    {
-        pObDereferenceObject(Process);
-        return(STATUS_NO_MEMORY);
-    }
-
-    pMmProbeAndLockPages(Mdl,
-                         UserMode,
-                         IoWriteAccess);
-
-    pExFreePool(Mdl);
-
-    pObDereferenceObject(Process);
-
-    *NumberOfBytesLocked = NumberOfBytesToLock;
-    return(STATUS_SUCCESS);
-}
-
-
-NTSTATUS STDCALL
-NtLockVirtualMemory(HANDLE ProcessHandle,
-                    PVOID BaseAddress,
-                    ULONG NumberOfBytesToLock,
-                    PULONG NumberOfBytesLocked)
-{
-    DPRINT("NtLockVirtualMemory(ProcessHandle %x, BaseAddress %x, "
-        "NumberOfBytesToLock %d, NumberOfBytesLocked %x)\n",
-        ProcessHandle,
-        BaseAddress,
-        NumberOfBytesToLock,
-        NumberOfBytesLocked);
-
-    return MiLockVirtualMemory(ProcessHandle,
-                               BaseAddress,
-                               NumberOfBytesToLock,
-                               NumberOfBytesLocked,
-                               ObReferenceObjectByHandle,
-                               MmCreateMdl,
-                               (PVOID)ObfDereferenceObject,
-                               MmProbeAndLockPages,
-                               ExFreePool);
-}
-
+    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,
@@ -276,11 +581,370 @@
     return Status;
 }
 
-/* (tMk 2004.II.4)
- * FUNCTION:
- * Called from VirtualQueryEx (lib\kernel32\mem\virtual.c)
- *
+NTSTATUS STDCALL
+MiProtectVirtualMemory(IN PEPROCESS Process,
+                       IN OUT PVOID *BaseAddress,
+                       IN OUT PULONG NumberOfBytesToProtect,
+                       IN ULONG NewAccessProtection,
+                       OUT PULONG OldAccessProtection  OPTIONAL)
+{
+    PMEMORY_AREA MemoryArea;
+    PMADDRESS_SPACE AddressSpace;
+    ULONG OldAccessProtection_;
+    NTSTATUS Status;
+    
+    *NumberOfBytesToProtect =
+    PAGE_ROUND_UP((ULONG_PTR)(*BaseAddress) + (*NumberOfBytesToProtect)) -
+    PAGE_ROUND_DOWN(*BaseAddress);
+    *BaseAddress = (PVOID)PAGE_ROUND_DOWN(*BaseAddress);
+    
+    AddressSpace = (PMADDRESS_SPACE)&(Process)->VadRoot;
+    
+    MmLockAddressSpace(AddressSpace);
+    MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, *BaseAddress);
+    if (MemoryArea == NULL)
+    {
+        MmUnlockAddressSpace(AddressSpace);
+        return STATUS_UNSUCCESSFUL;
+    }
+    
+    if (OldAccessProtection == NULL)
+        OldAccessProtection = &OldAccessProtection_;
+    
+    if (MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY)
+    {
+        Status = MmProtectAnonMem(AddressSpace, MemoryArea, *BaseAddress,
+                                  *NumberOfBytesToProtect, NewAccessProtection,
+                                  OldAccessProtection);
+    }
+    else if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW)
+    {
+        Status = MmProtectSectionView(AddressSpace, MemoryArea, *BaseAddress,
+                                      *NumberOfBytesToProtect,
+                                      NewAccessProtection,
+                                      OldAccessProtection);
+    }
+    else
+    {
+        /* FIXME: Should we return failure or success in this case? */
+        Status = STATUS_CONFLICTING_ADDRESSES;
+    }
+    
+    MmUnlockAddressSpace(AddressSpace);
+    
+    return Status;
+}
+
+/* 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 ULONG NumberOfBytesToRead,
+                    OUT PULONG NumberOfBytesRead OPTIONAL)
+{
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    PEPROCESS Process;
+    NTSTATUS Status = STATUS_SUCCESS;
+    ULONG 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 */
+        _SEH_TRY
+        {
+            /* Probe the output value */
+            if (NumberOfBytesRead) ProbeForWriteUlong(NumberOfBytesRead);
+        }
+        _SEH_HANDLE
+        {
+            /* Get exception code */
+            Status = _SEH_GetExceptionCode();
+        }
+        _SEH_END;
+        
+        /* Return if we failed */
+        if (!NT_SUCCESS(Status)) return Status;
+    }
+    
+    /* 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);
+        
+        /* Derefernece the process */
+        ObDereferenceObject(Process);
+    }
+    
+    /* Check if the caller sent this parameter */
+    if (NumberOfBytesRead)
+    {
+        /* Enter SEH to guard write */
+        _SEH_TRY
+        {
+            /* Return the number of bytes read */
+            *NumberOfBytesRead = BytesRead;
+        }
+        _SEH_HANDLE
+        {
+            /* Handle exception */
+            Status = _SEH_GetExceptionCode();
+        }
+        _SEH_END;
+    }
+
+    /* Return status */
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+NtWriteVirtualMemory(IN HANDLE ProcessHandle,
+                     IN PVOID BaseAddress,
+                     IN PVOID Buffer,
+                     IN ULONG NumberOfBytesToWrite,
+                     OUT PULONG 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 */
+        _SEH_TRY
+        {
+            /* Probe the output value */
+            if (NumberOfBytesWritten) ProbeForWriteUlong(NumberOfBytesWritten);
+        }
+        _SEH_HANDLE
+        {
+            /* Get exception code */
+            Status = _SEH_GetExceptionCode();
+        }
+        _SEH_END;
+        
+        /* Return if we failed */
+        if (!NT_SUCCESS(Status)) return Status;
+    }
+    
+    /* 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);
+        
+        /* Derefernece the process */
+        ObDereferenceObject(Process);
+    }
+    
+    /* Check if the caller sent this parameter */
+    if (NumberOfBytesWritten)
+    {
+        /* Enter SEH to guard write */
+        _SEH_TRY
+        {
+            /* Return the number of bytes read */
+            *NumberOfBytesWritten = BytesWritten;
+        }
+        _SEH_HANDLE
+        {
+            /* Handle exception */
+            Status = _SEH_GetExceptionCode();
+        }
+        _SEH_END;
+    }
+    
+    /* Return status */
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+NtProtectVirtualMemory(IN HANDLE ProcessHandle,
+                       IN OUT PVOID *UnsafeBaseAddress,
+                       IN OUT ULONG *UnsafeNumberOfBytesToProtect,
+                       IN ULONG NewAccessProtection,
+                       OUT PULONG UnsafeOldAccessProtection)
+{
+    PEPROCESS Process;
+    ULONG OldAccessProtection;
+    PVOID BaseAddress = NULL;
+    ULONG NumberOfBytesToProtect = 0;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    /* Check if we came from user mode */
+    if (PreviousMode != KernelMode)
+    {
+        /* Enter SEH for probing */
+        _SEH_TRY
+        {
+            /* Validate all outputs */
+            ProbeForWritePointer(UnsafeBaseAddress);
+            ProbeForWriteUlong(UnsafeNumberOfBytesToProtect);
+            ProbeForWriteUlong(UnsafeOldAccessProtection);
+            
+            /* Capture them */
+            BaseAddress = *UnsafeBaseAddress;
+            NumberOfBytesToProtect = *UnsafeNumberOfBytesToProtect;
+        }
+        _SEH_HANDLE
+        {
+            /* Get exception code */
+            Status = _SEH_GetExceptionCode();
+        }
+        _SEH_END;
+        
+        /* Return on exception */
+        if (!NT_SUCCESS(Status)) return Status;
+    }
+    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 */
+    _SEH_TRY
+    {
+        /* Return data to user */
+        *UnsafeOldAccessProtection = OldAccessProtection;
+        *UnsafeBaseAddress = BaseAddress;
+        *UnsafeNumberOfBytesToProtect = NumberOfBytesToProtect;
+    }
+    _SEH_HANDLE
+    {
+        /* Catch exception */
+        Status = _SEH_GetExceptionCode();
+    }
+    _SEH_END;
+
+    /* Return status */
+    return Status;
+}
+
 NTSTATUS STDCALL
 NtQueryVirtualMemory(IN HANDLE ProcessHandle,
                      IN PVOID Address,
@@ -297,15 +961,15 @@
         MEMORY_BASIC_INFORMATION BasicInfo;
     }
     VirtualMemoryInfo;
-
+    
     DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, "
            "VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, "
            "Length %lu ResultLength %x)\n",ProcessHandle,Address,
            VirtualMemoryInformationClass,VirtualMemoryInformation,
            Length,ResultLength);
-
+    
     PreviousMode =  ExGetPreviousMode();
-
+    
     if (PreviousMode != KernelMode && UnsafeResultLength != NULL)
     {
         _SEH_TRY
@@ -317,26 +981,26 @@
             Status = _SEH_GetExceptionCode();
         }
         _SEH_END;
-
+        
         if (!NT_SUCCESS(Status))
         {
             return Status;
         }
     }
-
+    
     if (Address >= MmSystemRangeStart)
     {
         DPRINT1("Invalid parameter\n");
         return STATUS_INVALID_PARAMETER;
     }
-
+    
     Status = MiQueryVirtualMemory(ProcessHandle,
                                   Address,
                                   VirtualMemoryInformationClass,
                                   &VirtualMemoryInfo,
                                   Length,
                                   &ResultLength );
-
+    
     if (NT_SUCCESS(Status))
     {
         if (PreviousMode != KernelMode)
@@ -371,687 +1035,50 @@
                               &VirtualMemoryInfo,
                               ResultLength);
             }
-
+            
             if (UnsafeResultLength != NULL)
             {
                 *UnsafeResultLength = ResultLength;
             }
         }
     }
-
-   return(Status);
-}
-
-
-NTSTATUS STDCALL
-MiProtectVirtualMemory(IN PEPROCESS Process,
-                       IN OUT PVOID *BaseAddress,
-                       IN OUT PULONG NumberOfBytesToProtect,
-                       IN ULONG NewAccessProtection,
-                       OUT PULONG OldAccessProtection  OPTIONAL)
-{
-    PMEMORY_AREA MemoryArea;
-    PMADDRESS_SPACE AddressSpace;
-    ULONG OldAccessProtection_;
-    NTSTATUS Status;
-
-    *NumberOfBytesToProtect =
-        PAGE_ROUND_UP((ULONG_PTR)(*BaseAddress) + (*NumberOfBytesToProtect)) -
-        PAGE_ROUND_DOWN(*BaseAddress);
-    *BaseAddress = (PVOID)PAGE_ROUND_DOWN(*BaseAddress);
-
-    AddressSpace = (PMADDRESS_SPACE)&(Process)->VadRoot;
-
-    MmLockAddressSpace(AddressSpace);
-    MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, *BaseAddress);
-    if (MemoryArea == NULL)
-    {
-        MmUnlockAddressSpace(AddressSpace);
-        return STATUS_UNSUCCESSFUL;
-    }
-
-    if (OldAccessProtection == NULL)
-        OldAccessProtection = &OldAccessProtection_;
-
-    if (MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY)
-    {
-        Status = MmProtectAnonMem(AddressSpace, MemoryArea, *BaseAddress,
-                                  *NumberOfBytesToProtect, NewAccessProtection,
-                                  OldAccessProtection);
-    }
-    else if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW)
-    {
-        Status = MmProtectSectionView(AddressSpace, MemoryArea, *BaseAddress,
-                                      *NumberOfBytesToProtect,
-                                      NewAccessProtection,
-                                      OldAccessProtection);
-    }
-    else
-    {
-        /* FIXME: Should we return failure or success in this case? */
-        Status = STATUS_CONFLICTING_ADDRESSES;
-    }
-
-    MmUnlockAddressSpace(AddressSpace);
-
-    return Status;
-}
-
-
-/* (tMk 2004.II.5)
- * FUNCTION:
- * Called from VirtualProtectEx (lib\kernel32\mem\virtual.c)
- *
- */
-NTSTATUS STDCALL
-NtProtectVirtualMemory(IN HANDLE ProcessHandle,
-                       IN OUT PVOID *UnsafeBaseAddress,
-                       IN OUT ULONG *UnsafeNumberOfBytesToProtect,
-                       IN ULONG NewAccessProtection,
-                       OUT PULONG UnsafeOldAccessProtection)
-{
-    PEPROCESS Process;
-    ULONG OldAccessProtection;
-    PVOID BaseAddress = NULL;
-    ULONG NumberOfBytesToProtect = 0;
-    KPROCESSOR_MODE PreviousMode;
-    NTSTATUS Status = STATUS_SUCCESS;
-
-    PreviousMode = ExGetPreviousMode();
-
-    if (PreviousMode != KernelMode)
-    {
-        _SEH_TRY
-        {
-            ProbeForWritePointer(UnsafeBaseAddress);
-            ProbeForWriteUlong(UnsafeNumberOfBytesToProtect);
-            ProbeForWriteUlong(UnsafeOldAccessProtection);
-
-            BaseAddress = *UnsafeBaseAddress;
-            NumberOfBytesToProtect = *UnsafeNumberOfBytesToProtect;
-        }
-        _SEH_HANDLE
-        {
-            Status = _SEH_GetExceptionCode();
-        }
-        _SEH_END;
-
-        if (!NT_SUCCESS(Status))
-        {
-            return Status;
-        }
-    }
-    else
-    {
-        BaseAddress = *UnsafeBaseAddress;
-        NumberOfBytesToProtect = *UnsafeNumberOfBytesToProtect;
-    }
-
-    if ((ULONG_PTR)BaseAddress + NumberOfBytesToProtect - 1 < (ULONG_PTR)BaseAddress ||
-        (ULONG_PTR)BaseAddress + NumberOfBytesToProtect - 1 >= MmUserProbeAddress)
-    {
-        /* Don't allow to change the protection of a kernel mode address */
-        return STATUS_INVALID_PARAMETER_2;
-    }
-
-    /* (tMk 2004.II.5) in Microsoft SDK I read:
-     * 'if this parameter is NULL or does not point to a valid variable, the function fails'
-     */
-    if(UnsafeOldAccessProtection == NULL)
-    {
-        return(STATUS_INVALID_PARAMETER);
-    }
-
-    Status = ObReferenceObjectByHandle(ProcessHandle,
-                                       PROCESS_VM_OPERATION,
-                                       PsProcessType,
-                                       UserMode,
-                                       (PVOID*)(&Process),
-                                       NULL);
-    if (!NT_SUCCESS(Status))
-    {
-        DPRINT("NtProtectVirtualMemory() = %x\n",Status);
-        return(Status);
-    }
-
-    Status = MiProtectVirtualMemory(Process,
-                                    &BaseAddress,
-                                    &NumberOfBytesToProtect,
-                                    NewAccessProtection,
-                                    &OldAccessProtection);
-
-    ObDereferenceObject(Process);
-
-    if (PreviousMode != KernelMode)
-    {
-        _SEH_TRY
-        {
-            *UnsafeOldAccessProtection = OldAccessProtection;
-            *UnsafeBaseAddress = BaseAddress;
-            *UnsafeNumberOfBytesToProtect = NumberOfBytesToProtect;
-        }
-        _SEH_HANDLE
-        {
-            Status = _SEH_GetExceptionCode();
-        }
-        _SEH_END;
-    }
-    else
-    {
-        *UnsafeOldAccessProtection = OldAccessProtection;
-        *UnsafeBaseAddress = BaseAddress;
-        *UnsafeNumberOfBytesToProtect = NumberOfBytesToProtect;
-    }
-
+    
     return(Status);
 }
 
-
-/* (tMk 2004.II.05)
- * FUNCTION:
- * Called from ReadProcessMemory (lib\kernel32\mem\procmem.c) and KlInitPeb(lib\kernel32\process\create.c)
- *
- * NOTE: This function will be correct if MmProbeAndLockPages() would be fully IMPLEMENTED.
- */
-NTSTATUS STDCALL
-NtReadVirtualMemory(IN HANDLE ProcessHandle,
+NTSTATUS
+NTAPI
+NtLockVirtualMemory(IN HANDLE ProcessHandle,
                     IN PVOID BaseAddress,
-                    OUT PVOID Buffer,
-                    IN ULONG NumberOfBytesToRead,
-                    OUT PULONG NumberOfBytesRead OPTIONAL)
-{
-    PMDL Mdl;
-    PVOID SystemAddress;
-    KPROCESSOR_MODE PreviousMode;
-    PEPROCESS Process, CurrentProcess;
-    NTSTATUS Status = STATUS_SUCCESS;
-
-    PAGED_CODE();
-
-    DPRINT("NtReadVirtualMemory(ProcessHandle %x, BaseAddress %x, "
-           "Buffer %x, NumberOfBytesToRead %d)\n",ProcessHandle,BaseAddress,
-           Buffer,NumberOfBytesToRead);
-
-    if ((ULONG_PTR)BaseAddress + NumberOfBytesToRead - 1 < (ULONG_PTR)BaseAddress ||
-        (ULONG_PTR)BaseAddress + NumberOfBytesToRead - 1 >= MmUserProbeAddress)
-    {
-        /* Don't allow to read from kernel space */
-        return STATUS_ACCESS_VIOLATION;
-    }
-
-    PreviousMode = ExGetPreviousMode();
-
-    if (PreviousMode != KernelMode)
-    {
-        if ((ULONG_PTR)Buffer + NumberOfBytesToRead - 1 < (ULONG_PTR)Buffer ||
-            (ULONG_PTR)Buffer + NumberOfBytesToRead - 1 >= MmUserProbeAddress)
-        {
-            /* Don't allow to write into kernel space */
-            return STATUS_ACCESS_VIOLATION;
-        }
-    }
-
-    Status = ObReferenceObjectByHandle(ProcessHandle,
-                                       PROCESS_VM_READ,
-                                       NULL,
-                                       PreviousMode,
-                                       (PVOID*)(&Process),
-                                       NULL);
-    if (!NT_SUCCESS(Status))
-    {
-        return(Status);
-    }
-
-    CurrentProcess = PsGetCurrentProcess();
-
-    if(PreviousMode != KernelMode)
-    {
-        _SEH_TRY
-        {
-            if(NumberOfBytesRead != NULL)
-            {
-                ProbeForWriteUlong(NumberOfBytesRead);
-            }
-        }
-        _SEH_HANDLE
-        {
-            Status = _SEH_GetExceptionCode();
-        }
-        _SEH_END;
-
-        if(!NT_SUCCESS(Status))
-        {
-            return Status;
-        }
-    }
-
-
-    if (Process == CurrentProcess)
-    {
-        _SEH_TRY
-        {
-            RtlCopyMemory(Buffer, BaseAddress, NumberOfBytesToRead);
-        }
-        _SEH_HANDLE
-        {
-            Status = _SEH_GetExceptionCode();
-        }
-        _SEH_END;
-    }
-    else
-    {
-        Mdl = MmCreateMdl(NULL,
-                          Buffer,
-                          NumberOfBytesToRead);
-        if(Mdl == NULL)
-        {
-            ObDereferenceObject(Process);
-            return(STATUS_NO_MEMORY);
-        }
-
-        _SEH_TRY
-        {
-            MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess);
-        }
-        _SEH_HANDLE
-        {
-            Status = _SEH_GetExceptionCode();
-        }
-        _SEH_END;
-
-        if(NT_SUCCESS(Status))
-        {
-            KeAttachProcess(&Process->Pcb);
-
-            SystemAddress = MmGetSystemAddressForMdl(Mdl);
-
-            Status = STATUS_SUCCESS;
-            _SEH_TRY
-            {
-                Status = STATUS_PARTIAL_COPY;
-                RtlCopyMemory(SystemAddress, BaseAddress, NumberOfBytesToRead);
-                Status = STATUS_SUCCESS;
-            }
-            _SEH_HANDLE
-            {
-                if(Status != STATUS_PARTIAL_COPY)
-                    Status = _SEH_GetExceptionCode();
-            }
-            _SEH_END;
-
-            KeDetachProcess();
-
-            if (Mdl->MappedSystemVa != NULL)
-            {
-                MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
-            }
-            MmUnlockPages(Mdl);
-        }
-        ExFreePool(Mdl);
-    }
-
-    ObDereferenceObject(Process);
-
-    if ((NT_SUCCESS(Status) || Status == STATUS_PARTIAL_COPY) &&
-        NumberOfBytesRead != NULL)
-    {
-        _SEH_TRY
-        {
-            *NumberOfBytesRead = NumberOfBytesToRead;
-        }
-        _SEH_HANDLE
-        {
-            Status = _SEH_GetExceptionCode();
-        }
-        _SEH_END;
-    }
-
-    return(Status);
-}
-
-/* (tMk 2004.II.05)
- * FUNCTION:  THIS function doesn't make a sense...
- * Called from VirtualUnlock (lib\kernel32\mem\virtual.c)
- */
-NTSTATUS STDCALL
-NtUnlockVirtualMemory(HANDLE ProcessHandle,
-                      PVOID BaseAddress,
-                      ULONG NumberOfBytesToUnlock,
-                      PULONG NumberOfBytesUnlocked OPTIONAL)
-{
-    // AG [08-20-03] : I have *no* idea if this is correct, I just used the
-    // other functions as a template and made a few intelligent guesses...
-
-    NTSTATUS Status;
-    PMDL Mdl;
-    PEPROCESS Process;
-
-    DPRINT("NtUnlockVirtualMemory(ProcessHandle %x, BaseAddress %x, "
-           "NumberOfBytesToUnlock %d), NumberOfBytesUnlocked %x\n",ProcessHandle,BaseAddress,
-           NumberOfBytesToUnlock, NumberOfBytesUnlocked);
-
-    Status = ObReferenceObjectByHandle(ProcessHandle,
-                                       PROCESS_VM_WRITE,
-                                       NULL,
-                                       UserMode,
-                                       (PVOID*)(&Process),
-                                       NULL);
-    if (!NT_SUCCESS(Status))
-    {
-        return(Status);
-    }
-
-    Mdl = MmCreateMdl(NULL,
-                      BaseAddress,
-                      NumberOfBytesToUnlock);
-    if(Mdl == NULL)
-    {
-        ObDereferenceObject(Process);
-        return(STATUS_NO_MEMORY);
-    }
-
-    ObDereferenceObject(Process);
-
-    if (Mdl->MappedSystemVa != NULL)
-    {
-        MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
-    }
-    MmUnlockPages(Mdl);
-    ExFreePool(Mdl);
-
-    *NumberOfBytesUnlocked = NumberOfBytesToUnlock;
-
-    return(STATUS_SUCCESS);
-}
-
-
-/* (tMk 2004.II.05)
- * FUNCTION:
- * Called from WriteProcessMemory (lib\kernel32\mem\procmem.c) and KlInitPeb(lib\kernel32\process\create.c)
- *
- * NOTE: This function will be correct if MmProbeAndLockPages() would be fully IMPLEMENTED.
- */
-NTSTATUS STDCALL
-NtWriteVirtualMemory(IN HANDLE ProcessHandle,
-                     IN PVOID BaseAddress,
-                     IN PVOID Buffer,
-                     IN ULONG NumberOfBytesToWrite,
-                     OUT PULONG NumberOfBytesWritten  OPTIONAL)
-{
-    PMDL Mdl;
-    PVOID SystemAddress;
-    PEPROCESS Process;
-    KPROCESSOR_MODE PreviousMode;
-    NTSTATUS CopyStatus, Status = STATUS_SUCCESS;
-
-    DPRINT("NtWriteVirtualMemory(ProcessHandle %x, BaseAddress %x, "
-           "Buffer %x, NumberOfBytesToWrite %d)\n",ProcessHandle,BaseAddress,
-           Buffer,NumberOfBytesToWrite);
-
-    if ((ULONG_PTR)BaseAddress + NumberOfBytesToWrite - 1 < (ULONG_PTR)BaseAddress ||
-        (ULONG_PTR)BaseAddress + NumberOfBytesToWrite - 1 >= MmUserProbeAddress)
-    {
-        /* Don't allow to write into kernel space */
-        return STATUS_ACCESS_VIOLATION;
-    }
-
-    PreviousMode = ExGetPreviousMode();
-
-    if (PreviousMode != KernelMode)
-    {
-        if ((ULONG_PTR)Buffer + NumberOfBytesToWrite - 1 < (ULONG_PTR)Buffer ||
-            (ULONG_PTR)Buffer + NumberOfBytesToWrite - 1 >= MmUserProbeAddress)
-        {
-            /* Don't allow to read from kernel space */
-            return STATUS_ACCESS_VIOLATION;
-        }
-        if (NumberOfBytesWritten != NULL)
-        {
-            _SEH_TRY
-            {
-                ProbeForWriteUlong(NumberOfBytesWritten);
-            }
-            _SEH_HANDLE
-            {
-                Status = _SEH_GetExceptionCode();
-            }
-            _SEH_END;
-
-            if (!NT_SUCCESS(Status))
-            {
-                return Status;
-            }
-        }
-    }
-
-    Status = ObReferenceObjectByHandle(ProcessHandle,
-                                       PROCESS_VM_WRITE,
-                                       NULL,
-                                       UserMode,
-                                       (PVOID*)(&Process),
-                                       NULL);
-    if (!NT_SUCCESS(Status))
-    {
-        return(Status);
-    }
-
-    CopyStatus = STATUS_SUCCESS;
-
-    /* Write memory */
-    if (Process == PsGetCurrentProcess())
-    {
-        if (PreviousMode != KernelMode)
-        {
-            _SEH_TRY
-            {
-                memcpy(BaseAddress, Buffer, NumberOfBytesToWrite);
-            }
-            _SEH_HANDLE
-            {
-                CopyStatus = _SEH_GetExceptionCode();
-            }
-            _SEH_END;
-        }
-        else
-        {
-            memcpy(BaseAddress, Buffer, NumberOfBytesToWrite);
-        }
-    }
-    else
-    {
-        /* Create MDL describing the source buffer. */
-        Mdl = MmCreateMdl(NULL,
-                          Buffer,
-                          NumberOfBytesToWrite);
-        if (Mdl == NULL)
-        {
-            ObDereferenceObject(Process);
-            return(STATUS_NO_MEMORY);
-        }
-        _SEH_TRY
-        {
-            /* Map the MDL. */
-            MmProbeAndLockPages(Mdl, UserMode, IoReadAccess);
-        }
-        _SEH_HANDLE
-        {
-            CopyStatus = _SEH_GetExceptionCode();
-        }
-        _SEH_END;
-
-        if (NT_SUCCESS(CopyStatus))
-        {
-            /* Copy memory from the mapped MDL into the target buffer. */
-            KeAttachProcess(&Process->Pcb);
-
-            SystemAddress = MmGetSystemAddressForMdl(Mdl);
-            if (PreviousMode != KernelMode)
-            {
-                _SEH_TRY
-                {
-                    memcpy(BaseAddress, SystemAddress, NumberOfBytesToWrite);
-                }
-                _SEH_HANDLE
-                {
-                    CopyStatus = _SEH_GetExceptionCode();
-                }
-                _SEH_END;
-            }
-            else
-            {
-                memcpy(BaseAddress, SystemAddress, NumberOfBytesToWrite);
-            }
-
-            KeDetachProcess();
-        }
-
-        /* Free the MDL. */
-        if (Mdl->MappedSystemVa != NULL)
-        {
-            MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
-        }
-        MmUnlockPages(Mdl);
-        ExFreePool(Mdl);
-    }
-    ObDereferenceObject(Process);
-
-    if (NT_SUCCESS(CopyStatus) && NumberOfBytesWritten != NULL)
-    {
-        if (PreviousMode != KernelMode)
-        {
-            _SEH_TRY
-            {
-                *NumberOfBytesWritten = NumberOfBytesToWrite;
-            }
-            _SEH_HANDLE
-            {
-                Status = _SEH_GetExceptionCode();
-            }
-            _SEH_END;
-        }
-        else
-        {
-            *NumberOfBytesWritten = NumberOfBytesToWrite;
-        }
-    }
-
-    return(NT_SUCCESS(CopyStatus) ? Status : CopyStatus);
-}
-
-/*
- * @unimplemented
- */
-
-PVOID
-STDCALL
-MmGetVirtualForPhysical(
-    IN PHYSICAL_ADDRESS PhysicalAddress
-    )
+                    IN ULONG NumberOfBytesToLock,
+                    OUT PULONG NumberOfBytesLocked OPTIONAL)
 {
     UNIMPLEMENTED;
-    return 0;
-}
-
-/* FUNCTION:
- * Called from EngSecureMem (subsys\win32k\eng\mem.c)
- * @unimplemented
- */
-PVOID STDCALL
-MmSecureVirtualMemory(PVOID  Address,
-                      SIZE_T Length,
-                      ULONG  Mode)
-{
-    /* Only works for user space */
-    if (((ULONG_PTR)Address >= (ULONG_PTR)Address + Length) ||
-        ((ULONG_PTR)MmHighestUserAddress < (ULONG_PTR)Address + Length))
-    {
-        return NULL;
-    }
-
+    if (NumberOfBytesLocked) *NumberOfBytesLocked = 0;
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+NtUnlockVirtualMemory(IN HANDLE ProcessHandle,
+                      IN PVOID BaseAddress,
+                      IN ULONG NumberOfBytesToUnlock,
+                      OUT PULONG NumberOfBytesUnlocked OPTIONAL)
+{
     UNIMPLEMENTED;
-
-    return 0;
-}
-
-
-/* FUNCTION:
- * Called from EngUnsecureMem (subsys\win32k\eng\mem.c)
- * @unimplemented
- */
-VOID STDCALL
-MmUnsecureVirtualMemory(PVOID SecureMem)
-{
-    if (NULL == SecureMem)
-    {
-        return;
-    }
-
+    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;
-}
-
-
-/*
- * @implemented
- */
-VOID STDCALL
-ProbeForRead(IN CONST VOID *Address,
-             IN ULONG Length,
-             IN ULONG Alignment)
-{
-    if (Length != 0)
-    {
-        ASSERT(Alignment == 1 || Alignment == 2 || Alignment == 4 || Alignment == 8);
-
-        if (((ULONG_PTR)Address & (Alignment - 1)) != 0)
-        {
-            ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT);
-        }
-        else if ((ULONG_PTR)Address + Length - 1 < (ULONG_PTR)Address ||
-                 (ULONG_PTR)Address + Length - 1 >= (ULONG_PTR)MmUserProbeAddress)
-        {
-            ExRaiseStatus (STATUS_ACCESS_VIOLATION);
-        }
-    }
-}
-
-
-/*
- * @implemented
- */
-VOID STDCALL
-ProbeForWrite(IN PVOID Address,
-              IN ULONG Length,
-              IN ULONG Alignment)
-{
-    volatile CHAR *Current;
-    PCHAR Last;
-
-    if (Length != 0)
-    {
-        ASSERT(Alignment == 1 || Alignment == 2 || Alignment == 4 || Alignment == 8);
-
-        if (((ULONG_PTR)Address & (Alignment - 1)) != 0)
-        {
-            ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT);
-        }
-
-        Last = (PCHAR)((ULONG_PTR)Address + Length - 1);
-        if ((ULONG_PTR)Last < (ULONG_PTR)Address ||
-            (ULONG_PTR)Last >= (ULONG_PTR)MmUserProbeAddress)
-        {
-            ExRaiseStatus (STATUS_ACCESS_VIOLATION);
-        }
-
-        /* Check for accessible pages, do *not* touch any memory outside of the
-           range!*/
-        Current = (volatile CHAR*)Address;
-        Last = (PCHAR)(PAGE_ROUND_DOWN(Last));
-        do
-        {
-            *Current = *Current;
-            Current = (volatile CHAR*)(PAGE_ROUND_DOWN(Current) + PAGE_SIZE);
-        } while (Current <= Last);
-    }
+    return STATUS_SUCCESS;
 }
 
 /* EOF */



More information about the Ros-diffs mailing list