- Set the correct type and state in MiQueryVirtualMemory.
[reactos.git] / reactos / ntoskrnl / mm / virtual.c
index c4fd406..b2d9f85 100644 (file)
-/* $Id: virtual.c,v 1.59 2002/06/04 15:26:57 dwelch Exp $
+/* $Id$
  *
- * COPYRIGHT:   See COPYING in the top directory
- * PROJECT:     ReactOS kernel
- * FILE:        ntoskrnl/mm/virtual.c
- * PURPOSE:     implementing the Virtualxxx section of the win32 api
- * PROGRAMMER:  David Welch
- * UPDATE HISTORY:
- *              09/4/98: Created
- *              10/6/98: Corrections from Iwan Fatahi (i_fatahi@hotmail.com)
- *              30/9/98: Implemented ZwxxxVirtualMemory functions
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS kernel
+ * FILE:            ntoskrnl/mm/virtual.c
+ * PURPOSE:         Implementing operations on virtual memory.
+ *
+ * PROGRAMMERS:     David Welch
  */
+
 /* INCLUDE *****************************************************************/
 
-#include <ddk/ntddk.h>
-#include <internal/mm.h>
-#include <internal/ob.h>
-#include <internal/io.h>
-#include <internal/ps.h>
-#include <internal/pool.h>
+#include <ntoskrnl.h>
 
 #define NDEBUG
 #include <internal/debug.h>
 
-/* TYPES *********************************************************************/
-
-typedef struct _MM_SEGMENT
-{
-   ULONG Type;
-   ULONG Protect;
-   ULONG Length;
-   LIST_ENTRY SegmentListEntry;
-} MM_SEGMENT, *PMM_SEGMENT;
-
-/* GLOBALS *******************************************************************/
-
-#define TAG_MM_SEGMENT    TAG('M', 'S', 'E', 'G')
-
 /* FUNCTIONS *****************************************************************/
 
-PMM_SEGMENT 
-MmGetSegmentForAddress(PMEMORY_AREA MArea,
-                      PVOID Address,
-                      PVOID* PCurrentAddress)
+NTSTATUS STDCALL
+NtFlushVirtualMemory(IN HANDLE ProcessHandle,
+                     IN PVOID BaseAddress,
+                     IN ULONG NumberOfBytesToFlush,
+                     OUT PULONG NumberOfBytesFlushed OPTIONAL)
 /*
- * FUNCTION: Get the segment corresponding to a particular memory area and
- * address. 
+ * FUNCTION: Flushes virtual memory to file
  * ARGUMENTS:
- *          MArea (IN) = The memory area
- *          Address (IN) = The address to get the segment for
- *          PCurrentAddress (OUT) = The start of the segment
- * RETURNS:
- *          The corresponding segment or NULL if an error occurred
+ *        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
  */
 {
-   PVOID CurrentAddress;
-   PMM_SEGMENT CurrentSegment;
-   PLIST_ENTRY Current;
-   
-   if (Address < MArea->BaseAddress ||
-       Address >= (MArea->BaseAddress + MArea->Length))
-     {
-       KeBugCheck(0);
-       *PCurrentAddress = NULL;
-       return(NULL);
-     }
-   
-   Current = MArea->Data.VirtualMemoryData.SegmentListHead.Flink;
-   CurrentAddress = MArea->BaseAddress;
-   while (Current != &MArea->Data.VirtualMemoryData.SegmentListHead)
-     {
-       CurrentSegment = CONTAINING_RECORD(Current, 
-                                          MM_SEGMENT,
-                                          SegmentListEntry);
-       if (Address >= CurrentAddress &&
-           Address < (CurrentAddress + CurrentSegment->Length))
-         {
-            *PCurrentAddress = CurrentAddress;
-            return(CurrentSegment);
-         }
-       CurrentAddress = CurrentAddress + CurrentSegment->Length;
-       Current = Current->Flink;
-     }
-   KeBugCheck(0);
-   return(NULL);
-}
-
-NTSTATUS 
-MmWritePageVirtualMemory(PMADDRESS_SPACE AddressSpace,
-                        PMEMORY_AREA MArea,
-                        PVOID Address)
-{
-   return(STATUS_UNSUCCESSFUL);
+  /* This should be implemented once we support network filesystems */
+  DPRINT("NtFlushVirtualMemory is UNIMPLEMENTED\n");
+  return(STATUS_SUCCESS);
 }
 
 
-NTSTATUS 
-MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace,
-                      PMEMORY_AREA MemoryArea,
-                      PVOID Address,
-                      PMM_PAGEOP PageOp)
+NTSTATUS STDCALL
+MiLockVirtualMemory(HANDLE ProcessHandle,
+  PVOID BaseAddress,
+  ULONG NumberOfBytesToLock,
+  PULONG NumberOfBytesLocked,
+  PObReferenceObjectByHandle pObReferenceObjectByHandle,
+  PMmCreateMdl pMmCreateMdl,
+  PObDereferenceObject pObDereferenceObject,
+  PMmProbeAndLockPages pMmProbeAndLockPages,
+  PExFreePool pExFreePool)
 {
-   PHYSICAL_ADDRESS PhysicalAddress;
-   BOOL WasDirty;
-   SWAPENTRY SwapEntry;
-   NTSTATUS Status;
-   PMDL Mdl;
-
-   DPRINT("MmPageOutVirtualMemory(Address 0x%.8X) PID %d\n",
-          Address, MemoryArea->Process->UniqueProcessId);
+  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);
+    }
 
-   /*
-    * Paging out code or readonly data is easy.
-    */
-   if ((MemoryArea->Attributes & PAGE_READONLY) ||
-       (MemoryArea->Attributes & PAGE_EXECUTE_READ))
-     {       
-       MmDeleteVirtualMapping(MemoryArea->Process, Address, FALSE,
-                             NULL, &PhysicalAddress);
-       MmDeleteAllRmaps(PhysicalAddress, NULL, NULL);
-       if (MmGetSavedSwapEntryPage(PhysicalAddress) != 0)
-        {
-          DPRINT1("Read-only page was swapped out.\n");
-          KeBugCheck(0);
-        }
-       MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
-       
-       PageOp->Status = STATUS_SUCCESS;
-       KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
-       MmReleasePageOp(PageOp);
-       return(STATUS_SUCCESS);
-     }
+  pMmProbeAndLockPages(Mdl,
+    UserMode,
+    IoWriteAccess);
 
-   /*
-    * Otherwise this is read-write data
-    */
-   MmDisableVirtualMapping(MemoryArea->Process, Address,
-                          &WasDirty, (PULONG)&PhysicalAddress);
-   if (PhysicalAddress.QuadPart == 0)
-     {
-       KeBugCheck(0);
-     }
-   if (!WasDirty)
-     {
-       MmDeleteVirtualMapping(MemoryArea->Process, Address, FALSE, NULL, NULL);
-       MmDeleteAllRmaps(PhysicalAddress, NULL, NULL);
-       if ((SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress)) != 0)
-        {
-          MmCreatePageFileMapping(MemoryArea->Process, Address, SwapEntry);
-          MmSetSavedSwapEntryPage(PhysicalAddress, 0);
-        }
-       MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
-       PageOp->Status = STATUS_SUCCESS;
-       KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
-       MmReleasePageOp(PageOp);
-       return(STATUS_SUCCESS);
-     }
+  pExFreePool(Mdl);
 
-   /*
-    * If necessary, allocate an entry in the paging file for this page
-    */
-   SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress);
-   if (SwapEntry == 0)
-     {
-       SwapEntry = MmAllocSwapPage();
-       if (SwapEntry == 0)
-        {
-          MmEnableVirtualMapping(MemoryArea->Process, Address);
-          PageOp->Status = STATUS_UNSUCCESSFUL;
-          KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
-          MmReleasePageOp(PageOp);
-          return(STATUS_UNSUCCESSFUL);
-        }
-     }
-   
-   /*
-    * Write the page to the pagefile
-    */
-   Mdl = MmCreateMdl(NULL, NULL, PAGESIZE);
-   MmBuildMdlFromPages(Mdl, (PULONG)&PhysicalAddress);
-   Status = MmWriteToSwapPage(SwapEntry, Mdl);
-   if (!NT_SUCCESS(Status))
-     {
-       DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", 
-              Status);
-       MmEnableVirtualMapping(MemoryArea->Process, Address);
-       PageOp->Status = STATUS_UNSUCCESSFUL;
-       KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
-       MmReleasePageOp(PageOp);
-       return(STATUS_UNSUCCESSFUL);
-     }
+  pObDereferenceObject(Process);
 
