MiQueryVirtualMemory(): created because ZwQueryVirtualMemory() didn't work for me...
[reactos.git] / reactos / ntoskrnl / mm / virtual.c
index 89f0e40..3970987 100644 (file)
 /*
- * COPYRIGHT:   See COPYING in the top directory
+ *  ReactOS kernel
+ *  Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/* $Id: virtual.c,v 1.86 2004/12/22 05:17:44 royce Exp $
+ *
  * PROJECT:     ReactOS kernel
  * FILE:        ntoskrnl/mm/virtual.c
- * PURPOSE:     implementing the Virtualxxx section of the win32 api
+ * PURPOSE:     Implementing operations on virtual memory.
  * PROGRAMMER:  David Welch
- * UPDATE HISTORY:
- *              09/4/98: Created
- *              10/6/98: Corrections from Fatahi (i_fatahi@hotmail.com)
- *              30/9/98: Implemented ZwxxxVirtualMemory functions
  */
-/* INCLUDE *****************************************************************/
 
-#include <windows.h>
+/* INCLUDE *****************************************************************/
 
-#include <internal/i386/segment.h>
-#include <internal/mm.h>
-#include <internal/mmhal.h>
-#include <internal/ob.h>
-#include <internal/io.h>
-#include <internal/ps.h>
+#include <ntoskrnl.h>
 
 #define NDEBUG
 #include <internal/debug.h>
 
-/* TYPES *******************************************************************/
-
-extern unsigned int etext;
-extern unsigned int end;
-
-static MEMORY_AREA* kernel_text_desc = NULL;
-static MEMORY_AREA* kernel_data_desc = NULL;
-static MEMORY_AREA* kernel_param_desc = NULL;
-static MEMORY_AREA* kernel_pool_desc = NULL;
+/* FUNCTIONS *****************************************************************/
 
-/* FUNCTIONS ****************************************************************/
-
-void VirtualInit(boot_param* bp)
+NTSTATUS STDCALL
+NtFlushVirtualMemory(IN HANDLE ProcessHandle,
+                     IN PVOID BaseAddress,
+                     IN ULONG NumberOfBytesToFlush,
+                     OUT PULONG NumberOfBytesFlushed OPTIONAL)
 /*
- * FUNCTION: Intialize the memory areas list
+ * FUNCTION: Flushes virtual memory to file
  * ARGUMENTS:
- *           bp = Pointer to the boot parameters
- *           kernel_len = Length of the kernel
+ *        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
  */
 {
-   unsigned int kernel_len = bp->end_mem - bp->start_mem;
-   PVOID BaseAddress;
-   ULONG Length;
-   ULONG ParamLength = kernel_len;
-   
-   DPRINT("VirtualInit() %x\n",bp);
-   
-   MmInitMemoryAreas();
-   ExInitNonPagedPool(KERNEL_BASE+ PAGE_ROUND_UP(kernel_len) + PAGESIZE);
-   
-   
-   /*
-    * Setup the system area descriptor list
-    */
-   BaseAddress = (PVOID)KERNEL_BASE;
-   Length = PAGE_ROUND_UP(((ULONG)&etext)) - KERNEL_BASE;
-   ParamLength = ParamLength - Length;
-   MmCreateMemoryArea(KernelMode,NULL,MEMORY_AREA_SYSTEM,&BaseAddress,
-                     Length,0,&kernel_text_desc);
-   
-   Length = PAGE_ROUND_UP(((ULONG)&end)) - PAGE_ROUND_UP(((ULONG)&etext));
-   ParamLength = ParamLength - Length;
-   DPRINT("Length %x\n",Length);
-   BaseAddress = (PVOID)PAGE_ROUND_UP(((ULONG)&etext));
-   MmCreateMemoryArea(KernelMode,
-                     NULL,
-                     MEMORY_AREA_SYSTEM,
-                     &BaseAddress,
-                     Length,
-                     0,
-                     &kernel_data_desc);
-   
-   
-   BaseAddress = (PVOID)PAGE_ROUND_UP(((ULONG)&end));
-   Length = ParamLength;
-   MmCreateMemoryArea(KernelMode,NULL,MEMORY_AREA_SYSTEM,&BaseAddress,
-                     Length,0,&kernel_param_desc);
-   
-   BaseAddress = (PVOID)(KERNEL_BASE + PAGE_ROUND_UP(kernel_len) + PAGESIZE);
-   Length = NONPAGED_POOL_SIZE;
-   MmCreateMemoryArea(KernelMode,NULL,MEMORY_AREA_SYSTEM,&BaseAddress,
-                     Length,0,&kernel_pool_desc);
-   
-//   MmDumpMemoryAreas();
-   CHECKPOINT;
-   
-   MmInitSectionImplementation();
+   UNIMPLEMENTED;
+   return(STATUS_NOT_IMPLEMENTED);
 }
 
