Lock always the address space if we changing the virtual mapping.
[reactos.git] / reactos / ntoskrnl / mm / anonmem.c
index c869b6c..ffb1257 100644 (file)
@@ -1,51 +1,61 @@
-/*
- *  ReactOS kernel
- *  Copyright (C) 1998, 1999, 2000, 2001, 2002 ReactOS Team
+/* $Id$
  *
- *  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.
+ * Copyright (C) 2002-2005 ReactOS Team (and the authors from the programmers section)
  *
- *  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.
+ * 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.
  *
- *  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: anonmem.c,v 1.28 2004/06/06 08:36:31 hbirr Exp $
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  *
- * PROJECT:     ReactOS kernel
- * FILE:        ntoskrnl/mm/anonmem.c
- * PURPOSE:     Implementing anonymous memory.
- * PROGRAMMER:  David Welch
+ *
+ * PROJECT:         ReactOS kernel
+ * FILE:            ntoskrnl/mm/anonmem.c
+ * PURPOSE:         Implementing anonymous memory.
+ *
+ * PROGRAMMERS:     David Welch
+ *                  Hartmut Birr
+ *                  Casper Hornstrup
+ *                  KJK::Hyperion
+ *                  Ge van Geldorp
+ *                  Eric Kohl
+ *                  Royce Mitchell III
+ *                  Aleksey Bragin 
+ *                  Jason Filby
+ *                  Art Yerkes
+ *                  Gunnar Andre' Dalsnes
+ *                  Filip Navara
+ *                  Thomas Weidenmueller
+ *                  Alex Ionescu
+ *                  Trevor McCort 
+ *                  Steven Edwards
  */
 
 /* 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>
 
 /* FUNCTIONS *****************************************************************/
 
 NTSTATUS