-   /*
-    * Otherwise we have succeeded, free the page
-    */
-   DPRINT("MM: Swapped out virtual memory page 0x%.8X!\n", PhysicalAddress);
-   MmDeleteVirtualMapping(MemoryArea->Process, Address, FALSE, NULL, NULL);
-   MmCreatePageFileMapping(MemoryArea->Process, Address, SwapEntry);
-   MmDeleteAllRmaps(PhysicalAddress, NULL, NULL);
-   MmSetSavedSwapEntryPage(PhysicalAddress, 0);
-   MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
-   PageOp->Status = STATUS_SUCCESS;
-   KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
-   MmReleasePageOp(PageOp);
-   return(STATUS_SUCCESS);
+  *NumberOfBytesLocked = NumberOfBytesToLock;
+  return(STATUS_SUCCESS);
 }
 
-NTSTATUS
-MmNotPresentFaultVirtualMemory(PMADDRESS_SPACE AddressSpace,
-                              MEMORY_AREA* MemoryArea, 
-                              PVOID Address,
-                              BOOLEAN Locked)
-/*
- * FUNCTION: Move data into memory to satisfy a page not present fault
- * ARGUMENTS:
- *      AddressSpace = Address space within which the fault occurred
- *      MemoryArea = The memory area within which the fault occurred
- *      Address = The absolute address of fault
- * RETURNS: Status
- * NOTES: This function is called with the address space lock held.
- */
-{
-   PHYSICAL_ADDRESS Page;
-   NTSTATUS Status;
-   PMM_SEGMENT Segment;
-   PVOID CurrentAddress;
-   PMM_PAGEOP PageOp;
-   
-   /*
-    * There is a window between taking the page fault and locking the
-    * address space when another thread could load the page so we check
-    * that.
-    */
-   if (MmIsPagePresent(NULL, Address))
-     {
-       if (Locked)
-         {
-           MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
-         }  
-       return(STATUS_SUCCESS);
-     }
-
-   /*
-    * Get the segment corresponding to the virtual address
-    */
-   Segment = MmGetSegmentForAddress(MemoryArea, Address, &CurrentAddress);
-   if (Segment == NULL)
-     {
-       return(STATUS_UNSUCCESSFUL);
-     }
-   if (Segment->Type == MEM_RESERVE)
-     {
-       return(STATUS_UNSUCCESSFUL);
-     }
-
-   /*
-    * Get or create a page operation
-    */
-   PageOp = MmGetPageOp(MemoryArea, (ULONG)PsGetCurrentProcessId(), 
-                       (PVOID)PAGE_ROUND_DOWN(Address), NULL, 0,
-                       MM_PAGEOP_PAGEIN);
-   if (PageOp == NULL)
-     {
-       DPRINT1("MmGetPageOp failed");
-       KeBugCheck(0);
-     }
 
-   /*
-    * Check if someone else is already handling this fault, if so wait
-    * for them
-    */
-   if (PageOp->Thread != PsGetCurrentThread())
-     {
-       MmUnlockAddressSpace(AddressSpace);
-       Status = KeWaitForSingleObject(&PageOp->CompletionEvent,
-                                     0,
-                                     KernelMode,
-                                     FALSE,
-                                     NULL);
-       /*
-       * Check for various strange conditions
-       */
-       if (Status != STATUS_SUCCESS)
-        {
-          DPRINT1("Failed to wait for page op\n");
-          KeBugCheck(0);
-        }
-       if (PageOp->Status == STATUS_PENDING)
-        {
-          DPRINT1("Woke for page op before completion\n");
-          KeBugCheck(0);
-        }
-       /*
-       * If this wasn't a pagein then we need to restart the handling
-       */
-       if (PageOp->OpType != MM_PAGEOP_PAGEIN)
-        {
-           MmLockAddressSpace(AddressSpace);
-          MmReleasePageOp(PageOp);
-          return(STATUS_MM_RESTART_OPERATION);
-        }
-       /*
-       * If the thread handling this fault has failed then we don't retry
-       */
-       if (!NT_SUCCESS(PageOp->Status))
-        {
-           MmLockAddressSpace(AddressSpace);
-          MmReleasePageOp(PageOp);
-          return(Status);
-        }
-       MmLockAddressSpace(AddressSpace);
-       if (Locked)
-        {
-          MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
-        }
-       MmReleasePageOp(PageOp);
-       return(STATUS_SUCCESS);
-     }
-   
-   /*
-    * Try to allocate a page
-    */
-   Status = MmRequestPageMemoryConsumer(MC_USER, FALSE, &Page);
-   if (Status == STATUS_NO_MEMORY)
-     {
-       MmUnlockAddressSpace(AddressSpace);
-       Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
-       MmLockAddressSpace(AddressSpace);
-     }
-
-   /*
-    * Handle swapped out pages.
-    */
-   if (MmIsPageSwapEntry(NULL, Address))
-     {
-       SWAPENTRY SwapEntry;
-       PMDL Mdl;
-
-       MmDeletePageFileMapping(NULL, Address, &SwapEntry);
-       Mdl = MmCreateMdl(NULL, NULL, PAGESIZE);
-       MmBuildMdlFromPages(Mdl, (PULONG)&Page);
-       Status = MmReadFromSwapPage(SwapEntry, Mdl);
-       if (!NT_SUCCESS(Status))
-        {
-          KeBugCheck(0);
-        }
-       MmSetSavedSwapEntryPage(Page, SwapEntry);
-     }
-   
-   /*
-    * Set the page. If we fail because we are out of memory then
-    * try again
-    */
-   Status = MmCreateVirtualMapping(PsGetCurrentProcess(),                    
-                                  Address,
-                                  MemoryArea->Attributes,
-                                  Page,
-                                  FALSE);
-   while (Status == STATUS_NO_MEMORY)
-     {
-       MmUnlockAddressSpace(AddressSpace);
-       Status = MmCreateVirtualMapping(PsGetCurrentProcess(),                
-                                       Address,
-                                       MemoryArea->Attributes,
-                                       Page,
-                                       TRUE);
-       MmLockAddressSpace(AddressSpace);
-     }  
-   if (!NT_SUCCESS(Status))
-     {
-       DPRINT1("MmCreateVirtualMapping failed, not out of memory\n");
-       KeBugCheck(0);
-       return(Status);
-     }
+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,
+    ObfDereferenceObject,
+    MmProbeAndLockPages,
+    ExFreePool);
+}
 
-   /*
-    * Add the page to the process's working set
-    */
-   MmInsertRmap(Page, PsGetCurrentProcess(), (PVOID)PAGE_ROUND_DOWN(Address));
 