-ULONG MmCommitedSectionHandleFault(MEMORY_AREA* MemoryArea, ULONG Address)
+
+NTSTATUS STDCALL
+MiLockVirtualMemory(HANDLE ProcessHandle,
+  PVOID BaseAddress,
+  ULONG NumberOfBytesToLock,
+  PULONG NumberOfBytesLocked,
+  PObReferenceObjectByHandle pObReferenceObjectByHandle,
+  PMmCreateMdl pMmCreateMdl,
+  PObDereferenceObject pObDereferenceObject,
+  PMmProbeAndLockPages pMmProbeAndLockPages,
+  PExFreePool pExFreePool)
 {
-   set_page(Address,0x7,get_free_page());
-   return(TRUE);
+  PEPROCESS Process;
+  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 MmSectionHandleFault(MEMORY_AREA* MemoryArea, PVOID Address)
+
+NTSTATUS STDCALL
+NtLockVirtualMemory(HANDLE ProcessHandle,
+  PVOID BaseAddress,
+  ULONG NumberOfBytesToLock,
+  PULONG NumberOfBytesLocked)
 {
-   LARGE_INTEGER Offset;
-   IO_STATUS_BLOCK IoStatus;
-   
-   DPRINT("MmSectionHandleFault(MemoryArea %x, Address %x)\n",
-           MemoryArea,Address);
-   
-   set_page(Address,0x7,get_free_page());
-   
-   Offset.LowPart = (Address - MemoryArea->BaseAddress) + 
-     MemoryArea->Data.SectionData.ViewOffset;
-   
-   DPRINT("MemoryArea->Data.SectionData.Section->FileObject %x\n",
-           MemoryArea->Data.SectionData.Section->FileObject);
-   
-   if (MemoryArea->Data.SectionData.Section->FileObject == NULL)
-     {
-       return(STATUS_UNSUCCESSFUL);
-     }
-   
-   IoPageRead(MemoryArea->Data.SectionData.Section->FileObject,
-             (PVOID)Address,
-             &Offset,
-             &IoStatus);
-   
-   DPRINT("Returning from MmSectionHandleFault()\n");
-   
-   return(STATUS_SUCCESS);
+  DPRINT("NtLockVirtualMemory(ProcessHandle %x, BaseAddress %x, "
+    "NumberOfBytesToLock %d, NumberOfBytesLocked %x)\n",
+    ProcessHandle,
+    BaseAddress,
+    NumberOfBytesToLock,
+    NumberOfBytesLocked);
+
+  return MiLockVirtualMemory(ProcessHandle,
+    BaseAddress,
+    NumberOfBytesToLock,
+    NumberOfBytesLocked,
+    ObReferenceObjectByHandle,
+    MmCreateMdl,
+    ObfDereferenceObject,
+    MmProbeAndLockPages,
+    ExFreePool);
 }
 
-asmlinkage int page_fault_handler(unsigned int cs,
-                                  unsigned int eip)
-/*
- * FUNCTION: Handle a page fault
- */
+
+NTSTATUS FASTCALL
+MiQueryVirtualMemory (IN HANDLE ProcessHandle,
+                      IN PVOID Address,
+                      IN CINT VirtualMemoryInformationClass,
+                      OUT PVOID VirtualMemoryInformation,
+                      IN ULONG Length,
+                      OUT PULONG ResultLength)
 {
-   KPROCESSOR_MODE FaultMode;
+   NTSTATUS Status;
+   PEPROCESS Process;
    MEMORY_AREA* MemoryArea;
-   KIRQL oldlvl;
-   ULONG stat;
-   
-   /*
-    * Get the address for the page fault
-    */
-   unsigned int cr2;
-   __asm__("movl %%cr2,%0\n\t" : "=d" (cr2));                
-   DPRINT("Page fault at address %x with eip %x\n",cr2,eip);
-
-   cr2 = PAGE_ROUND_DOWN(cr2);
-   
-   if (KeGetCurrentIrql()!=PASSIVE_LEVEL)
-     {
-       DbgPrint("Recursive page fault detected\n");
-       return(0);
-//     KeBugCheck(0);
-     }
-   
-   KeRaiseIrql(DISPATCH_LEVEL,&oldlvl);
-   
-   /*
-    * Find the memory area for the faulting address
-    */
-   if (cr2>=KERNEL_BASE)
-     {
-       /*
-        * Check permissions
-        */
-       if (cs!=KERNEL_CS)
-         {
-            printk("%s:%d\n",__FILE__,__LINE__);
-            return(0);
-         }
-       FaultMode = UserMode;
-     }
+   PMADDRESS_SPACE AddressSpace;
+
+   if (Address < (PVOID)KERNEL_BASE)
+   {
+      Status = ObReferenceObjectByHandle(ProcessHandle,
+                                         PROCESS_QUERY_INFORMATION,
+                                         NULL,
+                                         UserMode,
+                                         (PVOID*)(&Process),
+                                         NULL);
+
+      if (!NT_SUCCESS(Status))
+      {
+         DPRINT("NtQueryVirtualMemory() = %x\n",Status);
+         return(Status);
+      }
+      AddressSpace = &Process->AddressSpace;
+   }
    else
-     {
-       FaultMode = KernelMode;
-     }
-   
-   MemoryArea = MmOpenMemoryAreaByAddress(PsGetCurrentProcess(),(PVOID)cr2);
-   if (MemoryArea==NULL)
-     {
-       printk("%s:%d\n",__FILE__,__LINE__);
-       return(0);
-     }
-   
-   switch (MemoryArea->Type)
-     {
-      case MEMORY_AREA_SYSTEM:
-       stat = 0;
-       break;
-       
-      case MEMORY_AREA_SECTION_VIEW_COMMIT:
-        if (MmSectionHandleFault(MemoryArea,cr2)==STATUS_SUCCESS)
-         {
-            stat=1;
-         }
-       else
-         {
-            stat = 0;
-         }
-       break;
-       
-      case MEMORY_AREA_COMMIT:
-       stat = MmCommitedSectionHandleFault(MemoryArea,cr2);
-       break;
-       
+   {
+      AddressSpace = MmGetKernelAddressSpace();
+   }
+   MmLockAddressSpace(AddressSpace);
+   MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
+                                          Address);
+   switch(VirtualMemoryInformationClass)
+   {
+      case MemoryBasicInformation:
+         {
+           PMEMORY_BASIC_INFORMATION Info =
+               (PMEMORY_BASIC_INFORMATION)VirtualMemoryInformation;
+            if (Length != sizeof(MEMORY_BASIC_INFORMATION))
+            {
+               MmUnlockAddressSpace(AddressSpace);
+               ObDereferenceObject(Process);
+               return(STATUS_INFO_LENGTH_MISMATCH);
+            }
+
+            if (MemoryArea == NULL)
+            {
+              Info->Type = 0;
+               Info->State = MEM_FREE;
+              Info->Protect = PAGE_NOACCESS;
+              Info->AllocationProtect = 0;
+               Info->BaseAddress = (PVOID)PAGE_ROUND_DOWN(Address);
+              Info->AllocationBase = NULL;
+              Info->RegionSize = MmFindGapAtAddress(AddressSpace, Info->BaseAddress);
+               Status = STATUS_SUCCESS;
+               *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
+           }
+            else
+           {
+              switch(MemoryArea->Type)
+              {
+                 case MEMORY_AREA_VIRTUAL_MEMORY:
+                     Status = MmQueryAnonMem(MemoryArea, Address, Info,
+                                             ResultLength);
+                    break;
+                 case MEMORY_AREA_SECTION_VIEW:
+                     Status = MmQuerySectionView(MemoryArea, Address, Info,
+                                                 ResultLength);
+                     break;
+                 case MEMORY_AREA_NO_ACCESS:
+                    Info->Type = 0;
+                     Info->State = MEM_FREE;
+                    Info->Protect = MemoryArea->Attributes;
+                    Info->AllocationProtect = MemoryArea->Attributes;
+                     Info->BaseAddress = MemoryArea->BaseAddress;
+                    Info->AllocationBase = MemoryArea->BaseAddress;
+                    Info->RegionSize = MemoryArea->Length;
+                     Status = STATUS_SUCCESS;
+                     *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
+                    break;
+                 case MEMORY_AREA_SHARED_DATA:
+                    Info->Type = 0;
+                     Info->State = MEM_COMMIT;
+                    Info->Protect = MemoryArea->Attributes;
+                    Info->AllocationProtect = MemoryArea->Attributes;
+                     Info->BaseAddress = MemoryArea->BaseAddress;
+                    Info->AllocationBase = MemoryArea->BaseAddress;
+                    Info->RegionSize = MemoryArea->Length;
+                     Status = STATUS_SUCCESS;
+                     *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
+                    break;
+                 case MEMORY_AREA_SYSTEM:
+                    {
+                       static int warned = 0;
+                       if ( !warned )
+                       {
+                         DPRINT1("FIXME: MEMORY_AREA_SYSTEM case incomplete (or possibly wrong) for NtQueryVirtualMemory()\n");
+                         warned = 1;
+                       }
+                    }
+                    /* FIXME - don't have a clue if this is right, but it's better than nothing */
+                    Info->Type = 0;
+                     Info->State = MEM_COMMIT;
+                    Info->Protect = MemoryArea->Attributes;
+                    Info->AllocationProtect = MemoryArea->Attributes;
+                     Info->BaseAddress = MemoryArea->BaseAddress;
+                    Info->AllocationBase = MemoryArea->BaseAddress;
+                    Info->RegionSize = MemoryArea->Length;
+                     Status = STATUS_SUCCESS;
+                     *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
+                    break;
+                 case MEMORY_AREA_KERNEL_STACK:
+                    {
+                       static int warned = 0;
+                       if ( !warned )
+                       {
+                         DPRINT1("FIXME: MEMORY_AREA_KERNEL_STACK case incomplete (or possibly wrong) for NtQueryVirtualMemory()\n");
+                         warned = 1;
+                       }
+                    }
+                    /* FIXME - don't have a clue if this is right, but it's better than nothing */
+                    Info->Type = 0;
+                     Info->State = MEM_COMMIT;
+                    Info->Protect = MemoryArea->Attributes;
+                    Info->AllocationProtect = MemoryArea->Attributes;
+                     Info->BaseAddress = MemoryArea->BaseAddress;
+                    Info->AllocationBase = MemoryArea->BaseAddress;
+                    Info->RegionSize = MemoryArea->Length;
+                     Status = STATUS_SUCCESS;
+                     *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
+                    break;
+                 default:
+                    DPRINT1("unhandled memory area type: 0x%x\n", MemoryArea->Type);
+                    Status = STATUS_UNSUCCESSFUL;
+                     *ResultLength = 0;
+              }
+           }
+            break;
+         }
+
       default:
-       stat = 0;
-       break;
-     }
-   if (stat)
-     {
-       KeLowerIrql(oldlvl);
-     }
-   return(stat);
+         {
+            Status = STATUS_INVALID_INFO_CLASS;
+            *ResultLength = 0;
+            break;
+         }
+   }
+
+   MmUnlockAddressSpace(AddressSpace);
+   if (Address < (PVOID)KERNEL_BASE)
+   {
+      ObDereferenceObject(Process);
+   }
+
+   return Status;
 }
 
