Merge 36852, 37322, 37333, 37334, 43428, 43451, 44259, 46404 from amd64 branch.
[reactos.git] / reactos / ntoskrnl / mm / anonmem.c
index c0ba5b8..5645352 100644 (file)
 
 NTSTATUS
 NTAPI
-MmWritePageVirtualMemory(PMM_AVL_TABLE AddressSpace,
+MmWritePageVirtualMemory(PMMSUPPORT AddressSpace,
                          PMEMORY_AREA MemoryArea,
                          PVOID Address,
                          PMM_PAGEOP PageOp)
 {
    SWAPENTRY SwapEntry;
-   PFN_TYPE Page;
+   PFN_NUMBER Page;
    NTSTATUS Status;
    PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
 
@@ -130,12 +130,12 @@ MmWritePageVirtualMemory(PMM_AVL_TABLE AddressSpace,
 
 NTSTATUS
 NTAPI
-MmPageOutVirtualMemory(PMM_AVL_TABLE AddressSpace,
+MmPageOutVirtualMemory(PMMSUPPORT AddressSpace,
                        PMEMORY_AREA MemoryArea,
                        PVOID Address,
                        PMM_PAGEOP PageOp)
 {
-   PFN_TYPE Page;
+   PFN_NUMBER Page;
    BOOLEAN WasDirty;
    SWAPENTRY SwapEntry;
    NTSTATUS Status;
@@ -163,7 +163,7 @@ MmPageOutVirtualMemory(PMM_AVL_TABLE AddressSpace,
 
    if (Page == 0)
    {
-      ASSERT(FALSE);
+      KeBugCheck(MEMORY_MANAGEMENT);
    }
 
    /*
@@ -239,7 +239,7 @@ MmPageOutVirtualMemory(PMM_AVL_TABLE AddressSpace,
 
 NTSTATUS
 NTAPI
-MmNotPresentFaultVirtualMemory(PMM_AVL_TABLE AddressSpace,
+MmNotPresentFaultVirtualMemory(PMMSUPPORT AddressSpace,
                                MEMORY_AREA* MemoryArea,
                                PVOID Address,
                                BOOLEAN Locked)
@@ -253,7 +253,7 @@ MmNotPresentFaultVirtualMemory(PMM_AVL_TABLE AddressSpace,
  * NOTES: This function is called with the address space lock held.
  */
 {
-   PFN_TYPE Page;
+   PFN_NUMBER Page;
    NTSTATUS Status;
    PMM_REGION Region;
    PMM_PAGEOP PageOp;
@@ -266,10 +266,6 @@ MmNotPresentFaultVirtualMemory(PMM_AVL_TABLE AddressSpace,
     */
    if (MmIsPagePresent(NULL, Address))
    {
-      if (Locked)
-      {
-         MmLockPage(MmGetPfnForProcess(NULL, Address));
-      }
       return(STATUS_SUCCESS);
    }
 
@@ -287,11 +283,20 @@ MmNotPresentFaultVirtualMemory(PMM_AVL_TABLE AddressSpace,
    Region = MmFindRegion(MemoryArea->StartingAddress,
                          &MemoryArea->Data.VirtualMemoryData.RegionListHead,
                          Address, NULL);
+
    if (Region->Type == MEM_RESERVE || Region->Protect == PAGE_NOACCESS)
    {
       return(STATUS_ACCESS_VIOLATION);
    }
 
+   /*
+    * FIXME
+    */
+    if (Region->Protect & PAGE_GUARD)
+    {
+        return(STATUS_GUARD_PAGE_VIOLATION);
+    }
+
    /*
     * Get or create a page operation
     */
@@ -301,7 +306,7 @@ MmNotPresentFaultVirtualMemory(PMM_AVL_TABLE AddressSpace,
    if (PageOp == NULL)
    {
       DPRINT1("MmGetPageOp failed");
-      ASSERT(FALSE);
+      KeBugCheck(MEMORY_MANAGEMENT);
    }
 
    /*
@@ -322,12 +327,12 @@ MmNotPresentFaultVirtualMemory(PMM_AVL_TABLE AddressSpace,
       if (Status != STATUS_SUCCESS)
       {
          DPRINT1("Failed to wait for page op\n");
-         ASSERT(FALSE);
+         KeBugCheck(MEMORY_MANAGEMENT);
       }
       if (PageOp->Status == STATUS_PENDING)
       {
          DPRINT1("Woke for page op before completion\n");
-         ASSERT(FALSE);
+         KeBugCheck(MEMORY_MANAGEMENT);
       }
       /*
       * If this wasn't a pagein then we need to restart the handling
@@ -351,10 +356,6 @@ MmNotPresentFaultVirtualMemory(PMM_AVL_TABLE AddressSpace,
          return(Status);
       }
       MmLockAddressSpace(AddressSpace);
-      if (Locked)
-      {
-         MmLockPage(MmGetPfnForProcess(NULL, Address));
-      }
       KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
       MmReleasePageOp(PageOp);
       return(STATUS_SUCCESS);
@@ -373,7 +374,7 @@ MmNotPresentFaultVirtualMemory(PMM_AVL_TABLE AddressSpace,
    if (!NT_SUCCESS(Status))
    {
       DPRINT1("MmRequestPageMemoryConsumer failed, status = %x\n", Status);
-      ASSERT(FALSE);
+      KeBugCheck(MEMORY_MANAGEMENT);
    }
 
    /*
@@ -387,7 +388,7 @@ MmNotPresentFaultVirtualMemory(PMM_AVL_TABLE AddressSpace,
       Status = MmReadFromSwapPage(SwapEntry, Page);
       if (!NT_SUCCESS(Status))
       {
-         ASSERT(FALSE);
+         KeBugCheck(MEMORY_MANAGEMENT);
       }
       MmSetSavedSwapEntryPage(Page, SwapEntry);
    }
@@ -414,7 +415,7 @@ MmNotPresentFaultVirtualMemory(PMM_AVL_TABLE AddressSpace,
    if (!NT_SUCCESS(Status))
    {
       DPRINT1("MmCreateVirtualMapping failed, not out of memory\n");
-      ASSERT(FALSE);
+      KeBugCheck(MEMORY_MANAGEMENT);
       return(Status);
    }
 
@@ -426,18 +427,14 @@ MmNotPresentFaultVirtualMemory(PMM_AVL_TABLE AddressSpace,
    /*
     * Finish the operation
     */
-   if (Locked)
-   {
-      MmLockPage(Page);
-   }
    PageOp->Status = STATUS_SUCCESS;
    KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
    MmReleasePageOp(PageOp);
    return(STATUS_SUCCESS);
 }
 
-VOID static
-MmModifyAttributes(PMM_AVL_TABLE AddressSpace,
+static VOID
+MmModifyAttributes(PMMSUPPORT AddressSpace,
                    PVOID BaseAddress,
                    ULONG RegionSize,
                    ULONG OldType,
@@ -460,7 +457,7 @@ MmModifyAttributes(PMM_AVL_TABLE AddressSpace,
 
       for (i=0; i < PAGE_ROUND_UP(RegionSize)/PAGE_SIZE; i++)
       {
-         PFN_TYPE Page;
+         PFN_NUMBER Page;
 
          if (MmIsPageSwapEntry(Process,
                                (char*)BaseAddress + (i * PAGE_SIZE)))
@@ -519,7 +516,7 @@ MmModifyAttributes(PMM_AVL_TABLE AddressSpace,
 /*
  * @implemented
  */
-NTSTATUS STDCALL
+NTSTATUS NTAPI
 NtAllocateVirtualMemory(IN     HANDLE ProcessHandle,
                         IN OUT PVOID* UBaseAddress,
                         IN     ULONG_PTR  ZeroBits,
@@ -541,10 +538,7 @@ NtAllocateVirtualMemory(IN     HANDLE ProcessHandle,
  *      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
+ *      Protect = Indicates the protection type of the pages allocated.
  * RETURNS: Status
  */
 {
@@ -553,11 +547,12 @@ NtAllocateVirtualMemory(IN     HANDLE ProcessHandle,
    ULONG_PTR MemoryAreaLength;
    ULONG Type;
    NTSTATUS Status;
-   PMM_AVL_TABLE AddressSpace;
+   PMMSUPPORT AddressSpace;
    PVOID BaseAddress;
    ULONG RegionSize;
    PVOID PBaseAddress;
    ULONG PRegionSize;
+   ULONG MemProtection;
    PHYSICAL_ADDRESS BoundaryAddressMultiple;
    KPROCESSOR_MODE PreviousMode;
 
@@ -569,7 +564,15 @@ NtAllocateVirtualMemory(IN     HANDLE ProcessHandle,
           Protect);
 
    /* Check for valid protection flags */
-   if ((Protect & PAGE_FLAGS_VALID_FROM_USER_MODE) != Protect)
+   MemProtection = Protect & ~(PAGE_GUARD|PAGE_NOCACHE);
+   if (MemProtection != PAGE_NOACCESS &&
+       MemProtection != PAGE_READONLY &&
+       MemProtection != PAGE_READWRITE &&
+       MemProtection != PAGE_WRITECOPY &&
+       MemProtection != PAGE_EXECUTE &&
+       MemProtection != PAGE_EXECUTE_READ &&
+       MemProtection != PAGE_EXECUTE_READWRITE &&
+       MemProtection != PAGE_EXECUTE_WRITECOPY)
    {
       DPRINT1("Invalid page protection\n");
       return STATUS_INVALID_PAGE_PROTECTION;
@@ -632,7 +635,7 @@ NtAllocateVirtualMemory(IN     HANDLE ProcessHandle,
 
    PreviousMode = KeGetPreviousMode();
 
-   _SEH_TRY
+   _SEH2_TRY
    {
       if (PreviousMode != KernelMode)
       {
@@ -642,13 +645,12 @@ NtAllocateVirtualMemory(IN     HANDLE ProcessHandle,
       PBaseAddress = *UBaseAddress;
       PRegionSize  = *URegionSize;
    }
-   _SEH_HANDLE
+   _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
    {
-      /* Get the exception code */
-      Status = _SEH_GetExceptionCode();
-      _SEH_YIELD(return Status);
+      /* Return the exception code */
+      _SEH2_YIELD(return _SEH2_GetExceptionCode());
    }
-   _SEH_END;
+   _SEH2_END;
 
    BoundaryAddressMultiple.QuadPart = 0;
 
@@ -704,7 +706,7 @@ NtAllocateVirtualMemory(IN     HANDLE ProcessHandle,
    Type = (AllocationType & MEM_COMMIT) ? MEM_COMMIT : MEM_RESERVE;
    DPRINT("Type %x\n", Type);
 
-   AddressSpace = &Process->VadRoot;
+   AddressSpace = &Process->Vm;
    MmLockAddressSpace(AddressSpace);
 
    if (PBaseAddress != 0)
@@ -715,6 +717,36 @@ NtAllocateVirtualMemory(IN     HANDLE ProcessHandle,
       {
          MemoryAreaLength = (ULONG_PTR)MemoryArea->EndingAddress -
                             (ULONG_PTR)MemoryArea->StartingAddress;
+
+         if (((ULONG_PTR)BaseAddress + RegionSize) > (ULONG_PTR)MemoryArea->EndingAddress)
+         {
+            DPRINT("BaseAddress + RegionSize %x is larger than MemoryArea's EndingAddress %x\n",
+                  (ULONG_PTR)BaseAddress + RegionSize, MemoryArea->EndingAddress);
+
+            MmUnlockAddressSpace(AddressSpace);
+            ObDereferenceObject(Process);
+
+            return STATUS_MEMORY_NOT_ALLOCATED;
+         }
+
+         if (AllocationType == MEM_RESET)
+         {
+            if (MmIsPagePresent(Process, BaseAddress))
+            {
+               /* FIXME: mark pages as not modified */
+            }
+            else
+            {
+               /* FIXME: if pages are in paging file discard them and bring in pages of zeros */
+            }
+
+            MmUnlockAddressSpace(AddressSpace);
+            ObDereferenceObject(Process);
+
+            /* MEM_RESET does not modify any attributes of region */
+            return STATUS_SUCCESS;
+         }
+
          if (MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY &&
              MemoryAreaLength >= RegionSize)
          {
@@ -817,11 +849,11 @@ NtAllocateVirtualMemory(IN     HANDLE ProcessHandle,
    return(STATUS_SUCCESS);
 }
 
-VOID static
+static VOID
 MmFreeVirtualMemoryPage(PVOID Context,
                         MEMORY_AREA* MemoryArea,
                         PVOID Address,
-                        PFN_TYPE Page,
+                        PFN_NUMBER Page,
                         SWAPENTRY SwapEntry,
                         BOOLEAN Dirty)
 {
@@ -879,7 +911,7 @@ MmFreeVirtualMemory(PEPROCESS Process,
          if (PageOp != NULL)
          {
             NTSTATUS Status;
-            MmUnlockAddressSpace(&Process->VadRoot);
+            MmUnlockAddressSpace(&Process->Vm);
             Status = KeWaitForSingleObject(&PageOp->CompletionEvent,
                                            0,
                                            KernelMode,
@@ -888,9 +920,9 @@ MmFreeVirtualMemory(PEPROCESS Process,
             if (Status != STATUS_SUCCESS)
             {
                DPRINT1("Failed to wait for page op\n");
-               ASSERT(FALSE);
+               KeBugCheck(MEMORY_MANAGEMENT);
             }
-            MmLockAddressSpace(&Process->VadRoot);
+            MmLockAddressSpace(&Process->Vm);
             MmReleasePageOp(PageOp);
          }
       }
@@ -906,7 +938,7 @@ MmFreeVirtualMemory(PEPROCESS Process,
    }
 
    /* Actually free the memory area. */
-   MmFreeMemoryArea(&Process->VadRoot,
+   MmFreeMemoryArea(&Process->Vm,
                     MemoryArea,
                     MmFreeVirtualMemoryPage,
                     (PVOID)Process);
@@ -915,7 +947,7 @@ MmFreeVirtualMemory(PEPROCESS Process,
 /*
  * @implemented
  */
-NTSTATUS STDCALL
+NTSTATUS NTAPI
 NtFreeVirtualMemory(IN HANDLE ProcessHandle,
                     IN PVOID*  PBaseAddress,
                     IN PSIZE_T PRegionSize,
@@ -936,14 +968,38 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle,
    MEMORY_AREA* MemoryArea;
    NTSTATUS Status;
    PEPROCESS Process;
-   PMM_AVL_TABLE AddressSpace;
+   PMMSUPPORT AddressSpace;
    PVOID BaseAddress;
    ULONG RegionSize;
 
+   PAGED_CODE();
+
    DPRINT("NtFreeVirtualMemory(ProcessHandle %x, *PBaseAddress %x, "
           "*PRegionSize %x, FreeType %x)\n",ProcessHandle,*PBaseAddress,
           *PRegionSize,FreeType);
 
+    if (!(FreeType & (MEM_RELEASE | MEM_DECOMMIT)))
+    {
+        DPRINT1("Invalid FreeType\n");
+        return STATUS_INVALID_PARAMETER_4;
+    }
+
+    if (ExGetPreviousMode() != KernelMode)
+    {
+        _SEH2_TRY
+        {
+            /* Probe user pointers */
+            ProbeForWriteSize_t(PRegionSize);
+            ProbeForWritePointer(PBaseAddress);
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            /* Return the exception code */
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
+    }
+
    BaseAddress = (PVOID)PAGE_ROUND_DOWN((*PBaseAddress));
    RegionSize = PAGE_ROUND_UP((ULONG_PTR)(*PBaseAddress) + (*PRegionSize)) -
                 PAGE_ROUND_DOWN((*PBaseAddress));
@@ -959,7 +1015,7 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle,
       return(Status);
    }
 
-   AddressSpace = &Process->VadRoot;
+   AddressSpace = &Process->Vm;
 
    MmLockAddressSpace(AddressSpace);
    MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
@@ -988,7 +1044,9 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle,
          Status =
             MmAlterRegion(AddressSpace,
                           MemoryArea->StartingAddress,
-                          &MemoryArea->Data.VirtualMemoryData.RegionListHead,
+                          (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW) ?
+                             &MemoryArea->Data.SectionData.RegionListHead :
+                             &MemoryArea->Data.VirtualMemoryData.RegionListHead,
                           BaseAddress,
                           RegionSize,
                           MEM_RESERVE,
@@ -1009,7 +1067,7 @@ unlock_deref_and_return:
 
 NTSTATUS
 NTAPI
-MmProtectAnonMem(PMM_AVL_TABLE AddressSpace,
+MmProtectAnonMem(PMMSUPPORT AddressSpace,
                  PMEMORY_AREA MemoryArea,
                  PVOID BaseAddress,
                  ULONG Length,
@@ -1017,20 +1075,51 @@ MmProtectAnonMem(PMM_AVL_TABLE AddressSpace,
                  PULONG OldProtect)
 {
    PMM_REGION Region;
-   NTSTATUS Status;
+   NTSTATUS Status = STATUS_SUCCESS;
+   ULONG LengthCount = 0;
 
-   Region = MmFindRegion(MemoryArea->StartingAddress,
-                         &MemoryArea->Data.VirtualMemoryData.RegionListHead,
-                         BaseAddress, NULL);
-   *OldProtect = Region->Protect;
-   Status = MmAlterRegion(AddressSpace, MemoryArea->StartingAddress,
-                          &MemoryArea->Data.VirtualMemoryData.RegionListHead,
-                          BaseAddress, Length, Region->Type, Protect,
-                          MmModifyAttributes);
-   return(Status);
+   /* Search all Regions in MemoryArea up to Length */
+   /* Every Region up to Length must be committed for success */
+   for (;;)
+   {
+      Region = MmFindRegion(MemoryArea->StartingAddress,
+                            &MemoryArea->Data.VirtualMemoryData.RegionListHead,
+                            (PVOID)((ULONG_PTR)BaseAddress + (ULONG_PTR)LengthCount), NULL);
+
+      /* If a Region was found and it is committed */
+      if ((Region) && (Region->Type == MEM_COMMIT))
+      {
+         LengthCount += Region->Length;
+         if (Length <= LengthCount) break;
+         continue;
+      }
+      /* If Region was found and it is not commited */
+      else if (Region)
+      {
+         Status = STATUS_NOT_COMMITTED;
+         break;
+      }
+      /* If no Region was found at all */
+      else if (LengthCount == 0)
+      {
+         Status = STATUS_INVALID_ADDRESS;
+         break;
+      }
+   }
+
+   if (NT_SUCCESS(Status))
+   {
+       *OldProtect = Region->Protect;
+       Status = MmAlterRegion(AddressSpace, MemoryArea->StartingAddress,
+                              &MemoryArea->Data.VirtualMemoryData.RegionListHead,
+                              BaseAddress, Length, Region->Type, Protect,
+                              MmModifyAttributes);
+   }
+
+   return (Status);
 }
 
-NTSTATUS STDCALL
+NTSTATUS NTAPI
 MmQueryAnonMem(PMEMORY_AREA MemoryArea,
                PVOID Address,
                PMEMORY_BASIC_INFORMATION Info,