-   /*
-    * Finish the operation
-    */
-   if (Locked)
-     {
-       MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
-     }  
-   PageOp->Status = STATUS_SUCCESS;
-   KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
-   MmReleasePageOp(PageOp);
-   return(STATUS_SUCCESS);
-}
+NTSTATUS FASTCALL
+MiQueryVirtualMemory (IN HANDLE ProcessHandle,
+                      IN PVOID Address,
+                      IN CINT VirtualMemoryInformationClass,
+                      OUT PVOID VirtualMemoryInformation,
+                      IN ULONG Length,
+                      OUT PULONG ResultLength)
+{
+   NTSTATUS Status;
+   PEPROCESS Process;
+   MEMORY_AREA* MemoryArea;
+   PMADDRESS_SPACE AddressSpace;
 
-VOID STATIC
-MmModifyAttributes(PMADDRESS_SPACE AddressSpace,
-                  PVOID BaseAddress,
-                  ULONG RegionSize,
-                  ULONG OldType,
-                  ULONG OldProtect,
-                  ULONG NewType,
-                  ULONG NewProtect)
-/*
- * FUNCTION: Modify the attributes of a memory region
- */
-{      
-  /*
-   * If we are switching a previously committed region to reserved then
-   * free any allocated pages within the region
-   */
-  if (NewType == MEM_RESERVE && OldType == MEM_COMMIT)
-    {
-      ULONG i;
-      
-      for (i=0; i <= (RegionSize/PAGESIZE); i++)
-       {
-         LARGE_INTEGER PhysicalAddr;
-
-         if (MmIsPageSwapEntry(AddressSpace->Process,
-                               BaseAddress + (i * PAGESIZE)))
-           {
-             SWAPENTRY SwapEntry;
-             
-             MmDeletePageFileMapping(AddressSpace->Process,
-                                     BaseAddress + (i * PAGESIZE),
-                                     &SwapEntry);
-             MmFreeSwapPage(SwapEntry);
+   if (Address < MmSystemRangeStart)
+   {
+      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
+   {
+      AddressSpace = MmGetKernelAddressSpace();
+   }
+   MmLockAddressSpace(AddressSpace);
+   MemoryArea = MmLocateMemoryAreaByAddress(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
+            else
            {
-             PhysicalAddr = MmGetPhysicalAddress(BaseAddress + (i*PAGESIZE));
-             MmDeleteVirtualMapping(AddressSpace->Process,
-                                    BaseAddress + (i*PAGESIZE),
-                                    FALSE, NULL, NULL);
-             if (PhysicalAddr.QuadPart != 0)
-               {
-                 MmDeleteRmap(PhysicalAddr, AddressSpace->Process,
-                              BaseAddress + (i * PAGESIZE));
-                 MmDereferencePage(PhysicalAddr);
-               }
+              switch(MemoryArea->Type)
+              {
+                 case MEMORY_AREA_VIRTUAL_MEMORY:
+                  case MEMORY_AREA_PEB_OR_TEB:
+                     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 = MEM_PRIVATE;
+                     Info->State = MEM_RESERVE;
+                    Info->Protect = MemoryArea->Attributes;
+                    Info->AllocationProtect = MemoryArea->Attributes;
+                    Info->BaseAddress = MemoryArea->StartingAddress;
+                    Info->AllocationBase = MemoryArea->StartingAddress;
+                    Info->RegionSize = (ULONG_PTR)MemoryArea->EndingAddress -
+                                       (ULONG_PTR)MemoryArea->StartingAddress;
+                     Status = STATUS_SUCCESS;
+                     *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
+                    break;
+                 case MEMORY_AREA_SHARED_DATA:
+                    Info->Type = MEM_PRIVATE;
+                     Info->State = MEM_COMMIT;
+                    Info->Protect = MemoryArea->Attributes;
+                    Info->AllocationProtect = MemoryArea->Attributes;
+                    Info->BaseAddress = MemoryArea->StartingAddress;
+                    Info->AllocationBase = MemoryArea->StartingAddress;
+                    Info->RegionSize = (ULONG_PTR)MemoryArea->EndingAddress -
+                                       (ULONG_PTR)MemoryArea->StartingAddress;
+                     Status = STATUS_SUCCESS;
+                     *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
+                    break;
+                 case MEMORY_AREA_SYSTEM:
+                    Info->Type = 0;
+                     Info->State = MEM_COMMIT;
+                    Info->Protect = MemoryArea->Attributes;
+                    Info->AllocationProtect = MemoryArea->Attributes;
+                    Info->BaseAddress = MemoryArea->StartingAddress;
+                    Info->AllocationBase = MemoryArea->StartingAddress;
+                    Info->RegionSize = (ULONG_PTR)MemoryArea->EndingAddress -
+                                       (ULONG_PTR)MemoryArea->StartingAddress;
+                     Status = STATUS_SUCCESS;
+                     *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
+                    break;
+                 case MEMORY_AREA_KERNEL_STACK:
+                    Info->Type = 0;
+                     Info->State = MEM_COMMIT;
+                    Info->Protect = MemoryArea->Attributes;
+                    Info->AllocationProtect = MemoryArea->Attributes;
+                    Info->BaseAddress = MemoryArea->StartingAddress;
+                    Info->AllocationBase = MemoryArea->StartingAddress;
+                    Info->RegionSize = (ULONG_PTR)MemoryArea->EndingAddress -
+                                       (ULONG_PTR)MemoryArea->StartingAddress;
+                     Status = STATUS_SUCCESS;
+                     *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
+                    break;
+                  case MEMORY_AREA_PAGED_POOL:
+                    Info->Type = 0;
+                     Info->State = MEM_COMMIT;
+                    Info->Protect = MemoryArea->Attributes;
+                    Info->AllocationProtect = MemoryArea->Attributes;
+                    Info->BaseAddress = MemoryArea->StartingAddress;
+                    Info->AllocationBase = MemoryArea->StartingAddress;
+                    Info->RegionSize = (ULONG_PTR)MemoryArea->EndingAddress -
+                                       (ULONG_PTR)MemoryArea->StartingAddress;
+                     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;
+         }
 
-  /*
-   * If we are changing the protection attributes of a committed region then
-   * alter the attributes for any allocated pages within the region
-   */
-  if (NewType == MEM_COMMIT && OldType == MEM_COMMIT && 
-      OldProtect != NewProtect)
-    {
-      ULONG i;
-   
-      for (i=0; i <= (RegionSize/PAGESIZE); i++)
-       {
-         if (MmIsPagePresent(AddressSpace->Process, 
-                             BaseAddress + (i*PAGESIZE)))
-           {
-             MmSetPageProtect(AddressSpace->Process,
-                              BaseAddress + (i*PAGESIZE), 
-                              NewProtect);
-           }
-       }
-    }
+      default:
+         {
+            Status = STATUS_INVALID_INFO_CLASS;
+            *ResultLength = 0;
+            break;
+         }
+   }
+
+   MmUnlockAddressSpace(AddressSpace);
+   if (Address < MmSystemRangeStart)
+   {
+      ObDereferenceObject(Process);
+   }
+
+   return Status;
 }
 
-VOID STATIC 
-InsertAfterEntry(PLIST_ENTRY Previous,
-                PLIST_ENTRY Entry)
-/*
- * FUNCTION: Insert a list entry after another entry in the list
+/* (tMk 2004.II.4)
+ * FUNCTION:
+ * Called from VirtualQueryEx (lib\kernel32\mem\virtual.c)
+ *
  */
+NTSTATUS STDCALL
+NtQueryVirtualMemory (IN HANDLE ProcessHandle,
+                      IN PVOID Address,
+                      IN MEMORY_INFORMATION_CLASS VirtualMemoryInformationClass,
+                      OUT PVOID VirtualMemoryInformation,
+                      IN ULONG Length,
+                      OUT PULONG UnsafeResultLength)
 {
-   Previous->Flink->Blink = Entry;
-   
-   Entry->Flink = Previous->Flink;
-   Entry->Blink = Previous;
-   
-   Previous->Flink = Entry;
-}
+   NTSTATUS Status = STATUS_SUCCESS;
+   ULONG ResultLength = 0;
+   KPROCESSOR_MODE PreviousMode;
+   union
+   {
+      MEMORY_BASIC_INFORMATION BasicInfo;
+   }
+   VirtualMemoryInfo;
 
-#if 0
-VOID STATIC
-MmDumpSegmentsMemoryArea(PMEMORY_AREA MemoryArea)
-{
-   PVOID CurrentAddress;
-   PLIST_ENTRY CurrentEntry;
-   PMM_SEGMENT CurrentSegment;
-   PLIST_ENTRY ListHead;
-   
-   CurrentEntry = MemoryArea->Data.VirtualMemoryData.SegmentListHead.Flink;
-   ListHead = &MemoryArea->Data.VirtualMemoryData.SegmentListHead;
+   DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, "
+          "VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, "
+          "Length %lu ResultLength %x)\n",ProcessHandle,Address,
+          VirtualMemoryInformationClass,VirtualMemoryInformation,
+          Length,ResultLength);
+
+   PreviousMode =  ExGetPreviousMode();
    
-   CurrentAddress = MemoryArea->BaseAddress;
-   while (CurrentEntry != ListHead)
+   if (PreviousMode != KernelMode && UnsafeResultLength != NULL)
      {
-       CurrentSegment = CONTAINING_RECORD(CurrentEntry,
-                                          MM_SEGMENT,
-                                          SegmentListEntry);
-       
-       DbgPrint("0x%x 0x%x %d %d\n", 
-                CurrentAddress,
-                CurrentSegment->Length,
-                CurrentSegment->Type,
-                CurrentSegment->Protect);
-       
-       CurrentAddress = CurrentAddress + CurrentSegment->Length;
-       CurrentEntry = CurrentEntry->Flink;
+       _SEH_TRY
+         {
+           ProbeForWriteUlong(UnsafeResultLength);
+         }
+       _SEH_HANDLE
+         {
+           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)
+        {
+          _SEH_TRY
+            {
+              if (ResultLength > 0)
+                {
+                  ProbeForWrite(VirtualMemoryInformation,
+                                ResultLength,
+                                1);
+                  RtlCopyMemory(VirtualMemoryInformation,
+                                &VirtualMemoryInfo,
+                                ResultLength);
+                }
+              if (UnsafeResultLength != NULL)
+                {
+                  *UnsafeResultLength = ResultLength;
+                }
+            }
+          _SEH_HANDLE
+            {
+              Status = _SEH_GetExceptionCode();
+            }
+          _SEH_END;
+        }
+      else
+        {
+          if (ResultLength > 0)
+            {
+              RtlCopyMemory(VirtualMemoryInformation,
+                            &VirtualMemoryInfo,
+                            ResultLength);
+            }
+
+          if (UnsafeResultLength != NULL)
+            {
+              *UnsafeResultLength = ResultLength;
+            }
+        }
+   }
+
+   return(Status);
 }
-#endif
-
-NTSTATUS 
-MmSplitSegment(PMADDRESS_SPACE AddressSpace,
-              PMEMORY_AREA MemoryArea,
-              PVOID RegionAddress,
-              ULONG RegionLength,
-              ULONG Type,
-              ULONG Protect,
-              PMM_SEGMENT FirstSegment,
-              PVOID FirstAddress)
-/*
- * FUNCTION: Split a memory segment internally 
- */
+
+
+NTSTATUS STDCALL
+MiProtectVirtualMemory(IN PEPROCESS Process,
+                       IN OUT PVOID *BaseAddress,
+                       IN OUT PULONG NumberOfBytesToProtect,
+                       IN ULONG NewAccessProtection,
+                       OUT PULONG OldAccessProtection  OPTIONAL)
 {
-   PMM_SEGMENT NewTopSegment;
-   PMM_SEGMENT RegionSegment;
-   ULONG OldType;
-   ULONG OldProtect;
-   ULONG OldLength;
-   
-   DPRINT("MmSplitSegment()\n");
-   /*
-    * Save the type and protection and length of the current segment
-    */
-   OldType = FirstSegment->Type;
-   OldProtect = FirstSegment->Protect;
-   OldLength = FirstSegment->Length;
+   PMEMORY_AREA MemoryArea;
+   PMADDRESS_SPACE AddressSpace;
+   ULONG OldAccessProtection_;
+   NTSTATUS Status;
 
-   /*
-    * If the segment is already of the right type and protection then
-    * there is nothing to do.
-    */
-   if (FirstSegment->Type == Type && FirstSegment->Protect == Protect)
-     {
-       return(STATUS_SUCCESS);
-     }
-   
-   /*
-    * Allocate the segment we might need here because if the allocation
-    * fails below it will be difficult to undo what we've done already.
-    */
-   NewTopSegment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SEGMENT),
-                                        TAG_MM_SEGMENT);
-   if (NewTopSegment == NULL)
-     {
-       return(STATUS_NO_MEMORY);
-     }
-   
-   if (FirstAddress < RegionAddress)
-     {
-       /*
-        * If the region to be affected starts at a higher address than
-        * the current segment then create a new segment for the
-        * affected portion
-        */     
-       RegionSegment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SEGMENT),
-                                             TAG_MM_SEGMENT);
-       if (RegionSegment == NULL)
-         {
-            ExFreePool(NewTopSegment);
-            return(STATUS_NO_MEMORY);
-         }
-       
-       RegionSegment->Type = Type;
-       RegionSegment->Protect = Protect;
-       RegionSegment->Length = RegionLength;
-       
-       FirstSegment->Length = RegionAddress - FirstAddress;
-
-       InsertAfterEntry(&FirstSegment->SegmentListEntry,
-                        &RegionSegment->SegmentListEntry);
-     }
-   else
-     {
-       /*
-        * Otherwise just set its type and protection and length
-        */
-       
-       FirstSegment->Type = Type;
-       FirstSegment->Protect = Protect;
-       FirstSegment->Length = RegionLength;
-       
-        RegionSegment = FirstSegment;
-     }
-   
-   if ((FirstAddress + OldLength) > (RegionAddress + RegionLength))
-     {
-       /*
-        * If the top of the current segment extends after the affected
-        * region then create a segment for the unaffected portion
-        */
-       
-       NewTopSegment->Type = OldType;
-       NewTopSegment->Protect = OldProtect;
-       NewTopSegment->Length = (FirstAddress + OldLength) -
-         (RegionAddress + RegionLength);
-       
-       InsertAfterEntry(&RegionSegment->SegmentListEntry,
-                        &NewTopSegment->SegmentListEntry);
-     }
+   *NumberOfBytesToProtect =
+      PAGE_ROUND_UP((*BaseAddress) + (*NumberOfBytesToProtect)) -
+      PAGE_ROUND_DOWN(*BaseAddress);
+   *BaseAddress = (PVOID)PAGE_ROUND_DOWN(*BaseAddress);
+
+   AddressSpace = &Process->AddressSpace;
+
+   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
-     {
-       ExFreePool(NewTopSegment);
-       NewTopSegment = NULL;
-     }
-   
-   /*
-    * Actually set the type and protection of the affected region
-    */
-   MmModifyAttributes(AddressSpace, 
-                     RegionAddress, 
-                     RegionLength, 
-                     OldType, 
-                     OldProtect, 
-                     Type, 
-                     Protect);
-   return(STATUS_SUCCESS);
+   {
+      /* FIXME: Should we return failure or success in this case? */
+      Status = STATUS_CONFLICTING_ADDRESSES;
+   }
+
+   MmUnlockAddressSpace(AddressSpace);
+
+   return Status;
 }
 
-NTSTATUS MmGatherSegment(PMADDRESS_SPACE AddressSpace,
-                        PMEMORY_AREA MemoryArea,
-                        PVOID RegionAddress,
-                        ULONG RegionLength,
-                        ULONG Type,
-                        ULONG Protect,
-                        PMM_SEGMENT FirstSegment,
-                        PVOID FirstAddress)
-/*
- * FUNCTION: Do a virtual memory operation that will effect several
- * memory segments. 
- * ARGUMENTS:
- *          AddressSpace (IN) = Address space to affect
- *          MemoryArea (IN) = Memory area to affect
- *          BaseAddress (IN) = Base address of the region to affect
- *          RegionSize (IN) = Size of the region to affect
- *          Type (IN) = New type of the region
- *          Protect (IN) = New protection of the region
- *          CurrentSegment (IN) = First segment intersecting with the region
- *          CurrentAddress (IN) = Start address of the first segment
- *                                interesting with the region
- * RETURNS: 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)
 {
-   PMM_SEGMENT RegionSegment;
-   PVOID CurrentAddress;
-   ULONG RemainingLength;
-   PLIST_ENTRY CurrentEntry;
-   PLIST_ENTRY ListHead;
-   PMM_SEGMENT CurrentSegment;
+   PEPROCESS Process;
+   ULONG OldAccessProtection;
+   PVOID BaseAddress = NULL;
+   ULONG NumberOfBytesToProtect = 0;
+   KPROCESSOR_MODE PreviousMode;
+   NTSTATUS Status = STATUS_SUCCESS;
    
-   if (FirstAddress < RegionAddress)
+   PreviousMode = ExGetPreviousMode();
+   
+   if (PreviousMode != KernelMode)
      {
-       /*
-        * If a portion of the first segment is not covered by the region then
-        * we need to split it into two segments
-        */
-       
-       RegionSegment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SEGMENT),
-                                             TAG_MM_SEGMENT);
-       if (RegionSegment == NULL)
-         {
-            return(STATUS_NO_MEMORY);
-         }
-       
-       RegionSegment->Type = Type;
-       RegionSegment->Protect = Protect;
-       RegionSegment->Length = (FirstAddress + FirstSegment->Length) -
-         RegionAddress;
-       
-       FirstSegment->Length = RegionAddress - FirstAddress;
-
-       InsertAfterEntry(&FirstSegment->SegmentListEntry,
-                        &RegionSegment->SegmentListEntry);
-       
-       MmModifyAttributes(AddressSpace, 
-                          RegionAddress, 
-                          RegionSegment->Length,
-                          FirstSegment->Type, 
-                          FirstSegment->Protect, 
-                          Type, 
-                          Protect);
-       
-       CurrentAddress = FirstAddress + FirstSegment->Length +
-         RegionSegment->Length;
+       _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
      {
-       /*
-        *  Otherwise just change the attributes of the segment
-        */
-       
-       ULONG OldType;
-       ULONG OldProtect;
-       
-       OldType = FirstSegment->Type;
-       OldProtect = FirstSegment->Protect;
-       
-       FirstSegment->Type = Type;
-       FirstSegment->Protect = Protect;
-       
-       RegionSegment = FirstSegment;
-       
-       MmModifyAttributes(AddressSpace, 
-                          RegionAddress, 
-                          FirstSegment->Length,
-                          OldType, 
-                          OldProtect, 
-                          Type, 
-                          Protect);
-       
-       CurrentAddress = FirstAddress + RegionSegment->Length;
+       BaseAddress = *UnsafeBaseAddress;
+       NumberOfBytesToProtect = *UnsafeNumberOfBytesToProtect;
      }