-BOOLEAN MmIsNonPagedSystemAddressValid(PVOID VirtualAddress)
+/* (tMk 2004.II.4)
+ * FUNCTION:
+ * Called from VirtualQueryEx (lib\kernel32\mem\virtual.c)
+ *
+ */
+NTSTATUS STDCALL
+NtQueryVirtualMemory (IN HANDLE ProcessHandle,
+                      IN PVOID Address,
+                      IN CINT VirtualMemoryInformationClass,
+                      OUT PVOID VirtualMemoryInformation,
+                      IN ULONG Length,
+                      OUT PULONG UnsafeResultLength)
 {
-   UNIMPLEMENTED;
+   NTSTATUS Status;
+   ULONG ResultLength = 0;
+   KPROCESSOR_MODE PrevMode;
+   union
+   {
+      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);
+
+   PrevMode =  ExGetPreviousMode();
+
+   if (PrevMode == UserMode && Address >= (PVOID)KERNEL_BASE)
+   {
+      DPRINT1("Invalid parameter\n");
+      return STATUS_INVALID_PARAMETER;
+   }
+
+   Status = MiQueryVirtualMemory ( ProcessHandle,
+       Address,
+       VirtualMemoryInformationClass,
+       &VirtualMemoryInfo,
+       Length,
+       &ResultLength );
+
+   if (NT_SUCCESS(Status) && ResultLength > 0)
+   {
+      Status = MmCopyToCaller(VirtualMemoryInformation, &VirtualMemoryInfo, ResultLength);
+      if (!NT_SUCCESS(Status))
+      {
+         ResultLength = 0;
+      }
+   }
+
+   if (UnsafeResultLength != NULL)
+   {
+      MmCopyToCaller(UnsafeResultLength, &ResultLength, sizeof(ULONG));
+   }
+   return(Status);
 }
 
