sync with trunk head (34904)
[reactos.git] / reactos / ntoskrnl / mm / anonmem.c
index 4567a42..dd1943c 100644 (file)
@@ -1,5 +1,4 @@
-/* $Id$
- *
+/*
  * Copyright (C) 2002-2005 ReactOS Team (and the authors from the programmers section)
  *
  * This program is free software; you can redistribute it and/or
  * PURPOSE:         Implementing anonymous memory.
  *
  * PROGRAMMERS:     David Welch
- *                  Hartmut Birr
  *                  Casper Hornstrup
  *                  KJK::Hyperion
  *                  Ge van Geldorp
  *                  Eric Kohl
  *                  Royce Mitchell III
- *                  Aleksey Bragin 
+ *                  Aleksey Bragin
  *                  Jason Filby
  *                  Art Yerkes
  *                  Gunnar Andre' Dalsnes
  *                  Filip Navara
  *                  Thomas Weidenmueller
  *                  Alex Ionescu
- *                  Trevor McCort 
+ *                  Trevor McCort
  *                  Steven Edwards
  */
 
@@ -48,7 +46,8 @@
 /* FUNCTIONS *****************************************************************/
 
 NTSTATUS
-MmWritePageVirtualMemory(PMADDRESS_SPACE AddressSpace,
+NTAPI
+MmWritePageVirtualMemory(PMM_AVL_TABLE AddressSpace,
                          PMEMORY_AREA MemoryArea,
                          PVOID Address,
                          PMM_PAGEOP PageOp)
@@ -56,6 +55,7 @@ MmWritePageVirtualMemory(PMADDRESS_SPACE AddressSpace,
    SWAPENTRY SwapEntry;
    PFN_TYPE Page;
    NTSTATUS Status;
+   PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
 
    /*
     * Check for paging out from a deleted virtual memory area.
@@ -68,12 +68,12 @@ MmWritePageVirtualMemory(PMADDRESS_SPACE AddressSpace,
       return(STATUS_UNSUCCESSFUL);
    }
 
-   Page = MmGetPfnForProcess(AddressSpace->Process, Address);
+   Page = MmGetPfnForProcess(Process, Address);
 
    /*
     * Get that the page actually is dirty.
     */
-   if (!MmIsDirtyPage(AddressSpace->Process, Address))
+   if (!MmIsDirtyPage(Process, Address))
    {
       PageOp->Status = STATUS_SUCCESS;
       KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
@@ -84,7 +84,7 @@ MmWritePageVirtualMemory(PMADDRESS_SPACE AddressSpace,
    /*
     * Speculatively set the mapping to clean.
     */
-   MmSetCleanPage(AddressSpace->Process, Address);
+   MmSetCleanPage(Process, Address);
 
    /*
     * If necessary, allocate an entry in the paging file for this page
@@ -95,7 +95,7 @@ MmWritePageVirtualMemory(PMADDRESS_SPACE AddressSpace,
       SwapEntry = MmAllocSwapPage();
       if (SwapEntry == 0)
       {
-         MmSetDirtyPage(AddressSpace->Process, Address);
+         MmSetDirtyPage(Process, Address);
          PageOp->Status = STATUS_PAGEFILE_QUOTA_EXCEEDED;
          KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
          MmReleasePageOp(PageOp);
@@ -111,7 +111,7 @@ MmWritePageVirtualMemory(PMADDRESS_SPACE AddressSpace,
    {
       DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
               Status);
-      MmSetDirtyPage(AddressSpace->Process, Address);
+      MmSetDirtyPage(Process, Address);
       PageOp->Status = STATUS_UNSUCCESSFUL;
       KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
       MmReleasePageOp(PageOp);
@@ -129,18 +129,20 @@ MmWritePageVirtualMemory(PMADDRESS_SPACE AddressSpace,
 }
 
 NTSTATUS
-MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace,
+NTAPI
+MmPageOutVirtualMemory(PMM_AVL_TABLE AddressSpace,
                        PMEMORY_AREA MemoryArea,
                        PVOID Address,
                        PMM_PAGEOP PageOp)
 {
    PFN_TYPE Page;
-   BOOL WasDirty;
+   BOOLEAN WasDirty;
    SWAPENTRY SwapEntry;
    NTSTATUS Status;
-
+   PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
+    
    DPRINT("MmPageOutVirtualMemory(Address 0x%.8X) PID %d\n",
-          Address, MemoryArea->Process->UniqueProcessId);
+          Address, Process->UniqueProcessId);
 
    /*
     * Check for paging out from a deleted virtual memory area.
@@ -156,7 +158,7 @@ MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace,
    /*
     * Disable the virtual mapping.
     */
-   MmDisableVirtualMapping(AddressSpace->Process, Address,
+   MmDisableVirtualMapping(Process, Address,
                            &WasDirty, &Page);
 
    if (Page == 0)
@@ -169,13 +171,15 @@ MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace,
     */
    if (!WasDirty)
    {
-      MmDeleteVirtualMapping(AddressSpace->Process, Address, FALSE, NULL, NULL);
+      MmLockAddressSpace(AddressSpace);
+      MmDeleteVirtualMapping(Process, Address, FALSE, NULL, NULL);
       MmDeleteAllRmaps(Page, NULL, NULL);
       if ((SwapEntry = MmGetSavedSwapEntryPage(Page)) != 0)
       {
-         MmCreatePageFileMapping(AddressSpace->Process, Address, SwapEntry);
+         MmCreatePageFileMapping(Process, Address, SwapEntry);
          MmSetSavedSwapEntryPage(Page, 0);
       }
+      MmUnlockAddressSpace(AddressSpace);
       MmReleasePageMemoryConsumer(MC_USER, Page);
       PageOp->Status = STATUS_SUCCESS;
       KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
@@ -193,7 +197,7 @@ MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace,
       if (SwapEntry == 0)
       {
          MmShowOutOfSpaceMessagePagingFile();
-         MmEnableVirtualMapping(AddressSpace->Process, Address);
+         MmEnableVirtualMapping(Process, Address);
          PageOp->Status = STATUS_UNSUCCESSFUL;
          KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
          MmReleasePageOp(PageOp);
@@ -209,7 +213,7 @@ MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace,
    {
       DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
               Status);
-      MmEnableVirtualMapping(AddressSpace->Process, Address);
+      MmEnableVirtualMapping(Process, Address);
       PageOp->Status = STATUS_UNSUCCESSFUL;
       KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
       MmReleasePageOp(PageOp);
@@ -220,8 +224,10 @@ MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace,
     * Otherwise we have succeeded, free the page
     */
    DPRINT("MM: Swapped out virtual memory page 0x%.8X!\n", Page << PAGE_SHIFT);
-   MmDeleteVirtualMapping(AddressSpace->Process, Address, FALSE, NULL, NULL);
-   MmCreatePageFileMapping(AddressSpace->Process, Address, SwapEntry);
+   MmLockAddressSpace(AddressSpace);
+   MmDeleteVirtualMapping(Process, Address, FALSE, NULL, NULL);
+   MmCreatePageFileMapping(Process, Address, SwapEntry);
+   MmUnlockAddressSpace(AddressSpace);
    MmDeleteAllRmaps(Page, NULL, NULL);
    MmSetSavedSwapEntryPage(Page, 0);
    MmReleasePageMemoryConsumer(MC_USER, Page);
@@ -232,7 +238,8 @@ MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace,
 }
 
 NTSTATUS
-MmNotPresentFaultVirtualMemory(PMADDRESS_SPACE AddressSpace,
+NTAPI
+MmNotPresentFaultVirtualMemory(PMM_AVL_TABLE AddressSpace,
                                MEMORY_AREA* MemoryArea,
                                PVOID Address,
                                BOOLEAN Locked)
@@ -250,7 +257,8 @@ MmNotPresentFaultVirtualMemory(PMADDRESS_SPACE AddressSpace,
    NTSTATUS Status;
    PMM_REGION Region;
    PMM_PAGEOP PageOp;
-
+   PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
+    
    /*
     * There is a window between taking the page fault and locking the
     * address space when another thread could load the page so we check
@@ -287,7 +295,7 @@ MmNotPresentFaultVirtualMemory(PMADDRESS_SPACE AddressSpace,
    /*
     * Get or create a page operation
     */
-   PageOp = MmGetPageOp(MemoryArea, AddressSpace->Process->UniqueProcessId,
+   PageOp = MmGetPageOp(MemoryArea, Process->UniqueProcessId,
                         (PVOID)PAGE_ROUND_DOWN(Address), NULL, 0,
                         MM_PAGEOP_PAGEIN, FALSE);
    if (PageOp == NULL)
@@ -375,7 +383,7 @@ MmNotPresentFaultVirtualMemory(PMADDRESS_SPACE AddressSpace,
    {
       SWAPENTRY SwapEntry;
 
-      MmDeletePageFileMapping(AddressSpace->Process, Address, &SwapEntry);
+      MmDeletePageFileMapping(Process, Address, &SwapEntry);
       Status = MmReadFromSwapPage(SwapEntry, Page);
       if (!NT_SUCCESS(Status))
       {
@@ -388,7 +396,7 @@ MmNotPresentFaultVirtualMemory(PMADDRESS_SPACE AddressSpace,
     * Set the page. If we fail because we are out of memory then
     * try again
     */
-   Status = MmCreateVirtualMapping(AddressSpace->Process,
+   Status = MmCreateVirtualMapping(Process,
                                    (PVOID)PAGE_ROUND_DOWN(Address),
                                    Region->Protect,
                                    &Page,
@@ -396,7 +404,7 @@ MmNotPresentFaultVirtualMemory(PMADDRESS_SPACE AddressSpace,
    while (Status == STATUS_NO_MEMORY)
    {
       MmUnlockAddressSpace(AddressSpace);
-      Status = MmCreateVirtualMapping(AddressSpace->Process,
+      Status = MmCreateVirtualMapping(Process,
                                       Address,
                                       Region->Protect,
                                       &Page,
@@ -413,7 +421,7 @@ MmNotPresentFaultVirtualMemory(PMADDRESS_SPACE AddressSpace,
    /*
     * Add the page to the process's working set
     */
-   MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAGE_ROUND_DOWN(Address));
+   MmInsertRmap(Page, Process, (PVOID)PAGE_ROUND_DOWN(Address));
 
    /*
     * Finish the operation
@@ -428,8 +436,8 @@ MmNotPresentFaultVirtualMemory(PMADDRESS_SPACE AddressSpace,
    return(STATUS_SUCCESS);
 }
 
-VOID STATIC
-MmModifyAttributes(PMADDRESS_SPACE AddressSpace,
+VOID static
+MmModifyAttributes(PMM_AVL_TABLE AddressSpace,
                    PVOID BaseAddress,
                    ULONG RegionSize,
                    ULONG OldType,
@@ -440,6 +448,8 @@ MmModifyAttributes(PMADDRESS_SPACE AddressSpace,
  * FUNCTION: Modify the attributes of a memory region
  */
 {
+   PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
+    
    /*
     * If we are switching a previously committed region to reserved then
     * free any allocated pages within the region
@@ -452,19 +462,19 @@ MmModifyAttributes(PMADDRESS_SPACE AddressSpace,
       {
          PFN_TYPE Page;
 
-         if (MmIsPageSwapEntry(AddressSpace->Process,
+         if (MmIsPageSwapEntry(Process,
                                (char*)BaseAddress + (i * PAGE_SIZE)))
          {
             SWAPENTRY SwapEntry;
 
-            MmDeletePageFileMapping(AddressSpace->Process,
+            MmDeletePageFileMapping(Process,
                                     (char*)BaseAddress + (i * PAGE_SIZE),
                                     &SwapEntry);
             MmFreeSwapPage(SwapEntry);
          }
          else
          {
-            MmDeleteVirtualMapping(AddressSpace->Process,
+            MmDeleteVirtualMapping(Process,
                                    (char*)BaseAddress + (i*PAGE_SIZE),
                                    FALSE, NULL, &Page);
             if (Page != 0)
@@ -476,7 +486,7 @@ MmModifyAttributes(PMADDRESS_SPACE AddressSpace,
                   MmFreeSwapPage(SavedSwapEntry);
                   MmSetSavedSwapEntryPage(Page, 0);
                }
-               MmDeleteRmap(Page, AddressSpace->Process,
+               MmDeleteRmap(Page, Process,
                             (char*)BaseAddress + (i * PAGE_SIZE));
                MmReleasePageMemoryConsumer(MC_USER, Page);
             }
@@ -495,10 +505,10 @@ MmModifyAttributes(PMADDRESS_SPACE AddressSpace,
 
       for (i=0; i < PAGE_ROUND_UP(RegionSize)/PAGE_SIZE; i++)
       {
-         if (MmIsPagePresent(AddressSpace->Process,
+         if (MmIsPagePresent(Process,
                              (char*)BaseAddress + (i*PAGE_SIZE)))
          {
-            MmSetPageProtect(AddressSpace->Process,
+            MmSetPageProtect(Process,
                              (char*)BaseAddress + (i*PAGE_SIZE),
                              NewProtect);
          }
@@ -510,12 +520,12 @@ MmModifyAttributes(PMADDRESS_SPACE AddressSpace,
  * @implemented
  */
 NTSTATUS STDCALL
-NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
-                        IN OUT PVOID*  UBaseAddress,
-                        IN ULONG ZeroBits,
-                        IN OUT PULONG URegionSize,
-                        IN ULONG AllocationType,
-                        IN ULONG Protect)
+NtAllocateVirtualMemory(IN     HANDLE ProcessHandle,
+                        IN OUT PVOID* UBaseAddress,
+                        IN     ULONG  ZeroBits,
+                        IN OUT PSIZE_T URegionSize,
+                        IN     ULONG  AllocationType,
+                        IN     ULONG  Protect)
 /*
  * FUNCTION: Allocates a block of virtual memory in the process address space
  * ARGUMENTS:
@@ -543,42 +553,146 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
    ULONG_PTR MemoryAreaLength;
    ULONG Type;
    NTSTATUS Status;
-   PMADDRESS_SPACE AddressSpace;
+   PMM_AVL_TABLE AddressSpace;
    PVOID BaseAddress;
    ULONG RegionSize;
    PVOID PBaseAddress;
    ULONG PRegionSize;
    PHYSICAL_ADDRESS BoundaryAddressMultiple;
+   KPROCESSOR_MODE PreviousMode;
+
+   PAGED_CODE();
 
    DPRINT("NtAllocateVirtualMemory(*UBaseAddress %x, "
           "ZeroBits %d, *URegionSize %x, AllocationType %x, Protect %x)\n",
           *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;
+   }
+
+   /* MEM_RESET is an exclusive flag, make sure that is valid too */
+   if ((AllocationType & MEM_RESET) && (AllocationType != MEM_RESET))
+   {
+      DPRINT1("Invalid use of MEM_RESET\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;
    }
-   if ((AllocationType & (MEM_COMMIT | MEM_RESERVE)) == 0)
+
+   /* MEM_PHYSICAL can only be used with MEM_RESERVE, and can only be R/W */
+   if (AllocationType & MEM_PHYSICAL)
    {
-      return(STATUS_INVALID_PARAMETER);
+      /* 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;
-   PRegionSize = *URegionSize;
+   PreviousMode = KeGetPreviousMode();
+
+   _SEH_TRY
+   {
+      if (PreviousMode != KernelMode)
+      {
+         ProbeForWritePointer(UBaseAddress);
+         ProbeForWriteUlong(URegionSize);
+      }
+      PBaseAddress = *UBaseAddress;
+      PRegionSize  = *URegionSize;
+   }
+   _SEH_HANDLE
+   {
+      /* Get the exception code */
+      Status = _SEH_GetExceptionCode();
+      _SEH_YIELD(return Status);
+   }
+   _SEH_END;
+
    BoundaryAddressMultiple.QuadPart = 0;
 
    BaseAddress = (PVOID)PAGE_ROUND_DOWN(PBaseAddress);
-   RegionSize = PAGE_ROUND_UP(PBaseAddress + PRegionSize) -
+   RegionSize = PAGE_ROUND_UP((ULONG_PTR)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 ((ULONG_PTR)BaseAddress >= USER_SHARED_DATA)
+   {
+      DPRINT1("Virtual allocation base above User Space\n");
+      return STATUS_INVALID_PARAMETER_2;
+   }
+   if (!RegionSize)
+   {
+      DPRINT1("Region size is invalid (zero)\n");
+      return STATUS_INVALID_PARAMETER_4;
+   }
+   if ((USER_SHARED_DATA - (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 | 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,
-                                      UserMode,
+                                      PsProcessType,
+                                      PreviousMode,
                                       (PVOID*)(&Process),
                                       NULL);
    if (!NT_SUCCESS(Status))
@@ -590,7 +704,7 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
    Type = (AllocationType & MEM_COMMIT) ? MEM_COMMIT : MEM_RESERVE;
    DPRINT("Type %x\n", Type);
 
-   AddressSpace = &Process->AddressSpace;
+   AddressSpace = &Process->VadRoot;
    MmLockAddressSpace(AddressSpace);
 
    if (PBaseAddress != 0)
@@ -617,12 +731,21 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
          }
          else if (MemoryAreaLength >= RegionSize)
          {
-            Status =
-               MmAlterRegion(AddressSpace,
-                             MemoryArea->StartingAddress,
-                             &MemoryArea->Data.SectionData.RegionListHead,
-                             BaseAddress, RegionSize,
-                             Type, Protect, MmModifyAttributes);
+            /* Region list initialized? */
+            if (MemoryArea->Data.SectionData.RegionListHead.Flink)
+            {
+               Status =
+                  MmAlterRegion(AddressSpace,
+                                MemoryArea->StartingAddress,
+                                &MemoryArea->Data.SectionData.RegionListHead,
+                                BaseAddress, RegionSize,
+                                Type, Protect, MmModifyAttributes);
+            }
+            else
+            {
+               Status = STATUS_ACCESS_VIOLATION;
+            }
+
             MmUnlockAddressSpace(AddressSpace);
             ObDereferenceObject(Process);
             DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
@@ -637,15 +760,14 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
       }
    }
 
-   Status = MmCreateMemoryArea(Process,
-                               AddressSpace,
+   Status = MmCreateMemoryArea(AddressSpace,
                                MEMORY_AREA_VIRTUAL_MEMORY,
                                &BaseAddress,
                                RegionSize,
                                Protect,
                                &MemoryArea,
                                PBaseAddress != 0,
-                               (AllocationType & MEM_TOP_DOWN) == MEM_TOP_DOWN,
+                               AllocationType & MEM_TOP_DOWN,
                                BoundaryAddressMultiple);
    if (!NT_SUCCESS(Status))
    {
@@ -658,14 +780,14 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
    MemoryAreaLength = (ULONG_PTR)MemoryArea->EndingAddress -
                       (ULONG_PTR)MemoryArea->StartingAddress;
 
-   MmInitialiseRegion(&MemoryArea->Data.VirtualMemoryData.RegionListHead,
+   MmInitializeRegion(&MemoryArea->Data.VirtualMemoryData.RegionListHead,
                       MemoryAreaLength, Type, Protect);
 
    if ((AllocationType & MEM_COMMIT) &&
-         ((Protect & PAGE_READWRITE) ||
-          (Protect & PAGE_EXECUTE_READWRITE)))
+       (Protect & (PAGE_READWRITE | PAGE_EXECUTE_READWRITE)))
    {
-      MmReserveSwapPages(MemoryAreaLength);
+      const ULONG nPages = PAGE_ROUND_UP(MemoryAreaLength) >> PAGE_SHIFT;
+      MmReserveSwapPages(nPages);
    }
 
    *UBaseAddress = BaseAddress;
@@ -677,7 +799,7 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
    return(STATUS_SUCCESS);
 }
 
-VOID STATIC
+VOID static
 MmFreeVirtualMemoryPage(PVOID Context,
                         MEMORY_AREA* MemoryArea,
                         PVOID Address,
@@ -706,6 +828,7 @@ MmFreeVirtualMemoryPage(PVOID Context,
 }
 
 VOID
+NTAPI
 MmFreeVirtualMemory(PEPROCESS Process,
                     PMEMORY_AREA MemoryArea)
 {
@@ -727,24 +850,18 @@ MmFreeVirtualMemory(PEPROCESS Process,
    {
       ULONG_PTR MemoryAreaLength = (ULONG_PTR)MemoryArea->EndingAddress -
                                    (ULONG_PTR)MemoryArea->StartingAddress;
+      const ULONG nPages = PAGE_ROUND_UP(MemoryAreaLength) >> PAGE_SHIFT;
 
-      /* FiN TODO: Optimize loop counter! */
-      for (i = 0; i < PAGE_ROUND_UP(MemoryAreaLength) / PAGE_SIZE; i++)
+      for (i = 0; i < nPages && MemoryArea->PageOpCount != 0; ++i)
       {
          PMM_PAGEOP PageOp;
-
-         if (MemoryArea->PageOpCount == 0)
-         {
-            break;
-         }
-
          PageOp = MmCheckForPageOp(MemoryArea, Process->UniqueProcessId,
                                    (PVOID)((ULONG_PTR)MemoryArea->StartingAddress + (i * PAGE_SIZE)),
                                    NULL, 0);
          if (PageOp != NULL)
          {
             NTSTATUS Status;
-            MmUnlockAddressSpace(&Process->AddressSpace);
+            MmUnlockAddressSpace(&Process->VadRoot);
             Status = KeWaitForSingleObject(&PageOp->CompletionEvent,
                                            0,
                                            KernelMode,
@@ -755,7 +872,7 @@ MmFreeVirtualMemory(PEPROCESS Process,
                DPRINT1("Failed to wait for page op\n");
                KEBUGCHECK(0);
             }
-            MmLockAddressSpace(&Process->AddressSpace);
+            MmLockAddressSpace(&Process->VadRoot);
             MmReleasePageOp(PageOp);
          }
       }
@@ -771,7 +888,7 @@ MmFreeVirtualMemory(PEPROCESS Process,
    }
 
    /* Actually free the memory area. */
-   MmFreeMemoryArea(&Process->AddressSpace,
+   MmFreeMemoryArea(&Process->VadRoot,
                     MemoryArea,
                     MmFreeVirtualMemoryPage,
                     (PVOID)Process);
@@ -783,7 +900,7 @@ MmFreeVirtualMemory(PEPROCESS Process,
 NTSTATUS STDCALL
 NtFreeVirtualMemory(IN HANDLE ProcessHandle,
                     IN PVOID*  PBaseAddress,
-                    IN PULONG PRegionSize,
+                    IN PSIZE_T PRegionSize,
                     IN ULONG FreeType)
 /*
  * FUNCTION: Frees a range of virtual memory
@@ -801,7 +918,7 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle,
    MEMORY_AREA* MemoryArea;
    NTSTATUS Status;
    PEPROCESS Process;
-   PMADDRESS_SPACE AddressSpace;
+   PMM_AVL_TABLE AddressSpace;
    PVOID BaseAddress;
    ULONG RegionSize;
 
@@ -810,7 +927,7 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle,
           *PRegionSize,FreeType);
 
    BaseAddress = (PVOID)PAGE_ROUND_DOWN((*PBaseAddress));
-   RegionSize = PAGE_ROUND_UP((*PBaseAddress) + (*PRegionSize)) -
+   RegionSize = PAGE_ROUND_UP((ULONG_PTR)(*PBaseAddress) + (*PRegionSize)) -
                 PAGE_ROUND_DOWN((*PBaseAddress));
 
    Status = ObReferenceObjectByHandle(ProcessHandle,
@@ -824,15 +941,14 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle,
       return(Status);
    }
 
-   AddressSpace = &Process->AddressSpace;
+   AddressSpace = &Process->VadRoot;
 
    MmLockAddressSpace(AddressSpace);
    MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
    if (MemoryArea == NULL)
    {
-      MmUnlockAddressSpace(AddressSpace);
-      ObDereferenceObject(Process);
-      return(STATUS_UNSUCCESSFUL);
+      Status = STATUS_UNSUCCESSFUL;
+      goto unlock_deref_and_return;
    }
 
    switch (FreeType)
@@ -842,14 +958,13 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle,
          if (MemoryArea->StartingAddress != BaseAddress ||
              MemoryArea->Type != MEMORY_AREA_VIRTUAL_MEMORY)
          {
-            MmUnlockAddressSpace(AddressSpace);
-            ObDereferenceObject(Process);
-            return(STATUS_UNSUCCESSFUL);
+            Status = STATUS_UNSUCCESSFUL;
+            goto unlock_deref_and_return;
          }
+
          MmFreeVirtualMemory(Process, MemoryArea);
-         MmUnlockAddressSpace(AddressSpace);
-         ObDereferenceObject(Process);
-         return(STATUS_SUCCESS);
+         Status = STATUS_SUCCESS;
+         goto unlock_deref_and_return;
 
       case MEM_DECOMMIT:
          Status =
@@ -861,17 +976,22 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle,
                           MEM_RESERVE,
                           PAGE_NOACCESS,
                           MmModifyAttributes);
-         MmUnlockAddressSpace(AddressSpace);
-         ObDereferenceObject(Process);
-         return(Status);
+         goto unlock_deref_and_return;
    }
+
+   Status = STATUS_NOT_IMPLEMENTED;
+
+unlock_deref_and_return:
+
    MmUnlockAddressSpace(AddressSpace);
    ObDereferenceObject(Process);
-   return(STATUS_NOT_IMPLEMENTED);
+
+   return(Status);
 }
 
 NTSTATUS
-MmProtectAnonMem(PMADDRESS_SPACE AddressSpace,
+NTAPI
+MmProtectAnonMem(PMM_AVL_TABLE AddressSpace,
                  PMEMORY_AREA MemoryArea,
                  PVOID BaseAddress,
                  ULONG Length,
@@ -899,7 +1019,7 @@ MmQueryAnonMem(PMEMORY_AREA MemoryArea,
                PULONG ResultLength)
 {
    PMM_REGION Region;
-   PVOID RegionBase;
+   PVOID RegionBase = NULL;
 
    Info->BaseAddress = (PVOID)PAGE_ROUND_DOWN(Address);
 
@@ -908,8 +1028,8 @@ MmQueryAnonMem(PMEMORY_AREA MemoryArea,
                          Address, &RegionBase);
    Info->BaseAddress = RegionBase;
    Info->AllocationBase = MemoryArea->StartingAddress;
-   Info->AllocationProtect = MemoryArea->Attributes;
-   Info->RegionSize = (char*)RegionBase + Region->Length - (char*)Info->BaseAddress;
+   Info->AllocationProtect = MemoryArea->Protect;
+   Info->RegionSize = Region->Length;
    Info->State = Region->Type;
    Info->Protect = Region->Protect;
    Info->Type = MEM_PRIVATE;