-  
-   /*
-    * Change the attributes of all the complete segments lying inside the
-    * affected region
-    */   
-   RemainingLength = RegionLength - RegionSegment->Length;
-   CurrentEntry = RegionSegment->SegmentListEntry.Flink;
-   CurrentSegment = CONTAINING_RECORD(CurrentEntry,
-                                     MM_SEGMENT,
-                                     SegmentListEntry);
-   ListHead = &MemoryArea->Data.VirtualMemoryData.SegmentListHead;
-   
-   while (CurrentEntry != ListHead && RemainingLength > 0)
-     {
-       ULONG OldType;
-       ULONG OldProtect;
-       ULONG OldLength;
-                       
-       /*
-        * If this segment will not be completely covered by the
-        * affected region then break
-        */
-       if (CurrentSegment->Length > RemainingLength)
-         {
-            break;
-         }
-       
-       OldType = CurrentSegment->Type;
-       OldProtect = CurrentSegment->Protect;
-       OldLength = CurrentSegment->Length;
-       
-       /*
-        * Extend the length of the previous segment to cover this one
-        */
-       RegionSegment->Length = RegionSegment->Length + OldLength;
-       RemainingLength = RemainingLength - OldLength;
-       CurrentAddress = CurrentAddress + OldLength;
-       CurrentEntry = CurrentEntry->Flink;
-       
-       /*
-        * Remove the current segment from the list
-        */
-       RemoveEntryList(&CurrentSegment->SegmentListEntry);
-       ExFreePool(CurrentSegment);
-       
-       MmModifyAttributes(AddressSpace, 
-                          CurrentAddress, 
-                          OldLength,
-                          OldType, 
-                          OldProtect, 
-                          Type, 
-                          Protect);
-       
-       CurrentSegment = CONTAINING_RECORD(CurrentEntry,
-                                          MM_SEGMENT,
-                                          SegmentListEntry);
-     }
-   
-   /*
-    * If we've run off the top of the memory area then bug check
-    */
-   if (CurrentEntry == ListHead && RemainingLength > 0)
+
+   if ((ULONG_PTR)BaseAddress + NumberOfBytesToProtect - 1 < (ULONG_PTR)BaseAddress ||
+       (ULONG_PTR)BaseAddress + NumberOfBytesToProtect - 1 >= MmUserProbeAddress)
      {
-       KeBugCheck(0);
+       /* Don't allow to change the protection of a kernel mode address */
+       return STATUS_INVALID_PARAMETER_2;
      }