-BOOLEAN MmIsAddressValid(PVOID VirtualAddress)
-/*
- * FUNCTION: Checks whether the given address is valid for a read or write
- * ARGUMENTS:
- *          VirtualAddress = address to check
- * RETURNS: True if the access would be valid
- *          False if the access would cause a page fault
- * NOTES: This function checks whether a byte access to the page would
- *        succeed. Is this realistic for RISC processors which don't
- *        allow byte granular access?
+
+/* (tMk 2004.II.5)
+ * FUNCTION:
+ * Called from VirtualProtectEx (lib\kernel32\mem\virtual.c)
+ *
  */
+NTSTATUS STDCALL
+NtProtectVirtualMemory(IN HANDLE ProcessHandle,
+                       IN PVOID *UnsafeBaseAddress,
+                       IN ULONG *UnsafeNumberOfBytesToProtect,
+                       IN ULONG NewAccessProtection,
+                       OUT PULONG UnsafeOldAccessProtection)
 {
-   MEMORY_AREA* MemoryArea;
-   
-   MemoryArea = MmOpenMemoryAreaByAddress(PsGetCurrentProcess(),
-                                         VirtualAddress);
+   PMEMORY_AREA MemoryArea;
+   PEPROCESS Process;
+   NTSTATUS Status;
+   PMADDRESS_SPACE AddressSpace;
+   ULONG OldAccessProtection;
+   PVOID BaseAddress;
+   ULONG NumberOfBytesToProtect;
+
+   Status = MmCopyFromCaller(&BaseAddress, UnsafeBaseAddress, sizeof(PVOID));
+   if (!NT_SUCCESS(Status))
+      return Status;
+   Status = MmCopyFromCaller(&NumberOfBytesToProtect, UnsafeNumberOfBytesToProtect, sizeof(ULONG));
+   if (!NT_SUCCESS(Status))
+      return Status;
+
+   // (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);
+   }
+
+   NumberOfBytesToProtect =
+      PAGE_ROUND_UP(BaseAddress + NumberOfBytesToProtect) -
+      PAGE_ROUND_DOWN(BaseAddress);
+   BaseAddress = (PVOID)PAGE_ROUND_DOWN(BaseAddress);
 
+   Status = ObReferenceObjectByHandle(ProcessHandle,
+                                      PROCESS_VM_OPERATION,
+                                      PsProcessType,
+                                      UserMode,
+                                      (PVOID*)(&Process),
+                                      NULL);
+   if (!NT_SUCCESS(Status))
+   {
+      DPRINT("NtProtectVirtualMemory() = %x\n",Status);
+      return(Status);
+   }
+
+   AddressSpace = &Process->AddressSpace;
+
+   MmLockAddressSpace(AddressSpace);
+   MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
+                                          BaseAddress);
    if (MemoryArea == NULL)
-     {
-       return(FALSE);
-     }
-   return(TRUE);
+   {
+      MmUnlockAddressSpace(AddressSpace);
+      ObDereferenceObject(Process);
+      return(STATUS_UNSUCCESSFUL);
+   }
+
+   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);
+   }
+
+   MmUnlockAddressSpace(AddressSpace);
+   ObDereferenceObject(Process);
+
+   MmCopyToCaller(UnsafeOldAccessProtection, &OldAccessProtection, sizeof(ULONG));
+   MmCopyToCaller(UnsafeBaseAddress, &BaseAddress, sizeof(PVOID));
+   MmCopyToCaller(UnsafeNumberOfBytesToProtect, &NumberOfBytesToProtect, sizeof(ULONG));
+
+   return(Status);
 }
 
-NTSTATUS
-STDCALL
-NtAllocateVirtualMemory( 
-       IN HANDLE ProcessHandle,
-       IN OUT PVOID *BaseAddress,
-       IN ULONG  ZeroBits,
-       IN OUT PULONG  RegionSize,
-       IN ULONG  AllocationType, 
-       IN ULONG  Protect
-       )
-{
-   return(ZwAllocateVirtualMemory(ProcessHandle,
-                                 BaseAddress,
-                                 ZeroBits,
-                                 RegionSize,
-                                 AllocationType,
-                                 Protect));
-}
 