+NTAPI
 MmWritePageVirtualMemory(PMADDRESS_SPACE AddressSpace,
                          PMEMORY_AREA MemoryArea,
                          PVOID Address,
                          PMM_PAGEOP PageOp)
 {
    SWAPENTRY SwapEntry;
-   LARGE_INTEGER PhysicalAddress;
+   PFN_TYPE Page;
    NTSTATUS Status;
 
    /*
@@ -59,13 +69,12 @@ MmWritePageVirtualMemory(PMADDRESS_SPACE AddressSpace,
       return(STATUS_UNSUCCESSFUL);
    }
 
-   PhysicalAddress =
-      MmGetPhysicalAddressForProcess(AddressSpace->Process, Address);
+   Page = MmGetPfnForProcess(AddressSpace->Process, Address);
 
    /*
     * Get that the page actually is dirty.
     */
-   if (!MmIsDirtyPage(MemoryArea->Process, Address))
+   if (!MmIsDirtyPage(AddressSpace->Process, Address))
    {
       PageOp->Status = STATUS_SUCCESS;
       KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
@@ -76,18 +85,18 @@ MmWritePageVirtualMemory(PMADDRESS_SPACE AddressSpace,
    /*
     * Speculatively set the mapping to clean.
     */
-   MmSetCleanPage(MemoryArea->Process, Address);
+   MmSetCleanPage(AddressSpace->Process, Address);
 
    /*
     * If necessary, allocate an entry in the paging file for this page
     */
-   SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress);
+   SwapEntry = MmGetSavedSwapEntryPage(Page);
    if (SwapEntry == 0)
    {
       SwapEntry = MmAllocSwapPage();
       if (SwapEntry == 0)
       {
-         MmSetDirtyPage(MemoryArea->Process, Address);
+         MmSetDirtyPage(AddressSpace->Process, Address);
          PageOp->Status = STATUS_PAGEFILE_QUOTA_EXCEEDED;
          KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
          MmReleasePageOp(PageOp);
@@ -98,12 +107,12 @@ MmWritePageVirtualMemory(PMADDRESS_SPACE AddressSpace,
    /*
     * Write the page to the pagefile
     */
-   Status = MmWriteToSwapPage(SwapEntry, &PhysicalAddress);
+   Status = MmWriteToSwapPage(SwapEntry, Page);
    if (!NT_SUCCESS(Status))
    {
       DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
               Status);
-      MmSetDirtyPage(MemoryArea->Process, Address);
+      MmSetDirtyPage(AddressSpace->Process, Address);
       PageOp->Status = STATUS_UNSUCCESSFUL;
       KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
       MmReleasePageOp(PageOp);
@@ -113,7 +122,7 @@ MmWritePageVirtualMemory(PMADDRESS_SPACE AddressSpace,
    /*
     * Otherwise we have succeeded.
     */
-   MmSetSavedSwapEntryPage(PhysicalAddress, SwapEntry);
+   MmSetSavedSwapEntryPage(Page, SwapEntry);
    PageOp->Status = STATUS_SUCCESS;
    KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
    MmReleasePageOp(PageOp);
@@ -121,18 +130,19 @@ MmWritePageVirtualMemory(PMADDRESS_SPACE AddressSpace,
 }
 
 NTSTATUS
+NTAPI
 MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace,
                        PMEMORY_AREA MemoryArea,
                        PVOID Address,
                        PMM_PAGEOP PageOp)
 {
-   PHYSICAL_ADDRESS PhysicalAddress;
+   PFN_TYPE Page;
    BOOL WasDirty;
    SWAPENTRY SwapEntry;
    NTSTATUS Status;
 
    DPRINT("MmPageOutVirtualMemory(Address 0x%.8X) PID %d\n",
-          Address, MemoryArea->Process->UniqueProcessId);
+          Address, AddressSpace->Process->UniqueProcessId);
 
    /*
     * Check for paging out from a deleted virtual memory area.
@@ -148,27 +158,29 @@ MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace,
    /*
     * Disable the virtual mapping.
     */
-   MmDisableVirtualMapping(MemoryArea->Process, Address,
-                           &WasDirty, &PhysicalAddress);
+   MmDisableVirtualMapping(AddressSpace->Process, Address,
+                           &WasDirty, &Page);
 
-   if (PhysicalAddress.QuadPart == 0)
+   if (Page == 0)
    {
       KEBUGCHECK(0);
    }
 
    /*
-    * Paging out non-dirty data is easy. 
+    * Paging out non-dirty data is easy.
     */
    if (!WasDirty)
    {
-      MmDeleteVirtualMapping(MemoryArea->Process, Address, FALSE, NULL, NULL);
-      MmDeleteAllRmaps(PhysicalAddress, NULL, NULL);
-      if ((SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress)) != 0)
+      MmLockAddressSpace(AddressSpace);
+      MmDeleteVirtualMapping(AddressSpace->Process, Address, FALSE, NULL, NULL);
+      MmDeleteAllRmaps(Page, NULL, NULL);
+      if ((SwapEntry = MmGetSavedSwapEntryPage(Page)) != 0)
       {
-         MmCreatePageFileMapping(MemoryArea->Process, Address, SwapEntry);
-         MmSetSavedSwapEntryPage(PhysicalAddress, 0);
+         MmCreatePageFileMapping(AddressSpace->Process, Address, SwapEntry);
+         MmSetSavedSwapEntryPage(Page, 0);
       }
-      MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
+      MmUnlockAddressSpace(AddressSpace);
+      MmReleasePageMemoryConsumer(MC_USER, Page);
       PageOp->Status = STATUS_SUCCESS;
       KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
       MmReleasePageOp(PageOp);
@@ -178,14 +190,14 @@ MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace,
    /*
     * If necessary, allocate an entry in the paging file for this page
     */
-   SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress);
+   SwapEntry = MmGetSavedSwapEntryPage(Page);
    if (SwapEntry == 0)
    {
       SwapEntry = MmAllocSwapPage();
       if (SwapEntry == 0)
       {
          MmShowOutOfSpaceMessagePagingFile();
-         MmEnableVirtualMapping(MemoryArea->Process, Address);
+         MmEnableVirtualMapping(AddressSpace->Process, Address);
          PageOp->Status = STATUS_UNSUCCESSFUL;
          KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
          MmReleasePageOp(PageOp);
@@ -196,12 +208,12 @@ MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace,
    /*
     * Write the page to the pagefile
     */
-   Status = MmWriteToSwapPage(SwapEntry, &PhysicalAddress);
+   Status = MmWriteToSwapPage(SwapEntry, Page);
    if (!NT_SUCCESS(Status))
    {
       DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
               Status);
-      MmEnableVirtualMapping(MemoryArea->Process, Address);
+      MmEnableVirtualMapping(AddressSpace->Process, Address);
       PageOp->Status = STATUS_UNSUCCESSFUL;
       KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
       MmReleasePageOp(PageOp);
@@ -211,12 +223,14 @@ MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace,
    /*
     * 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);
+   DPRINT("MM: Swapped out virtual memory page 0x%.8X!\n", Page << PAGE_SHIFT);
+   MmLockAddressSpace(AddressSpace);
+   MmDeleteVirtualMapping(AddressSpace->Process, Address, FALSE, NULL, NULL);
+   MmCreatePageFileMapping(AddressSpace->Process, Address, SwapEntry);
+   MmUnlockAddressSpace(AddressSpace);
+   MmDeleteAllRmaps(Page, NULL, NULL);
+   MmSetSavedSwapEntryPage(Page, 0);
+   MmReleasePageMemoryConsumer(MC_USER, Page);
    PageOp->Status = STATUS_SUCCESS;
    KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
    MmReleasePageOp(PageOp);
@@ -224,6 +238,7 @@ MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace,
 }
 
 NTSTATUS
+NTAPI
 MmNotPresentFaultVirtualMemory(PMADDRESS_SPACE AddressSpace,
                                MEMORY_AREA* MemoryArea,
                                PVOID Address,
@@ -238,7 +253,7 @@ MmNotPresentFaultVirtualMemory(PMADDRESS_SPACE AddressSpace,
  * NOTES: This function is called with the address space lock held.
  */
 {
-   PHYSICAL_ADDRESS Page;
+   PFN_TYPE Page;
    NTSTATUS Status;
    PMM_REGION Region;
    PMM_PAGEOP PageOp;
@@ -252,7 +267,7 @@ MmNotPresentFaultVirtualMemory(PMADDRESS_SPACE AddressSpace,
    {
       if (Locked)
       {
-         MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
+         MmLockPage(MmGetPfnForProcess(NULL, Address));
       }
       return(STATUS_SUCCESS);
    }
@@ -268,7 +283,7 @@ MmNotPresentFaultVirtualMemory(PMADDRESS_SPACE AddressSpace,
    /*
     * Get the segment corresponding to the virtual address
     */
-   Region = MmFindRegion(MemoryArea->BaseAddress,
+   Region = MmFindRegion(MemoryArea->StartingAddress,
                          &MemoryArea->Data.VirtualMemoryData.RegionListHead,
                          Address, NULL);
    if (Region->Type == MEM_RESERVE || Region->Protect == PAGE_NOACCESS)
@@ -279,7 +294,7 @@ MmNotPresentFaultVirtualMemory(PMADDRESS_SPACE AddressSpace,
    /*
     * Get or create a page operation
     */
-   PageOp = MmGetPageOp(MemoryArea, (ULONG)MemoryArea->Process->UniqueProcessId,
+   PageOp = MmGetPageOp(MemoryArea, AddressSpace->Process->UniqueProcessId,
                         (PVOID)PAGE_ROUND_DOWN(Address), NULL, 0,
                         MM_PAGEOP_PAGEIN, FALSE);
    if (PageOp == NULL)
@@ -337,7 +352,7 @@ MmNotPresentFaultVirtualMemory(PMADDRESS_SPACE AddressSpace,
       MmLockAddressSpace(AddressSpace);
       if (Locked)
       {
-         MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
+         MmLockPage(MmGetPfnForProcess(NULL, Address));
       }
       KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
       MmReleasePageOp(PageOp);
@@ -367,8 +382,8 @@ MmNotPresentFaultVirtualMemory(PMADDRESS_SPACE AddressSpace,
    {
       SWAPENTRY SwapEntry;
 
-      MmDeletePageFileMapping(MemoryArea->Process, Address, &SwapEntry);
-      Status = MmReadFromSwapPage(SwapEntry, &Page);
+      MmDeletePageFileMapping(AddressSpace->Process, Address, &SwapEntry);
+      Status = MmReadFromSwapPage(SwapEntry, Page);
       if (!NT_SUCCESS(Status))
       {
          KEBUGCHECK(0);
@@ -380,19 +395,19 @@ MmNotPresentFaultVirtualMemory(PMADDRESS_SPACE AddressSpace,
     * Set the page. If we fail because we are out of memory then
     * try again
     */
-   Status = MmCreateVirtualMapping(MemoryArea->Process,
+   Status = MmCreateVirtualMapping(AddressSpace->Process,
                                    (PVOID)PAGE_ROUND_DOWN(Address),
                                    Region->Protect,
-                                   Page,
-                                   FALSE);
+                                   &Page,
+                                   1);
    while (Status == STATUS_NO_MEMORY)
    {
       MmUnlockAddressSpace(AddressSpace);
-      Status = MmCreateVirtualMapping(MemoryArea->Process,
+      Status = MmCreateVirtualMapping(AddressSpace->Process,
                                       Address,
                                       Region->Protect,
-                                      Page,
-                                      TRUE);
+                                      &Page,
+                                      1);
       MmLockAddressSpace(AddressSpace);
    }
    if (!NT_SUCCESS(Status))
@@ -405,14 +420,14 @@ MmNotPresentFaultVirtualMemory(PMADDRESS_SPACE AddressSpace,
    /*
     * Add the page to the process's working set
     */
-   MmInsertRmap(Page, MemoryArea->Process, (PVOID)PAGE_ROUND_DOWN(Address));
+   MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAGE_ROUND_DOWN(Address));
 
    /*
     * Finish the operation
     */
    if (Locked)
    {
-      MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
+      MmLockPage(Page);
    }
    PageOp->Status = STATUS_SUCCESS;
    KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
@@ -442,7 +457,7 @@ MmModifyAttributes(PMADDRESS_SPACE AddressSpace,
 
       for (i=0; i < PAGE_ROUND_UP(RegionSize)/PAGE_SIZE; i++)
       {
-         LARGE_INTEGER PhysicalAddr;
+         PFN_TYPE Page;
 
          if (MmIsPageSwapEntry(AddressSpace->Process,
                                (char*)BaseAddress + (i * PAGE_SIZE)))
@@ -458,19 +473,19 @@ MmModifyAttributes(PMADDRESS_SPACE AddressSpace,
          {
             MmDeleteVirtualMapping(AddressSpace->Process,
                                    (char*)BaseAddress + (i*PAGE_SIZE),
-                                   FALSE, NULL, &PhysicalAddr);
-            if (PhysicalAddr.QuadPart != 0)
+                                   FALSE, NULL, &Page);
+            if (Page != 0)
             {
                SWAPENTRY SavedSwapEntry;
-               SavedSwapEntry = MmGetSavedSwapEntryPage(PhysicalAddr);
+               SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
                if (SavedSwapEntry != 0)
                {
                   MmFreeSwapPage(SavedSwapEntry);
-                  MmSetSavedSwapEntryPage(PhysicalAddr, 0);
+                  MmSetSavedSwapEntryPage(Page, 0);
                }
-               MmDeleteRmap(PhysicalAddr, AddressSpace->Process,
+               MmDeleteRmap(Page, AddressSpace->Process,
                             (char*)BaseAddress + (i * PAGE_SIZE));
-               MmReleasePageMemoryConsumer(MC_USER, PhysicalAddr);
+               MmReleasePageMemoryConsumer(MC_USER, Page);
             }
          }
       }
@@ -481,7 +496,7 @@ MmModifyAttributes(PMADDRESS_SPACE AddressSpace,
     * alter the attributes for any allocated pages within the region
     */
    if (NewType == MEM_COMMIT && OldType == MEM_COMMIT &&
-         OldProtect != NewProtect)
+       OldProtect != NewProtect)
    {
       ULONG i;
 
@@ -512,26 +527,27 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
  * 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 
+ *      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 
+ *      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, 
+ *      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, 
+ *                a combination of PAGE_READONLY, PAGE_READWRITE,
+ *                PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_GUARD,
  *                PAGE_NOACCESS
  * RETURNS: Status
  */
 {
    PEPROCESS Process;
    MEMORY_AREA* MemoryArea;
+   ULONG_PTR MemoryAreaLength;
    ULONG Type;
    NTSTATUS Status;
    PMADDRESS_SPACE AddressSpace;
@@ -546,16 +562,66 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
           *UBaseAddress,ZeroBits,*URegionSize,AllocationType,
           Protect);
 
-   /*
-    * Check the validity of the parameters
-    */
+   /* Check for valid protection flags */
    if ((Protect & PAGE_FLAGS_VALID_FROM_USER_MODE) != Protect)
    {
-      return(STATUS_INVALID_PAGE_PROTECTION);
+      DPRINT1("Invalid page protection\n");
+      return STATUS_INVALID_PAGE_PROTECTION;
+   }
+
+   /* Check for valid Zero bits */
+   if (ZeroBits > 21)
+   {
+      DPRINT1("Too many zero bits\n");
+      return STATUS_INVALID_PARAMETER_3;
+   }
+
+   /* Check for valid Allocation Types */
+   if ((AllocationType &~ (MEM_COMMIT | MEM_RESERVE | MEM_RESET | MEM_PHYSICAL |
+                           MEM_TOP_DOWN | MEM_WRITE_WATCH)))
+   {
+      DPRINT1("Invalid Allocation Type\n");
+      return STATUS_INVALID_PARAMETER_5;
+   }
+
+   /* Check for at least one of these Allocation Types to be set */
+   if (!(AllocationType & (MEM_COMMIT | MEM_RESERVE | MEM_RESET)))
+   {
+      DPRINT1("No memory allocation base type\n");
+      return STATUS_INVALID_PARAMETER_5;
    }
-   if ((AllocationType & (MEM_COMMIT | MEM_RESERVE)) == 0)
+   
+   /* MEM_RESET is an exclusive flag, make sure that is valid too */
+   if ((AllocationType & MEM_RESET) && (AllocationType != MEM_RESET))
    {
-      return(STATUS_INVALID_PARAMETER);
+      DPRINT1("MEM_RESET used illegaly\n");
+      return STATUS_INVALID_PARAMETER_5;
+   }
+
+   /* MEM_WRITE_WATCH can only be used if MEM_RESERVE is also used */
+   if ((AllocationType & MEM_WRITE_WATCH) && !(AllocationType & MEM_RESERVE))
+   {
+      DPRINT1("MEM_WRITE_WATCH used without MEM_RESERVE\n");
+      return STATUS_INVALID_PARAMETER_5;
+   }
+
+   /* MEM_PHYSICAL can only be used with MEM_RESERVE, and can only be R/W */
+   if (AllocationType & MEM_PHYSICAL)
+   {
+      /* First check for MEM_RESERVE exclusivity */
+      if (AllocationType != (MEM_RESERVE | MEM_PHYSICAL))
+      {
+         DPRINT1("MEM_PHYSICAL used with other flags then MEM_RESERVE or"
+                 "MEM_RESERVE was not present at all\n");
+         return STATUS_INVALID_PARAMETER_5;
+      }
+
+      /* Then make sure PAGE_READWRITE is used */
+      if (Protect != PAGE_READWRITE)
+      {
+         DPRINT1("MEM_PHYSICAL used without PAGE_READWRITE\n");
+         return STATUS_INVALID_PAGE_PROTECTION;
+      }
    }
 
    PBaseAddress = *UBaseAddress;
@@ -566,6 +632,39 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
    RegionSize = PAGE_ROUND_UP(PBaseAddress + PRegionSize) -
                 PAGE_ROUND_DOWN(PBaseAddress);
 
+   /* 
+    * We've captured and calculated the data, now do more checks
+    * Yes, MmCreateMemoryArea does similar checks, but they don't return
+    * the right status codes that a caller of this routine would expect.
+    */
+   if (BaseAddress >= MM_HIGHEST_USER_ADDRESS)
+   {
+      DPRINT1("Virtual allocation above User Space\n");
+      return STATUS_INVALID_PARAMETER_2;
+   }
+   if (!RegionSize)
+   {
+      DPRINT1("Region size is invalid\n");
+      return STATUS_INVALID_PARAMETER_4;
+   }
+   if (((ULONG_PTR)MM_HIGHEST_USER_ADDRESS - (ULONG_PTR)BaseAddress) < RegionSize)
+   {
+      DPRINT1("Region size would overflow into kernel-memory\n");
+      return STATUS_INVALID_PARAMETER_4;
+   }
+
+   /* 
+    * Copy on Write is reserved for system use. This case is a certain failure
+    * but there may be other cases...needs more testing
+    */
+   if ((!BaseAddress || (AllocationType & MEM_RESERVE)) && 
+       ((Protect & PAGE_WRITECOPY) || (Protect & PAGE_EXECUTE_WRITECOPY)))
+   {
+      DPRINT1("Copy on write is not supported by VirtualAlloc\n");
+      return STATUS_INVALID_PAGE_PROTECTION;
+   }
+
+
    Status = ObReferenceObjectByHandle(ProcessHandle,
                                       PROCESS_VM_OPERATION,
                                       NULL,
@@ -586,42 +685,45 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
 
    if (PBaseAddress != 0)
    {
-      MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
-                                             BaseAddress);
+      MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
 
-      if (MemoryArea != NULL &&
-            MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY &&
-            MemoryArea->Length >= RegionSize)
-      {
-         Status =
-            MmAlterRegion(AddressSpace,
-                          MemoryArea->BaseAddress,
-                          &MemoryArea->Data.VirtualMemoryData.RegionListHead,
-                          BaseAddress, RegionSize,
-                          Type, Protect, MmModifyAttributes);
-         MmUnlockAddressSpace(AddressSpace);
-         ObDereferenceObject(Process);
-         DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
-         return(Status);
-      }
-      else if (MemoryArea != NULL && MemoryArea->Length >= RegionSize)
-      {
-         Status =
-            MmAlterRegion(AddressSpace,
-                          MemoryArea->BaseAddress,
-                          &MemoryArea->Data.SectionData.RegionListHead,
-                          BaseAddress, RegionSize,
-                          Type, Protect, MmModifyAttributes);
-         MmUnlockAddressSpace(AddressSpace);
-         ObDereferenceObject(Process);
-         DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
-         return(Status);
-      }
-      else if (MemoryArea != NULL)
+      if (MemoryArea != NULL)
       {
-         MmUnlockAddressSpace(AddressSpace);
-         ObDereferenceObject(Process);
-         return(STATUS_UNSUCCESSFUL);
+         MemoryAreaLength = (ULONG_PTR)MemoryArea->EndingAddress -
+                            (ULONG_PTR)MemoryArea->StartingAddress;
+         if (MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY &&
+             MemoryAreaLength >= RegionSize)
+         {
+            Status =
+               MmAlterRegion(AddressSpace,
+                             MemoryArea->StartingAddress,
+                             &MemoryArea->Data.VirtualMemoryData.RegionListHead,
+                             BaseAddress, RegionSize,
+                             Type, Protect, MmModifyAttributes);
+            MmUnlockAddressSpace(AddressSpace);
+            ObDereferenceObject(Process);
+            DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
+            return(Status);
+         }
+         else if (MemoryAreaLength >= RegionSize)
+         {
+            Status =
+               MmAlterRegion(AddressSpace,
+                             MemoryArea->StartingAddress,
+                             &MemoryArea->Data.SectionData.RegionListHead,
+                             BaseAddress, RegionSize,
+                             Type, Protect, MmModifyAttributes);
+            MmUnlockAddressSpace(AddressSpace);
+            ObDereferenceObject(Process);
+            DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
+            return(Status);
+         }
+         else
+         {
+            MmUnlockAddressSpace(AddressSpace);
+            ObDereferenceObject(Process);
+            return(STATUS_UNSUCCESSFUL);
+         }
       }
    }
 
@@ -633,7 +735,7 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
                                Protect,
                                &MemoryArea,
                                PBaseAddress != 0,
-                               (AllocationType & MEM_TOP_DOWN),
+                               (AllocationType & MEM_TOP_DOWN) == MEM_TOP_DOWN,
                                BoundaryAddressMultiple);
    if (!NT_SUCCESS(Status))
    {
@@ -642,18 +744,22 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
       DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
       return(Status);
    }
+
+   MemoryAreaLength = (ULONG_PTR)MemoryArea->EndingAddress -
+                      (ULONG_PTR)MemoryArea->StartingAddress;
+
    MmInitialiseRegion(&MemoryArea->Data.VirtualMemoryData.RegionListHead,
-                      RegionSize, Type, Protect);
+                      MemoryAreaLength, Type, Protect);
 
    if ((AllocationType & MEM_COMMIT) &&
          ((Protect & PAGE_READWRITE) ||
           (Protect & PAGE_EXECUTE_READWRITE)))
    {
-      MmReserveSwapPages(RegionSize);
+      MmReserveSwapPages(MemoryAreaLength);
    }
 
    *UBaseAddress = BaseAddress;
-   *URegionSize = RegionSize;
+   *URegionSize = MemoryAreaLength;
    DPRINT("*UBaseAddress %x  *URegionSize %x\n", BaseAddress, RegionSize);
 
    MmUnlockAddressSpace(AddressSpace);
@@ -665,23 +771,23 @@ VOID STATIC
 MmFreeVirtualMemoryPage(PVOID Context,
                         MEMORY_AREA* MemoryArea,
                         PVOID Address,
-                        PHYSICAL_ADDRESS PhysicalAddr,
+                        PFN_TYPE Page,
                         SWAPENTRY SwapEntry,
                         BOOLEAN Dirty)
 {
    PEPROCESS Process = (PEPROCESS)Context;
 
-   if (PhysicalAddr.QuadPart != 0)
+   if (Page != 0)
    {
       SWAPENTRY SavedSwapEntry;
-      SavedSwapEntry = MmGetSavedSwapEntryPage(PhysicalAddr);
+      SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
       if (SavedSwapEntry != 0)
       {
          MmFreeSwapPage(SavedSwapEntry);
-         MmSetSavedSwapEntryPage(PhysicalAddr, 0);
+         MmSetSavedSwapEntryPage(Page, 0);
       }
-      MmDeleteRmap(PhysicalAddr, Process, Address);
-      MmReleasePageMemoryConsumer(MC_USER, PhysicalAddr);
+      MmDeleteRmap(Page, Process, Address);
+      MmReleasePageMemoryConsumer(MC_USER, Page);
    }
    else if (SwapEntry != 0)
    {
@@ -690,6 +796,7 @@ MmFreeVirtualMemoryPage(PVOID Context,
 }
 
 VOID
+NTAPI
 MmFreeVirtualMemory(PEPROCESS Process,
                     PMEMORY_AREA MemoryArea)
 {
@@ -709,7 +816,11 @@ MmFreeVirtualMemory(PEPROCESS Process,
     */
    if (MemoryArea->PageOpCount > 0)
    {
-      for (i = 0; i < PAGE_ROUND_UP(MemoryArea->Length) / PAGE_SIZE; i++)
+      ULONG_PTR MemoryAreaLength = (ULONG_PTR)MemoryArea->EndingAddress -
+                                   (ULONG_PTR)MemoryArea->StartingAddress;
+
+      /* FiN TODO: Optimize loop counter! */
+      for (i = 0; i < PAGE_ROUND_UP(MemoryAreaLength) / PAGE_SIZE; i++)
       {
          PMM_PAGEOP PageOp;
 
@@ -719,7 +830,7 @@ MmFreeVirtualMemory(PEPROCESS Process,
          }
 
          PageOp = MmCheckForPageOp(MemoryArea, Process->UniqueProcessId,
-                                   (char*)MemoryArea->BaseAddress + (i * PAGE_SIZE),
+                                   (PVOID)((ULONG_PTR)MemoryArea->StartingAddress + (i * PAGE_SIZE)),
                                    NULL, 0);
          if (PageOp != NULL)
          {
@@ -752,14 +863,13 @@ MmFreeVirtualMemory(PEPROCESS Process,
 
    /* Actually free the memory area. */
    MmFreeMemoryArea(&Process->AddressSpace,
-                    MemoryArea->BaseAddress,
-                    0,
+                    MemoryArea,
                     MmFreeVirtualMemoryPage,
                     (PVOID)Process);
 }
 
 /*
- * @unimplemented
+ * @implemented
  */
 NTSTATUS STDCALL
 NtFreeVirtualMemory(IN HANDLE ProcessHandle,
@@ -769,14 +879,14 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle,
 /*
  * FUNCTION: Frees a range of virtual memory
  * ARGUMENTS:
- *        ProcessHandle = Points to the process that allocated the virtual 
+ *        ProcessHandle = Points to the process that allocated the virtual
  *                        memory
- *        BaseAddress = Points to the memory address, rounded down to a 
+ *        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 
+ *        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 
+ * RETURNS: Status
  */
 {
    MEMORY_AREA* MemoryArea;
@@ -808,8 +918,7 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle,
    AddressSpace = &Process->AddressSpace;
 
    MmLockAddressSpace(AddressSpace);
-   MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
-                                          BaseAddress);
+   MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
    if (MemoryArea == NULL)
    {
       MmUnlockAddressSpace(AddressSpace);
@@ -821,7 +930,8 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle,
    {
       case MEM_RELEASE:
          /* We can only free a memory area in one step. */
-         if (MemoryArea->BaseAddress != BaseAddress)
+         if (MemoryArea->StartingAddress != BaseAddress ||
+             MemoryArea->Type != MEMORY_AREA_VIRTUAL_MEMORY)
          {
             MmUnlockAddressSpace(AddressSpace);
             ObDereferenceObject(Process);
@@ -835,7 +945,7 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle,
       case MEM_DECOMMIT:
          Status =
             MmAlterRegion(AddressSpace,
-                          MemoryArea->BaseAddress,
+                          MemoryArea->StartingAddress,
                           &MemoryArea->Data.VirtualMemoryData.RegionListHead,
                           BaseAddress,
                           RegionSize,
@@ -852,6 +962,7 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle,
 }
 
 NTSTATUS
+NTAPI
 MmProtectAnonMem(PMADDRESS_SPACE AddressSpace,
                  PMEMORY_AREA MemoryArea,
                  PVOID BaseAddress,
@@ -862,11 +973,11 @@ MmProtectAnonMem(PMADDRESS_SPACE AddressSpace,
    PMM_REGION Region;
    NTSTATUS Status;
 
-   Region = MmFindRegion(MemoryArea->BaseAddress,
+   Region = MmFindRegion(MemoryArea->StartingAddress,
                          &MemoryArea->Data.VirtualMemoryData.RegionListHead,
                          BaseAddress, NULL);
    *OldProtect = Region->Protect;
-   Status = MmAlterRegion(AddressSpace, MemoryArea->BaseAddress,
+   Status = MmAlterRegion(AddressSpace, MemoryArea->StartingAddress,
                           &MemoryArea->Data.VirtualMemoryData.RegionListHead,
                           BaseAddress, Length, Region->Type, Protect,
                           MmModifyAttributes);
@@ -884,12 +995,13 @@ MmQueryAnonMem(PMEMORY_AREA MemoryArea,
 
    Info->BaseAddress = (PVOID)PAGE_ROUND_DOWN(Address);
 
-   Region = MmFindRegion(MemoryArea->BaseAddress,
+   Region = MmFindRegion(MemoryArea->StartingAddress,
                          &MemoryArea->Data.VirtualMemoryData.RegionListHead,
                          Address, &RegionBase);
-   Info->AllocationBase = RegionBase;
-   Info->AllocationProtect = Region->Protect;  /* FIXME */
-   Info->RegionSize = (char*)RegionBase + Region->Length - (char*)Info->BaseAddress;
+   Info->BaseAddress = RegionBase;
+   Info->AllocationBase = MemoryArea->StartingAddress;
+   Info->AllocationProtect = MemoryArea->Attributes;
+   Info->RegionSize = Region->Length;
    Info->State = Region->Type;
    Info->Protect = Region->Protect;
    Info->Type = MEM_PRIVATE;