-   
-   /*
-    * We've only affected a portion of a segment then split it in two
+
+   /* (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 (RemainingLength > 0)
-     {
-       CurrentSegment->Length = CurrentSegment->Length - RemainingLength;
-
-       RegionSegment->Length = RegionSegment->Length + RemainingLength;
-       
-       MmModifyAttributes(AddressSpace, 
-                          CurrentAddress, 
-                          RemainingLength,
-                          CurrentSegment->Type, 
-                          CurrentSegment->Protect, 
-                          Type, 
-                          Protect);
-     }
-   
-   return(STATUS_SUCCESS);
-}
+   if(UnsafeOldAccessProtection == NULL)
+   {
+      return(STATUS_INVALID_PARAMETER);
+   }
 
-NTSTATUS MmComplexVirtualMemoryOperation(PMADDRESS_SPACE AddressSpace,
-                                        PMEMORY_AREA MemoryArea,
-                                        PVOID BaseAddress,
-                                        ULONG RegionSize,
-                                        ULONG Type,
-                                        ULONG Protect)
-{
-   PMM_SEGMENT CurrentSegment;
-   PVOID CurrentAddress;
-   
-   CurrentSegment = MmGetSegmentForAddress(MemoryArea, 
-                                          BaseAddress, 
-                                          &CurrentAddress);
-   if (CurrentSegment == NULL)
-     {
-       KeBugCheck(0);
-     }
-   
-   if (BaseAddress >= CurrentAddress &&
-       (BaseAddress + RegionSize) <= (CurrentAddress + CurrentSegment->Length))
+   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)
      {
-       return((MmSplitSegment(AddressSpace,
-                              MemoryArea,
-                              BaseAddress,
-                              RegionSize,
-                              Type,
-                              Protect,
-                              CurrentSegment,
-                              CurrentAddress)));
+       _SEH_TRY
+         {
+           *UnsafeOldAccessProtection = OldAccessProtection;
+           *UnsafeBaseAddress = BaseAddress;
+           *UnsafeNumberOfBytesToProtect = NumberOfBytesToProtect;
+         }
+       _SEH_HANDLE
+         {
+           Status = _SEH_GetExceptionCode();
+         }
+       _SEH_END;
      }
    else
      {
-       return((MmGatherSegment(AddressSpace,
-                               MemoryArea,
-                               BaseAddress,
-                               RegionSize,
-                               Type,
-                               Protect,
-                               CurrentSegment,
-                               CurrentAddress)));
+       *UnsafeOldAccessProtection = OldAccessProtection;
+       *UnsafeBaseAddress = BaseAddress;
+       *UnsafeNumberOfBytesToProtect = NumberOfBytesToProtect;
      }
+
+   return(Status);
 }
 
 
-NTSTATUS STDCALL
-NtAllocateVirtualMemory(IN     HANDLE  ProcessHandle,
-                       IN OUT  PVOID*  UBaseAddress,
-                       IN      ULONG   ZeroBits,
-                       IN OUT  PULONG  URegionSize,
-                       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 a combination of 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;
-   PMADDRESS_SPACE AddressSpace;
-   PMM_SEGMENT Segment;
-   PVOID BaseAddress;
-   ULONG RegionSize;
-   PVOID PBaseAddress;
-   ULONG PRegionSize;
-
-   DPRINT("NtAllocateVirtualMemory(*UBaseAddress %x, "
-         "ZeroBits %d, *URegionSize %x, AllocationType %x, Protect %x)\n",
-         *UBaseAddress,ZeroBits,*URegionSize,AllocationType,
-         Protect);
-   
-   /*
-    * Check the validity of the parameters
-    */
-   if ((Protect & PAGE_FLAGS_VALID_FROM_USER_MODE) != Protect)
-     {
-       return(STATUS_INVALID_PAGE_PROTECTION);
-     }
-   if ((AllocationType & (MEM_COMMIT | MEM_RESERVE)) == 0)
+   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)
      {
-       return(STATUS_INVALID_PARAMETER);
+       /* Don't allow to read from kernel space */
+       return STATUS_ACCESS_VIOLATION;
      }