-NTSTATUS
-STDCALL
-ZwAllocateVirtualMemory( 
-       IN HANDLE ProcessHandle,
-       IN OUT PVOID *BaseAddress,
-       IN ULONG  ZeroBits,
-       IN OUT PULONG  RegionSize,
-       IN ULONG  AllocationType, 
-       IN ULONG  Protect
-       )
-/*
- * FUNCTION: Allocates a block of virtual memory in the process address space
- * ARGUMENTS:
- *      ProcessHandle = The handle of the process which owns the virtual memory
- *      BaseAddress   = A pointer to the virtual memory allocated. If you 
- *                      supply a non zero value the system will try to 
- *                      allocate the memory at the address supplied. It round 
- *                      it down to a multiple  of the page size.
- *      ZeroBits  = (OPTIONAL) You can specify the number of high order bits 
- *                      that must be zero, ensuring that the memory will be 
- *                      allocated at a address below a certain value.
- *      RegionSize = The number of bytes to allocate
- *      AllocationType = Indicates the type of virtual memory you like to 
- *                       allocated, can be one of the values : MEM_COMMIT, 
- *                       MEM_RESERVE, MEM_RESET, MEM_TOP_DOWN
- *      Protect = Indicates the protection type of the pages allocated, can be
- *                a combination of PAGE_READONLY, PAGE_READWRITE, 
- *                PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_GUARD, 
- *                PAGE_NOACCESS
- * REMARKS:
- *       This function maps to the win32 VirtualAllocEx. Virtual memory is 
- *       process based so the  protocol starts with a ProcessHandle. I 
- *       splitted the functionality of obtaining the actual address and 
- *       specifying the start address in two parameters ( BaseAddress and 
- *       StartAddress ) The NumberOfBytesAllocated specify the range and the 
- *       AllocationType and ProctectionType map to the other two parameters.
- * RETURNS: 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,
+                    IN PVOID BaseAddress,
+                    OUT PVOID Buffer,
+                    IN ULONG NumberOfBytesToRead,
+                    OUT PULONG NumberOfBytesRead OPTIONAL)
 {
-   PEPROCESS Process;
-   MEMORY_AREA* MemoryArea;
-   ULONG Type;
    NTSTATUS Status;
-   
-   DPRINT("ZwAllocateVirtualMemory(ProcessHandle %x, *BaseAddress %x, "
-           "ZeroBits %d, RegionSize %d, AllocationType %x, Protect %x)\n",
-           ProcessHandle,*BaseAddress,ZeroBits,*RegionSize,AllocationType,
-           Protect);
-   
+   PMDL Mdl;
+   PVOID SystemAddress;
+   PEPROCESS Process, CurrentProcess;
+
+
+   DPRINT("NtReadVirtualMemory(ProcessHandle %x, BaseAddress %x, "
+          "Buffer %x, NumberOfBytesToRead %d)\n",ProcessHandle,BaseAddress,
+          Buffer,NumberOfBytesToRead);
+
    Status = ObReferenceObjectByHandle(ProcessHandle,
-                                     PROCESS_VM_OPERATION,
-                                     NULL,
-                                     UserMode,
-                                     (PVOID*)(&Process),
-                                     NULL);
-   if (Status != STATUS_SUCCESS)
-     {
-       DPRINT("ZwAllocateVirtualMemory() = %x\n",Status);
-       return(Status);
-     }
-   
-   if (AllocationType & MEM_RESERVE)
-     {
-       Type = MEMORY_AREA_RESERVE;
-     }
+                                      PROCESS_VM_WRITE,
+                                      NULL,
+                                      UserMode,
+                                      (PVOID*)(&Process),
+                                      NULL);
+   if (!NT_SUCCESS(Status))
+   {
+      return(Status);
+   }
+
+   CurrentProcess = PsGetCurrentProcess();
+
+   if (Process == CurrentProcess)
+   {
+      memcpy(Buffer, BaseAddress, NumberOfBytesToRead);
+   }
    else
-     {
-       Type = MEMORY_AREA_COMMIT;
-     }
-   
-   if ((*BaseAddress) != 0)
-     {
-       MemoryArea = MmOpenMemoryAreaByAddress(Process, *BaseAddress);
-       
-       if (MemoryArea != NULL)
-         {
-            if (MemoryArea->BaseAddress == (*BaseAddress) &&
-                MemoryArea->Length == *RegionSize)
-              {
-                 MemoryArea->Type = Type;
-                 MemoryArea->Attributes =Protect;
-                 DPRINT("*BaseAddress %x\n",*BaseAddress);
-                 return(STATUS_SUCCESS);
-              }
-            
-            MemoryArea = MmSplitMemoryArea(Process,
-                                           MemoryArea,
-                                           *BaseAddress,
-                                           *RegionSize,
-                                           Type,
-                                           Protect);
-            DPRINT("*BaseAddress %x\n",*BaseAddress);
-            return(STATUS_SUCCESS);
-         }
-     }
-   
- //FIXME RegionSize should be passed as pointer
-
-
-   Status = MmCreateMemoryArea(UserMode,
-                              Process,
-                              Type,
-                              BaseAddress,
-                              *RegionSize,
-                              Protect,
-                              &MemoryArea);
-   
-   if (Status != STATUS_SUCCESS)
-     {
-       DPRINT("ZwAllocateVirtualMemory() = %x\n",Status);
-       return(Status);
-     }
-   
-   DPRINT("*BaseAddress %x\n",*BaseAddress);
-   
+   {
+      Mdl = MmCreateMdl(NULL,
+                        Buffer,
+                        NumberOfBytesToRead);
+      if(Mdl == NULL)
+      {
+         ObDereferenceObject(Process);
+         return(STATUS_NO_MEMORY);
+      }
+      MmProbeAndLockPages(Mdl,
+                          UserMode,
+                          IoWriteAccess);
+
+      KeAttachProcess(&Process->Pcb);
+
+      SystemAddress = MmGetSystemAddressForMdl(Mdl);
+      memcpy(SystemAddress, BaseAddress, NumberOfBytesToRead);
+
+      KeDetachProcess();
+
+      if (Mdl->MappedSystemVa != NULL)
+      {
+         MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
+      }
+      MmUnlockPages(Mdl);
+      ExFreePool(Mdl);
+   }
+
+   ObDereferenceObject(Process);
+
+   if (NumberOfBytesRead)
+      *NumberOfBytesRead = NumberOfBytesToRead;
    return(STATUS_SUCCESS);
 }
 
-NTSTATUS STDCALL NtFlushVirtualMemory(IN HANDLE ProcessHandle,
-                                     IN PVOID BaseAddress,
-                                     IN ULONG NumberOfBytesToFlush,
-                                     OUT PULONG NumberOfBytesFlushed OPTIONAL)
-{
-   return(ZwFlushVirtualMemory(ProcessHandle,
-                              BaseAddress,
-                              NumberOfBytesToFlush,
-                              NumberOfBytesFlushed));
-}
-
-NTSTATUS STDCALL ZwFlushVirtualMemory(IN HANDLE ProcessHandle,
-                                     IN PVOID BaseAddress,
-                                     IN ULONG NumberOfBytesToFlush,
-                                     OUT PULONG NumberOfBytesFlushed OPTIONAL)
-
-/*
- * 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 
+/* (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)
 {
-   UNIMPLEMENTED;
-}
-
-NTSTATUS STDCALL NtFreeVirtualMemory(IN HANDLE ProcessHandle,
-                                    IN PVOID  *BaseAddress,    
-                                    IN PULONG  RegionSize,     
-                                    IN ULONG  FreeType)
-{
-   return(ZwFreeVirtualMemory(ProcessHandle,
-                             BaseAddress,
-                             RegionSize,
-                             FreeType));
-}
-
-NTSTATUS STDCALL ZwFreeVirtualMemory(IN HANDLE ProcessHandle,
-                                    IN PVOID  *BaseAddress,    
-                                    IN PULONG  RegionSize,     
-                                    IN ULONG  FreeType)
+   // 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...
 
-/*
- * FUNCTION: Frees a range of virtual memory
- * ARGUMENTS:
- *        ProcessHandle = Points to the process that allocated the virtual 
- *                        memory
- *        BaseAddress = Points to the memory address, rounded down to a 
- *                      multiple of the pagesize
- *        RegionSize = Limits the range to free, rounded up to a multiple of 
- *                     the paging size
- *        FreeType = Can be one of the values:  MEM_DECOMMIT, or MEM_RELEASE
- * RETURNS: Status 
- */
-{
-   MEMORY_AREA* MemoryArea;
    NTSTATUS Status;
+   PMDL Mdl;
    PEPROCESS Process;
-   
-   Status = ObReferenceObjectByHandle(ProcessHandle,
-                                     PROCESS_VM_OPERATION,
-                                     PsProcessType,
-                                     UserMode,
-                                     (PVOID*)(&Process),
-                                     NULL);
-   if (Status != STATUS_SUCCESS)
-     {
-       DbgPrint("ZwFreeVirtualMemory() = %x\n",Status);
-       return(Status);
-     }
-
-   MemoryArea = MmOpenMemoryAreaByAddress(Process,*BaseAddress);
-   if (MemoryArea == NULL)
-     {
-       return(STATUS_UNSUCCESSFUL);
-     }
-   
-   if (FreeType == MEM_RELEASE)
-     {
-       if (MemoryArea->BaseAddress != (*BaseAddress))
-         {
-            return(STATUS_UNSUCCESSFUL);
-         }
-       MmFreeMemoryArea(PsGetCurrentProcess(),
-                        BaseAddress,
-                        0,
-                        TRUE);
-       return(STATUS_SUCCESS);
-     }
-   
-   UNIMPLEMENTED;
-}
 