-   if (((AllocationType & (MEM_COMMIT | MEM_RESERVE)) == MEM_COMMIT) &&
-       (*UBaseAddress == 0))
+
+   PreviousMode = ExGetPreviousMode();
+
+   if (PreviousMode != KernelMode)
      {
-       /* Fix for badly behaved vc applications. */
-       AllocationType |= MEM_RESERVE;
+       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;
+         }
      }
-   
-   PBaseAddress = *UBaseAddress;
-   PRegionSize = *URegionSize;
-   
 
-   BaseAddress = (PVOID)PAGE_ROUND_DOWN(PBaseAddress);
-   RegionSize = PAGE_ROUND_UP(PBaseAddress + PRegionSize) -
-     PAGE_ROUND_DOWN(PBaseAddress);
-   
    Status = ObReferenceObjectByHandle(ProcessHandle,
-                                     PROCESS_VM_OPERATION,
-                                     NULL,
-                                     UserMode,
-                                     (PVOID*)(&Process),
-                                     NULL);
+                                      PROCESS_VM_READ,
+                                      NULL,
+                                      PreviousMode,
+                                      (PVOID*)(&Process),
+                                      NULL);
    if (!NT_SUCCESS(Status))
+   {
+      return(Status);
+   }
+
+   CurrentProcess = PsGetCurrentProcess();
+
+   if(PreviousMode != KernelMode)
+   {
+     _SEH_TRY
      {
-       DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
-       return(Status);
+       if(NumberOfBytesRead != NULL)
+       {
+         ProbeForWriteUlong(NumberOfBytesRead);
+       }
      }
-   
-   Type = (AllocationType & MEM_COMMIT) ? MEM_COMMIT : MEM_RESERVE;
-   DPRINT("Type %x\n", Type);
-   
-   AddressSpace = &Process->AddressSpace;
-   MmLockAddressSpace(AddressSpace);
-   
-   if ((PBaseAddress != 0) &&
-       ((AllocationType & (MEM_COMMIT | MEM_RESERVE)) == MEM_COMMIT))
+     _SEH_HANDLE
      {
-       MemoryArea = MmOpenMemoryAreaByAddress(&Process->AddressSpace,
-                                              BaseAddress);
-       
-       if (MemoryArea != NULL &&
-           MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY &&
-           MemoryArea->Length >= RegionSize)
-         {
-            Status = MmComplexVirtualMemoryOperation(AddressSpace,
-                                                     MemoryArea,
-                                                     BaseAddress,
-                                                     RegionSize,
-                                                     Type,
-                                                     Protect);
-            /* FIXME: Reserve/dereserve swap pages */
-            MmUnlockAddressSpace(AddressSpace);
-            ObDereferenceObject(Process);
-            DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
-            return(Status);
-         }
-       else if (MemoryArea != NULL)
-         {
-            MmUnlockAddressSpace(AddressSpace);
-            ObDereferenceObject(Process);
-            return(STATUS_UNSUCCESSFUL);
-         }
+       Status = _SEH_GetExceptionCode();
      }
-   
-   Segment = ExAllocatePoolWithTag(NonPagedPool,
-                                  sizeof(MM_SEGMENT),
-                                  TAG_MM_SEGMENT);
-   if (Segment == NULL)
+     _SEH_END;
+
+     if(!NT_SUCCESS(Status))
      {
-       MmUnlockAddressSpace(AddressSpace);
-       ObDereferenceObject(Process);
-       return(STATUS_UNSUCCESSFUL);
+       return Status;
      }
-   
-   Status = MmCreateMemoryArea(Process,
-                              &Process->AddressSpace,
-                              MEMORY_AREA_VIRTUAL_MEMORY,
-                              &BaseAddress,
-                              RegionSize,
-                              Protect,
-                              &MemoryArea,
-                              PBaseAddress != 0);
-   
-   if (!NT_SUCCESS(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
      {
-       MmUnlockAddressSpace(AddressSpace);
-       ObDereferenceObject(Process);
-       DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
-       return(Status);
+       *NumberOfBytesRead = NumberOfBytesToRead;
      }
-   
-   InitializeListHead(&MemoryArea->Data.VirtualMemoryData.SegmentListHead);
-   
-   Segment->Type = Type;
-   Segment->Protect = Protect;
-   Segment->Length = RegionSize;
-   InsertTailList(&MemoryArea->Data.VirtualMemoryData.SegmentListHead,
-                 &Segment->SegmentListEntry);
-   
-   if ((AllocationType & MEM_COMMIT) &&
-       ((Protect & PAGE_READWRITE) ||
-       (Protect & PAGE_EXECUTE_READWRITE)))
+     _SEH_HANDLE
      {
-       MmReserveSwapPages(RegionSize);
+       Status = _SEH_GetExceptionCode();
      }
-   
-   *UBaseAddress = BaseAddress;
-   *URegionSize = RegionSize;
-   DPRINT("*UBaseAddress %x  *URegionSize %x\n", BaseAddress, RegionSize);
-   
-   MmUnlockAddressSpace(AddressSpace);
-   ObDereferenceObject(Process);
-   return(STATUS_SUCCESS);
-}
-
-
-NTSTATUS STDCALL 
-NtFlushVirtualMemory(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 
- */
-{
-       UNIMPLEMENTED;
-}
-
-VOID STATIC
-MmFreeVirtualMemoryPage(PVOID Context,
-                       MEMORY_AREA* MemoryArea,
-                       PVOID Address,
-                       PHYSICAL_ADDRESS PhysicalAddr,
-                       SWAPENTRY SwapEntry,
-                       BOOLEAN Dirty)
-{
-  PEPROCESS Process = (PEPROCESS)Context;
-  
-  if (PhysicalAddr.QuadPart != 0)
-    {
-      MmDeleteRmap(PhysicalAddr, Process, Address);
-      MmDereferencePage(PhysicalAddr);
-    }
-  else if (SwapEntry != 0)
-    {
-      MmFreeSwapPage(SwapEntry);
-    }
-}
+     _SEH_END;
+   }
 
-VOID
-MmFreeVirtualMemory(PEPROCESS Process,
-                   PMEMORY_AREA MemoryArea)
-{
-  PLIST_ENTRY current_entry;
-  PMM_SEGMENT current;
-  
-  DPRINT("MmFreeVirtualMemory(Process %p  MemoryArea %p)\n", Process, MemoryArea);
-  
-  current_entry = MemoryArea->Data.VirtualMemoryData.SegmentListHead.Flink;
-  while (current_entry != &MemoryArea->Data.VirtualMemoryData.SegmentListHead)
-    {
-      current = CONTAINING_RECORD(current_entry, MM_SEGMENT, SegmentListEntry);
-      current_entry = current_entry->Flink;
-      DPRINT("ExFreePool(%p)\n", current);
-      ExFreePool(current);
-    }
-
-  MmFreeMemoryArea(&Process->AddressSpace,
-                  MemoryArea->BaseAddress,
-                  0,
-                  MmFreeVirtualMemoryPage,
-                  (PVOID)Process);
+   return(Status);
 }
 
-NTSTATUS STDCALL 
-NtFreeVirtualMemory(IN HANDLE  ProcessHandle,
-                   IN  PVOID*  PBaseAddress,   
-                   IN  PULONG  PRegionSize,    
-                   IN  ULONG   FreeType)
-/*
- * 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 
+/* (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)
 {
-   MEMORY_AREA* MemoryArea;
+   // 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;
-   PMADDRESS_SPACE AddressSpace;
-   PVOID BaseAddress;
-   ULONG RegionSize;
-   
-   DPRINT("NtFreeVirtualMemory(ProcessHandle %x, *PBaseAddress %x, "
-         "*PRegionSize %x, FreeType %x)\n",ProcessHandle,*PBaseAddress,
-         *PRegionSize,FreeType);
-                                
-   BaseAddress = (PVOID)PAGE_ROUND_DOWN((*PBaseAddress));
-   RegionSize = PAGE_ROUND_UP((*PBaseAddress) + (*PRegionSize)) -
-     PAGE_ROUND_DOWN((*PBaseAddress));
-   
+
+   DPRINT("NtUnlockVirtualMemory(ProcessHandle %x, BaseAddress %x, "
+          "NumberOfBytesToUnlock %d), NumberOfBytesUnlocked %x\n",ProcessHandle,BaseAddress,
+          NumberOfBytesToUnlock, NumberOfBytesUnlocked);
+
    Status = ObReferenceObjectByHandle(ProcessHandle,
-                                     PROCESS_VM_OPERATION,
-                                     PsProcessType,
-                                     UserMode,
-                                     (PVOID*)(&Process),
-                                     NULL);
+                                      PROCESS_VM_WRITE,
+                                      NULL,
+                                      UserMode,
+                                      (PVOID*)(&Process),
+                                      NULL);
    if (!NT_SUCCESS(Status))
-     {
-       return(Status);
-     }
-   
-   AddressSpace = &Process->AddressSpace;
-   
-   MmLockAddressSpace(AddressSpace);
-   MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
-                                         BaseAddress);
-   if (MemoryArea == NULL)
-     {
-       MmUnlockAddressSpace(AddressSpace);
-       ObDereferenceObject(Process);
-       return(STATUS_UNSUCCESSFUL);
-     }
-   
-   switch (FreeType)
-     {
-      case MEM_RELEASE:
-       if (MemoryArea->BaseAddress != BaseAddress)
-         {
-            MmUnlockAddressSpace(AddressSpace);
-            ObDereferenceObject(Process);
-            return(STATUS_UNSUCCESSFUL);
-         }
-#if 0  
-       if ((MemoryArea->Type == MEMORY_AREA_COMMIT) &&
-           ((MemoryArea->Attributes & PAGE_READWRITE) ||
-            (MemoryArea->Attributes & PAGE_EXECUTE_READWRITE)))
-         {
-            MmDereserveSwapPages(PAGE_ROUND_UP(MemoryArea->Length));
-         }
-#endif
-
-       MmFreeVirtualMemory(Process, MemoryArea);
-       MmUnlockAddressSpace(AddressSpace);
-       ObDereferenceObject(Process);
-       return(STATUS_SUCCESS);
-       
-      case MEM_DECOMMIT:
-       Status = MmComplexVirtualMemoryOperation(AddressSpace,
-                                                MemoryArea,
-                                                BaseAddress,
-                                                RegionSize,
-                                                MEM_RESERVE,
-                                                PAGE_NOACCESS);
-       MmUnlockAddressSpace(AddressSpace);     
-       ObDereferenceObject(Process);
-       return(Status);
-     }
-   MmUnlockAddressSpace(AddressSpace);
-   ObDereferenceObject(Process);
-   return(STATUS_NOT_IMPLEMENTED);
-}
+   {
+      return(Status);
+   }
+
+   Mdl = MmCreateMdl(NULL,
+                     BaseAddress,
+                     NumberOfBytesToUnlock);
+   if(Mdl == NULL)
+   {
+      ObDereferenceObject(Process);
+      return(STATUS_NO_MEMORY);
+   }
 
+   ObDereferenceObject(Process);
 
-NTSTATUS STDCALL 
-NtLockVirtualMemory(HANDLE     ProcessHandle,
-                   PVOID       BaseAddress,
-                   ULONG       NumberOfBytesToLock,
-                   PULONG      NumberOfBytesLocked)
-{
-  UNIMPLEMENTED;
-}
+   if (Mdl->MappedSystemVa != NULL)
+   {
+      MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
+   }
+   MmUnlockPages(Mdl);
+   ExFreePool(Mdl);
 
+   *NumberOfBytesUnlocked = NumberOfBytesToUnlock;
 
-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);
-         }
-     }
+   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
-NtProtectVirtualMemory(IN      HANDLE  ProcessHandle,
-                      IN       PVOID   BaseAddress,
-                      IN       ULONG   NumberOfBytesToProtect,
-                      IN       ULONG   NewAccessProtection,
-                      OUT      PULONG  OldAccessProtection)
+NtWriteVirtualMemory(IN HANDLE ProcessHandle,
+                     IN PVOID BaseAddress,
+                     IN PVOID Buffer,
+                     IN ULONG NumberOfBytesToWrite,
+                     OUT PULONG NumberOfBytesWritten  OPTIONAL)
 {
-   PMEMORY_AREA MemoryArea;
+   PMDL Mdl;
+   PVOID SystemAddress;
    PEPROCESS Process;
-   NTSTATUS Status;
-   PMADDRESS_SPACE AddressSpace;
-   
-   Status = ObReferenceObjectByHandle(ProcessHandle,
-                                     PROCESS_VM_OPERATION,
-                                     PsProcessType,
-                                     UserMode,
-                                     (PVOID*)(&Process),
-                                     NULL);
-   if (Status != STATUS_SUCCESS)
+   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)
      {
-       DPRINT("NtProtectVirtualMemory() = %x\n",Status);
-       return(Status);
+       /* Don't allow to write into kernel space */
+       return STATUS_ACCESS_VIOLATION;
      }
 
-   AddressSpace = &Process->AddressSpace;
+   PreviousMode = ExGetPreviousMode();
    
-   MmLockAddressSpace(AddressSpace);
-   MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
-                                         BaseAddress);
-   if (MemoryArea == NULL)
+   if (PreviousMode != KernelMode)
      {
-       DPRINT("NtProtectVirtualMemory() = %x\n",STATUS_UNSUCCESSFUL);
-       MmUnlockAddressSpace(AddressSpace);
-       ObDereferenceObject(Process);
-       return(STATUS_UNSUCCESSFUL);
+       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;
+             }
+          }
      }