-NTSTATUS STDCALL NtLockVirtualMemory(HANDLE ProcessHandle,
-                                    PVOID BaseAddress,
-                                    ULONG NumberOfBytesToLock,
-                                    PULONG NumberOfBytesLocked)
-{
-   return(ZwLockVirtualMemory(ProcessHandle,
-                             BaseAddress,
-                             NumberOfBytesToLock,
-                             NumberOfBytesLocked));
-}
+   DPRINT("NtUnlockVirtualMemory(ProcessHandle %x, BaseAddress %x, "
+          "NumberOfBytesToUnlock %d), NumberOfBytesUnlocked %x\n",ProcessHandle,BaseAddress,
+          NumberOfBytesToUnlock, NumberOfBytesUnlocked);
 
-NTSTATUS STDCALL ZwLockVirtualMemory(HANDLE ProcessHandle,
-                                    PVOID BaseAddress,
-                                    ULONG NumberOfBytesToLock,
-                                    PULONG NumberOfBytesLocked)
-{
-   UNIMPLEMENTED;
-}
+   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;
 
-NTSTATUS STDCALL NtProtectVirtualMemory(IN HANDLE ProcessHandle,
-                                       IN PVOID BaseAddress,
-                                       IN ULONG NumberOfBytesToProtect,
-                                       IN ULONG NewAccessProtection,
-                                       OUT PULONG OldAccessProtection)
-{
-   return(ZwProtectVirtualMemory(ProcessHandle,
-                                BaseAddress,
-                                NumberOfBytesToProtect,
-                                NewAccessProtection,
-                                OldAccessProtection));
+   return(STATUS_SUCCESS);
 }
 
-VOID MmChangeAreaProtection(PEPROCESS Process, 
-                           PVOID BaseAddress,
-                           ULONG Length, 
-                           ULONG Protect)
-{
-   ULONG i;
-   
-   for (i=0; i<(Length/PAGESIZE); i++)
-     {
-       if (MmIsPagePresent(Process, BaseAddress + (i*PAGESIZE)))
-         {
-            MmSetPageProtect(Process, BaseAddress + (i*PAGESIZE), Protect);
-         }
-     }
-}
 