-#if 0
-   *OldAccessProtection = MemoryArea->Attributes;
 
-   if (MemoryArea->BaseAddress == BaseAddress &&
-       MemoryArea->Length == NumberOfBytesToProtect)
-     {
-       MemoryArea->Attributes = NewAccessProtection;
-     }
+   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
-     {
-       MemoryArea = MmSplitMemoryArea(Process,
-                                      &Process->AddressSpace,
-                                      MemoryArea,
-                                      BaseAddress,
-                                      NumberOfBytesToProtect,
-                                      MemoryArea->Type,
-                                      NewAccessProtection);
-     }
-   MmChangeAreaProtection(Process,
-                         BaseAddress,
-                         NumberOfBytesToProtect,
-                         NewAccessProtection);
-#endif
-   MmUnlockAddressSpace(AddressSpace);
-   ObDereferenceObject(Process);
-   return(STATUS_SUCCESS);
-}
-
-
-NTSTATUS STDCALL NtQueryVirtualMemory (IN HANDLE ProcessHandle,
-                                      IN PVOID Address,
-                                      IN CINT VirtualMemoryInformationClass,
-                                      OUT PVOID VirtualMemoryInformation,
-                                      IN ULONG Length,
-                                      OUT PULONG ResultLength)
-{
-   NTSTATUS Status;
-   PEPROCESS Process;
-   MEMORY_AREA* MemoryArea;
+   {
+      /* 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();
+       }
 
-   DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, "
-          "VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, "
-          "Length %lu ResultLength %x)\n",ProcessHandle,Address,
-          VirtualMemoryInformationClass,VirtualMemoryInformation,
-          Length,ResultLength);
+      /* Free the MDL. */
+      if (Mdl->MappedSystemVa != NULL)
+      {
+         MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
+      }
+      MmUnlockPages(Mdl);
+      ExFreePool(Mdl);
+   }
+   ObDereferenceObject(Process);
 
-   switch(VirtualMemoryInformationClass)
+   if (NT_SUCCESS(CopyStatus) && NumberOfBytesWritten != NULL)
      {
-        case MemoryBasicInformation:
-          {
-             PMEMORY_BASIC_INFORMATION Info =
-                (PMEMORY_BASIC_INFORMATION)VirtualMemoryInformation;
-            PMADDRESS_SPACE AddressSpace;
-            
-             if (Length < sizeof(MEMORY_BASIC_INFORMATION))
-               {
-                  ObDereferenceObject(Process);
-                  return STATUS_INFO_LENGTH_MISMATCH;
-               }
-
-             if (ResultLength)
-               {
-                  *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
-               }
-
-             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;
-            MmLockAddressSpace(AddressSpace);
-             MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
-                                                    Address);
-
-             if (MemoryArea == NULL)
-               {
-                  Info->State = MEM_FREE;
-                  DPRINT("Virtual memory at %p is free.\n", Address);
-                 MmUnlockAddressSpace(AddressSpace);
-                  ObDereferenceObject(Process);
-                  return (STATUS_SUCCESS);
-               }
-
-#if 0       
-             if (MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY)
-               {
-                  Info->State = MEM_COMMIT;
-               }
-             else
-               {
-                  Info->State = MEM_RESERVE;
-               }
-#endif
-            
-             Info->BaseAddress = MemoryArea->BaseAddress;
-             Info->RegionSize  = MemoryArea->Length;
-
-             DPRINT("BaseAddress %p, RegionSize %x State %x\n",
-                    Info->BaseAddress, Info->RegionSize, Info->State);
-            
-            MmUnlockAddressSpace(AddressSpace);
-             ObDereferenceObject(Process);
-             return STATUS_SUCCESS;
-          }
-          break;
+       if (PreviousMode != KernelMode)
+         {
+           _SEH_TRY
+             {
+               *NumberOfBytesWritten = NumberOfBytesToWrite;
+             }
+           _SEH_HANDLE
+             {
+               Status = _SEH_GetExceptionCode();
+             }
+           _SEH_END;
+         }
+       else
+         {
+           *NumberOfBytesWritten = NumberOfBytesToWrite;
+         }
      }
 
-   return STATUS_INVALID_INFO_CLASS;
+   return(NT_SUCCESS(CopyStatus) ? Status : CopyStatus);
 }
 
+/*
+ * @unimplemented
+ */
 
-NTSTATUS STDCALL 
-NtReadVirtualMemory(IN HANDLE  ProcessHandle,
-                   IN  PVOID   BaseAddress,
-                   OUT PVOID   Buffer,
-                   IN  ULONG   NumberOfBytesToRead,
-                   OUT PULONG  NumberOfBytesRead)
+PVOID
+STDCALL
+MmGetVirtualForPhysical (
+    IN PHYSICAL_ADDRESS PhysicalAddress
+    )
 {
-   NTSTATUS Status;
-   PMDL Mdl;
-   PVOID SystemAddress;
-   PEPROCESS Process;
-   
-   DPRINT("NtReadVirtualMemory(ProcessHandle %x, BaseAddress %x, "
-           "Buffer %x, NumberOfBytesToRead %d)\n",ProcessHandle,BaseAddress,
-           Buffer,NumberOfBytesToRead);
-   
-   Status = ObReferenceObjectByHandle(ProcessHandle,
-                                     PROCESS_VM_WRITE,
-                                     NULL,
-                                     UserMode,
-                                     (PVOID*)(&Process),
-                                     NULL);
-   if (Status != STATUS_SUCCESS)
-     {
-       return(Status);
-     }
-   
-   Mdl = MmCreateMdl(NULL, 
-                    Buffer,
-                    NumberOfBytesToRead);
-   MmProbeAndLockPages(Mdl,
-                      UserMode,
-                      IoWriteAccess);
-   
-   KeAttachProcess(Process);
-   
-   SystemAddress = MmGetSystemAddressForMdl(Mdl);
-   memcpy(SystemAddress, BaseAddress, NumberOfBytesToRead);
-   
-   KeDetachProcess();
-
-   if (Mdl->MappedSystemVa != NULL)
-     {      
-       MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
-     }
-   MmUnlockPages(Mdl);
-   ExFreePool(Mdl);
-   
-   ObDereferenceObject(Process);
-   
-   *NumberOfBytesRead = NumberOfBytesToRead;
-   return(STATUS_SUCCESS);
+       UNIMPLEMENTED;
+       return 0;
 }
 
-
-NTSTATUS STDCALL 
-NtUnlockVirtualMemory(HANDLE   ProcessHandle,
-                     PVOID     BaseAddress,
-                     ULONG     NumberOfBytesToUnlock,
-                     PULONG NumberOfBytesUnlocked OPTIONAL)
+/* FUNCTION:
+ * Called from EngSecureMem (subsys\win32k\eng\mem.c)
+ * @unimplemented
+ */
+PVOID STDCALL
+MmSecureVirtualMemory (PVOID  Address,
+                       SIZE_T Length,
+                       ULONG  Mode)
 {
-       UNIMPLEMENTED;
+   /* Only works for user space */
+   if (MmHighestUserAddress < Address)
+   {
+      return NULL;
+   }
+
+   UNIMPLEMENTED;
+
+   return 0;
 }
 
 
-NTSTATUS STDCALL 
-NtWriteVirtualMemory(IN        HANDLE  ProcessHandle,
-                    IN PVOID   BaseAddress,
-                    IN PVOID   Buffer,
-                    IN ULONG   NumberOfBytesToWrite,
-                    OUT        PULONG  NumberOfBytesWritten)
+/* FUNCTION:
+ * Called from EngUnsecureMem (subsys\win32k\eng\mem.c)
+ * @unimplemented
+ */
+VOID STDCALL
+MmUnsecureVirtualMemory(PVOID SecureMem)
 {
-   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_WRITE,
-                                     NULL,
-                                     UserMode,
-                                     (PVOID*)(&Process),
-                                     NULL);
-   if (Status != STATUS_SUCCESS)
-     {
-       return(Status);
-     }
-   
-   Mdl = MmCreateMdl(NULL, 
-                    Buffer,
-                    NumberOfBytesToWrite);
-   MmProbeAndLockPages(Mdl,
-                      UserMode,
-                      IoReadAccess);
-   
-   KeAttachProcess(Process);
-   
-   DPRINT("Attached to process copying memory\n");
-   
-   SystemAddress = MmGetSystemAddressForMdl(Mdl);
-   memcpy(BaseAddress, SystemAddress, NumberOfBytesToWrite);
-   
-   DPRINT("Done copy\n");
-   
-   KeDetachProcess();
-   
-   ObDereferenceObject(Process);
+   if (NULL == SecureMem)
+   {
+      return;
+   }
 
-   if (Mdl->MappedSystemVa != NULL)
-     {      
-       MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
-     }
-   MmUnlockPages(Mdl);
-   ExFreePool(Mdl);
-   
-   *NumberOfBytesWritten = NumberOfBytesToWrite;
-   
-   DPRINT("Finished NtWriteVirtualMemory()\n");
-   
-   return(STATUS_SUCCESS);
+   UNIMPLEMENTED;
 }
 
 
-DWORD
-STDCALL
-MmSecureVirtualMemory (
-       DWORD   Unknown0,
-       DWORD   Unknown1,
-       DWORD   Unknown2
-       )
+/*
+ * @implemented
+ */
+VOID STDCALL
+ProbeForRead (IN CONST VOID *Address,
+              IN ULONG Length,
+              IN ULONG Alignment)
 {
-       UNIMPLEMENTED;
-       return 0;
+   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 - 1 < (ULONG_PTR)Address ||
+            (ULONG_PTR)Address + Length - 1 >= (ULONG_PTR)MmUserProbeAddress)
+   {
+      ExRaiseStatus (STATUS_ACCESS_VIOLATION);
+   }
 }
 
 
-VOID
-STDCALL
-MmUnsecureVirtualMemory (
-       DWORD   Unknown0
-       )
+/*
+ * @implemented
+ */
+VOID STDCALL
+ProbeForWrite (IN CONST VOID *Address,
+               IN ULONG Length,
+               IN ULONG Alignment)
 {
-       UNIMPLEMENTED;
+   volatile CHAR *Current;
+   PCHAR Last;
+
+   ASSERT(Alignment == 1 || Alignment == 2 || Alignment == 4 || Alignment == 8);
+
+   if (Length == 0)
+      return;
+
+   if (((ULONG_PTR)Address & (Alignment - 1)) != 0)
+   {
+      ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT);
+   }
+
+   Last = (CHAR*)((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 */
+   Current = (CHAR*)Address;
+   *Current = *Current;
+   Current = (PCHAR)((ULONG_PTR)PAGE_ROUND_DOWN(Current) + PAGE_SIZE);
+   while (Current <= Last)
+   {
+     *Current = *Current;
+     Current = (CHAR*)((ULONG_PTR)Current + PAGE_SIZE);
+   } 
 }
 
 /* EOF */