-NTSTATUS STDCALL ZwProtectVirtualMemory(IN HANDLE ProcessHandle,
-                                       IN PVOID BaseAddress,
-                                       IN ULONG NumberOfBytesToProtect,
-                                       IN ULONG NewAccessProtection,
-                                       OUT PULONG OldAccessProtection)
+/* (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)
 {
-   PMEMORY_AREA MemoryArea;
-   PEPROCESS Process;
    NTSTATUS Status;
-   
+   PMDL Mdl;
+   PVOID SystemAddress;
+   PEPROCESS Process;
+
+   DPRINT("NtWriteVirtualMemory(ProcessHandle %x, BaseAddress %x, "
+          "Buffer %x, NumberOfBytesToWrite %d)\n",ProcessHandle,BaseAddress,
+          Buffer,NumberOfBytesToWrite);
+
    Status = ObReferenceObjectByHandle(ProcessHandle,
-                                     PROCESS_VM_OPERATION,
-                                     PsProcessType,
-                                     UserMode,
-                                     (PVOID*)(&Process),
-                                     NULL);
-   if (Status != STATUS_SUCCESS)
-     {
-       DbgPrint("ZwProtectVirtualMemory() = %x\n",Status);
-       return(Status);
-     }
-
-   MemoryArea = MmOpenMemoryAreaByAddress(Process,BaseAddress);
-   if (MemoryArea == NULL)
-     {
-       DbgPrint("ZwProtectVirtualMemory() = %x\n",STATUS_UNSUCCESSFUL);
-       return(STATUS_UNSUCCESSFUL);
-     }
-
-   *OldAccessProtection = MemoryArea->Attributes;
-
-   if (MemoryArea->BaseAddress == BaseAddress &&
-       MemoryArea->Length == NumberOfBytesToProtect)
-     {
-       MemoryArea->Attributes = NewAccessProtection;   
-     }
+                                      PROCESS_VM_WRITE,
+                                      NULL,
+                                      UserMode,
+                                      (PVOID*)(&Process),
+                                      NULL);
+   if (!NT_SUCCESS(Status))
+   {
+      return(Status);
+   }
+
+   if (Process == PsGetCurrentProcess())
+   {
+      memcpy(BaseAddress, Buffer, NumberOfBytesToWrite);
+   }
    else
-     {
-       MemoryArea = MmSplitMemoryArea(Process,
-                                      MemoryArea,
-                                      BaseAddress,
-                                      NumberOfBytesToProtect,
-                                      MemoryArea->Type,
-                                      NewAccessProtection);
-     }
-   MmChangeAreaProtection(Process,BaseAddress,NumberOfBytesToProtect,
-                         NewAccessProtection);
+   {
+      Mdl = MmCreateMdl(NULL,
+                        Buffer,
+                        NumberOfBytesToWrite);
+      MmProbeAndLockPages(Mdl,
+                          UserMode,
+                          IoReadAccess);
+      if(Mdl == NULL)
+      {
+         ObDereferenceObject(Process);
+         return(STATUS_NO_MEMORY);
+      }
+      KeAttachProcess(&Process->Pcb);
+
+      SystemAddress = MmGetSystemAddressForMdl(Mdl);
+      memcpy(BaseAddress, SystemAddress, NumberOfBytesToWrite);
+
+      KeDetachProcess();
+
+      if (Mdl->MappedSystemVa != NULL)
+      {
+         MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
+      }
+      MmUnlockPages(Mdl);
+      ExFreePool(Mdl);
+   }
+
+   ObDereferenceObject(Process);
+
+   *NumberOfBytesWritten = NumberOfBytesToWrite;
+
    return(STATUS_SUCCESS);
 }
 
+/*
+ * @unimplemented
+ */
 
-NTSTATUS STDCALL NtQueryVirtualMemory(IN HANDLE ProcessHandle,
-                                     IN PVOID Address,
-                                     IN IN CINT VirtualMemoryInformationClass,
-                                     OUT PVOID VirtualMemoryInformation,
-                                     IN ULONG Length,
-                                     OUT PULONG ResultLength)
+PVOID
+STDCALL
+MmGetVirtualForPhysical (
+    IN PHYSICAL_ADDRESS PhysicalAddress
+    )
 {
-   return(ZwQueryVirtualMemory(ProcessHandle,
-                              Address,
-                              VirtualMemoryInformationClass,
-                              VirtualMemoryInformation,
-                              Length,
-                              ResultLength));
+       UNIMPLEMENTED;
+       return 0;
 }
 
-NTSTATUS STDCALL ZwQueryVirtualMemory(IN HANDLE ProcessHandle,
-                                     IN PVOID Address,
-                                     IN CINT VirtualMemoryInformationClass,
-                                     OUT PVOID VirtualMemoryInformation,
-                                     IN ULONG Length,
-                                     OUT PULONG ResultLength)
+/* 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 (MmHighestUserAddress < Address)
+   {
+      return NULL;
+   }
+
    UNIMPLEMENTED;
-}
 
-NTSTATUS STDCALL NtReadVirtualMemory(IN HANDLE ProcessHandle,
-                                    IN PVOID BaseAddress,
-                                    OUT PVOID Buffer,
-                                    IN ULONG  NumberOfBytesToRead,
-                                    OUT PULONG NumberOfBytesRead)
-{
-   return(ZwReadVirtualMemory(ProcessHandle,
-                             BaseAddress,
-                             Buffer,
-                             NumberOfBytesToRead,
-                             NumberOfBytesRead));
+   return 0;
 }
 
-NTSTATUS STDCALL ZwReadVirtualMemory(IN HANDLE ProcessHandle,
-                                    IN PVOID BaseAddress,
-                                    OUT PVOID Buffer,
-                                    IN ULONG  NumberOfBytesToRead,
-                                    OUT PULONG NumberOfBytesRead)
-{
-   PEPROCESS Process;
-   MEMORY_AREA* MemoryArea;
-   ULONG i;
-   NTSTATUS Status;
-   PULONG CurrentEntry;
-   
-   Status = ObReferenceObjectByHandle(ProcessHandle,
-                                     PROCESS_VM_READ,
-                                     NULL,
-                                     UserMode,
-                                     (PVOID*)(&Process),
-                                     NULL);
-   if (Status != STATUS_SUCCESS)
-     {
-       return(Status);
-     }
-
-   MemoryArea = MmOpenMemoryAreaByAddress(Process,BaseAddress);
-   
-   if (MemoryArea == NULL)
-     {
-       return(STATUS_UNSUCCESSFUL);
-     }
-   if (MemoryArea->Length > NumberOfBytesToRead)
-     {
-       NumberOfBytesToRead = MemoryArea->Length;
-     }
-   
-   *NumberOfBytesRead = NumberOfBytesToRead;
-   
-   for (i=0; i<(NumberOfBytesToRead/PAGESIZE); i++)
-     {
-       CurrentEntry = MmGetPageEntry(Process, BaseAddress + (i*PAGESIZE));
-       RtlCopyMemory(Buffer + (i*PAGESIZE),
-                     (PVOID)physical_to_linear(PAGE_MASK(*CurrentEntry)),
-                     PAGESIZE);
-       
-     }
-   return(STATUS_SUCCESS);
-}
 
-NTSTATUS STDCALL NtUnlockVirtualMemory(HANDLE ProcessHandle,
-                                      PVOID BaseAddress,
-                                      ULONG  NumberOfBytesToUnlock,
-                                      PULONG NumberOfBytesUnlocked OPTIONAL)
+/* FUNCTION:
+ * Called from EngUnsecureMem (subsys\win32k\eng\mem.c)
+ * @unimplemented
+ */
+VOID STDCALL
+MmUnsecureVirtualMemory(PVOID SecureMem)
 {
-   return(ZwUnlockVirtualMemory(ProcessHandle,
-                               BaseAddress,
-                               NumberOfBytesToUnlock,
-                               NumberOfBytesUnlocked));
-}
+   if (NULL == SecureMem)
+   {
+      return;
+   }
 
-NTSTATUS STDCALL ZwUnlockVirtualMemory(HANDLE ProcessHandle,
-                                      PVOID BaseAddress,
-                                      ULONG  NumberOfBytesToUnlock,
-                                      PULONG NumberOfBytesUnlocked OPTIONAL)
-{
    UNIMPLEMENTED;
 }
 
-NTSTATUS STDCALL NtWriteVirtualMemory(IN HANDLE ProcessHandle,
-                                     IN PVOID  BaseAddress,
-                                     IN PVOID Buffer,
-                                     IN ULONG NumberOfBytesToWrite,
-                                     OUT PULONG NumberOfBytesWritten)
+
+/*
+ * @implemented
+ */
+VOID STDCALL
+ProbeForRead (IN PVOID Address,
+              IN ULONG Length,
+              IN ULONG Alignment)
 {
-   return(ZwWriteVirtualMemory(ProcessHandle,
-                              BaseAddress,
-                              Buffer,
-                              NumberOfBytesToWrite,
-                              NumberOfBytesWritten));
+   ASSERT(Alignment ==1 || Alignment == 2 || Alignment == 4 || Alignment == 8);
+
+   if (Length == 0)
+      return;
+
+   if (((ULONG_PTR)Address & (Alignment - 1)) != 0)
+   {
+      ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT);
+   }
+   else if ((ULONG_PTR)Address + Length < (ULONG_PTR)Address ||
+            (ULONG_PTR)Address + Length > (ULONG_PTR)MmUserProbeAddress)
+   {
+      ExRaiseStatus (STATUS_ACCESS_VIOLATION);
+   }
 }
 
-NTSTATUS STDCALL ZwWriteVirtualMemory(IN HANDLE ProcessHandle,
-                                     IN PVOID BaseAddress,
-                                     IN PVOID Buffer,
-                                     IN ULONG NumberOfBytesToWrite,
-                                     OUT PULONG NumberOfBytesWritten)
+
+/*
+ * @implemented
+ */
+VOID STDCALL
+ProbeForWrite (IN PVOID Address,
+               IN ULONG Length,
+               IN ULONG Alignment)
 {
-   PEPROCESS Process;
-   MEMORY_AREA* MemoryArea;
+   PULONG Ptr;
+   ULONG x;
    ULONG i;
-   NTSTATUS Status;
-   PULONG CurrentEntry;
-   
-   Status = ObReferenceObjectByHandle(ProcessHandle,
-                                     PROCESS_VM_WRITE,
-                                     NULL,
-                                     UserMode,
-                                     (PVOID*)(&Process),
-                                     NULL);
-   if (Status != STATUS_SUCCESS)
-     {
-       return(Status);
-     }
-
-   MemoryArea = MmOpenMemoryAreaByAddress(Process,BaseAddress);
-   
-   if (MemoryArea == NULL)
-     {
-       return(STATUS_UNSUCCESSFUL);
-     }
-   if (MemoryArea->Length > NumberOfBytesToWrite)
-     {
-       NumberOfBytesToWrite = MemoryArea->Length;
-     }
-   
-   *NumberOfBytesWritten = NumberOfBytesToWrite;
-   
-   for (i=0; i<(NumberOfBytesToWrite/PAGESIZE); i++)
-     {
-       CurrentEntry = MmGetPageEntry(Process, BaseAddress + (i*PAGESIZE));
-       RtlCopyMemory((PVOID)physical_to_linear(PAGE_MASK(*CurrentEntry)),
-                     Buffer + (i*PAGESIZE),
-                     PAGESIZE);
-       
-     }
-   return(STATUS_SUCCESS);
+
+   ASSERT(Alignment ==1 || Alignment == 2 || Alignment == 4 || Alignment == 8);
+
+   if (Length == 0)
+      return;
+
+   if (((ULONG_PTR)Address & (Alignment - 1)) != 0)
+   {
+      ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT);
+   }
+   else if ((ULONG_PTR)Address + Length < (ULONG_PTR)Address ||
+            (ULONG_PTR)Address + Length > (ULONG_PTR)MmUserProbeAddress)
+   {
+      ExRaiseStatus (STATUS_ACCESS_VIOLATION);
+   }
+
+   /* Check for accessible pages */
+   for (i = 0; i < Length; i += PAGE_SIZE)
+   {
+      Ptr = (PULONG)(((ULONG_PTR)Address & ~(PAGE_SIZE - 1)) + i);
+      x = *Ptr;
+      *Ptr = x;
+   }
 }
 
+/* EOF */