[NTOS:MM]
[reactos.git] / reactos / ntoskrnl / mm / ARM3 / section.c
index 09e284e..a71dcd7 100644 (file)
@@ -13,7 +13,7 @@
 #include <debug.h>
 
 #define MODULE_INVOLVED_IN_ARM3
-#include "../ARM3/miarm.h"
+#include <mm/ARM3/miarm.h>
 
 /* GLOBALS ********************************************************************/
 
@@ -198,7 +198,7 @@ MiMakeProtectionMask(IN ULONG Protect)
         }
 
         /* This actually turns on guard page in this scenario! */
-        ProtectMask |= MM_DECOMMIT;
+        ProtectMask |= MM_GUARDPAGE;
     }
 
     /* Check for nocache option */
@@ -608,6 +608,8 @@ MiSegmentDelete(IN PSEGMENT Segment)
     SEGMENT_FLAGS SegmentFlags;
     PSUBSECTION Subsection;
     PMMPTE PointerPte, LastPte, PteForProto;
+    PMMPFN Pfn1;
+    PFN_NUMBER PageFrameIndex;
     MMPTE TempPte;
     KIRQL OldIrql;
 
@@ -621,7 +623,7 @@ MiSegmentDelete(IN PSEGMENT Segment)
 
     /* These things are not supported yet */
     ASSERT(ControlArea->DereferenceList.Flink == NULL);
-    ASSERT(!(ControlArea->u.Flags.Image) & !(ControlArea->u.Flags.File));
+    ASSERT(!(ControlArea->u.Flags.Image) && !(ControlArea->u.Flags.File));
     ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0);
     ASSERT(ControlArea->u.Flags.Rom == 0);
 
@@ -661,7 +663,52 @@ MiSegmentDelete(IN PSEGMENT Segment)
         TempPte = *PointerPte;
         ASSERT(SegmentFlags.LargePages == 0);
         ASSERT(TempPte.u.Hard.Valid == 0);
-        ASSERT(TempPte.u.Soft.Prototype == 1);
+
+        /* See if we should clean things up */
+        if (!(ControlArea->u.Flags.Image) && !(ControlArea->u.Flags.File))
+        {
+            /*
+             * This is a section backed by the pagefile. Now that it doesn't exist anymore,
+             * we can give everything back to the system.
+             */
+            ASSERT(TempPte.u.Soft.Prototype == 0);
+
+            if (TempPte.u.Soft.Transition == 1)
+            {
+                /* We can give the page back for other use */
+                DPRINT("Releasing page for transition PTE %p\n", PointerPte);
+                PageFrameIndex = PFN_FROM_PTE(&TempPte);
+                Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
+
+                /* As this is a paged-backed section, nobody should reference it anymore (no cache or whatever) */
+                ASSERT(Pfn1->u3.ReferenceCount == 0);
+
+                /* And it should be in standby or modified list */
+                ASSERT((Pfn1->u3.e1.PageLocation == ModifiedPageList) || (Pfn1->u3.e1.PageLocation == StandbyPageList));
+
+                /* Unlink it and put it back in free list */
+                MiUnlinkPageFromList(Pfn1);
+
+                /* Temporarily mark this as active and make it free again */
+                Pfn1->u3.e1.PageLocation = ActiveAndValid;
+                MI_SET_PFN_DELETED(Pfn1);
+
+                MiInsertPageInFreeList(PageFrameIndex);
+            }
+            else if (TempPte.u.Soft.PageFileHigh != 0)
+            {
+                /* Should not happen for now */
+                ASSERT(FALSE);
+            }
+        }
+        else
+        {
+            /* unsupported for now */
+            ASSERT(FALSE);
+
+            /* File-backed section must have prototype PTEs */
+            ASSERT(TempPte.u.Soft.Prototype == 1);
+        }
 
         /* Zero the PTE and keep going */
         PointerPte->u.Long = 0;
@@ -890,8 +937,8 @@ MiSessionCommitPageTables(IN PVOID StartVa,
 {
     KIRQL OldIrql;
     ULONG Color, Index;
-    PMMPTE StartPde, EndPde;
-    MMPTE TempPte = ValidKernelPdeLocal;
+    PMMPDE StartPde, EndPde;
+    MMPDE TempPde = ValidKernelPdeLocal;
     PMMPFN Pfn1;
     PFN_NUMBER PageCount = 0, ActualPages = 0, PageFrameNumber;
 
@@ -925,7 +972,15 @@ MiSessionCommitPageTables(IN PVOID StartVa,
     /* Loop each PDE while holding the working set lock */
 //  MiLockWorkingSet(PsGetCurrentThread(),
 //                   &MmSessionSpace->GlobalVirtualAddress->Vm);
-#ifndef _M_AMD64
+#ifdef _M_AMD64
+_WARN("MiSessionCommitPageTables halfplemented for amd64")
+    DBG_UNREFERENCED_LOCAL_VARIABLE(OldIrql);
+    DBG_UNREFERENCED_LOCAL_VARIABLE(Color);
+    DBG_UNREFERENCED_LOCAL_VARIABLE(TempPde);
+    DBG_UNREFERENCED_LOCAL_VARIABLE(Pfn1);
+    DBG_UNREFERENCED_LOCAL_VARIABLE(PageFrameNumber);
+    ASSERT(FALSE);
+#else
     while (StartPde <= EndPde)
     {
         /* Check if we already have a page table */
@@ -941,12 +996,12 @@ MiSessionCommitPageTables(IN PVOID StartVa,
             OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
             Color = (++MmSessionSpace->Color) & MmSecondaryColorMask;
             PageFrameNumber = MiRemoveZeroPage(Color);
-            TempPte.u.Hard.PageFrameNumber = PageFrameNumber;
-            MI_WRITE_VALID_PTE(StartPde, TempPte);
+            TempPde.u.Hard.PageFrameNumber = PageFrameNumber;
+            MI_WRITE_VALID_PDE(StartPde, TempPde);
 
             /* Write the page table in session space structure */
             ASSERT(MmSessionSpace->PageTables[Index].u.Long == 0);
-            MmSessionSpace->PageTables[Index] = TempPte;
+            MmSessionSpace->PageTables[Index] = TempPde;
 
             /* Initialize the PFN */
             MiInitializePfnForOtherProcess(PageFrameNumber,
@@ -1066,7 +1121,7 @@ MiMapViewInSystemSpace(IN PVOID Section,
         Status = MiSessionCommitPageTables(Base,
                                            (PVOID)((ULONG_PTR)Base +
                                            Buckets * MI_SYSTEM_VIEW_BUCKET_SIZE));
-        NT_ASSERT(NT_SUCCESS(Status));
+        ASSERT(NT_SUCCESS(Status));
     }
 
     /* Create the actual prototype PTEs for this mapping */
@@ -1185,7 +1240,7 @@ MiLoadUserSymbols(IN PCONTROL_AREA ControlArea,
     Status = RtlUnicodeStringToAnsiString(&FileNameA, FileName, TRUE);
     if (NT_SUCCESS(Status))
     {
-        DbgLoadImageSymbols(&FileNameA, BaseAddress, (ULONG_PTR)Process);
+        DbgLoadImageSymbols(&FileNameA, BaseAddress, (ULONG_PTR)Process->UniqueProcessId);
         RtlFreeAnsiString(&FileNameA);
     }
 }
@@ -1205,8 +1260,8 @@ MiMapViewOfDataSection(IN PCONTROL_AREA ControlArea,
                        IN ULONG AllocationType)
 {
     PMMVAD_LONG Vad;
-    PETHREAD Thread = PsGetCurrentThread();
-    ULONG_PTR StartAddress, EndingAddress;
+    ULONG_PTR StartAddress;
+    ULONG_PTR ViewSizeInPages;
     PSUBSECTION Subsection;
     PSEGMENT Segment;
     PFN_NUMBER PteOffset;
@@ -1214,19 +1269,25 @@ MiMapViewOfDataSection(IN PCONTROL_AREA ControlArea,
     ULONG QuotaCharge = 0, QuotaExcess = 0;
     PMMPTE PointerPte, LastPte;
     MMPTE TempPte;
+    ULONG Granularity = MM_VIRTMEM_GRANULARITY;
+
+    DPRINT("Mapping ARM3 data section\n");
 
     /* Get the segment for this section */
     Segment = ControlArea->Segment;
 
+#ifdef _M_IX86
+    /* ALlow being less restrictive on x86. */
+    if (AllocationType & MEM_DOS_LIM)
+        Granularity = PAGE_SIZE;
+#endif
+
     /* One can only reserve a file-based mapping, not shared memory! */
     if ((AllocationType & MEM_RESERVE) && !(ControlArea->FilePointer))
     {
         return STATUS_INVALID_PARAMETER_9;
     }
 
-    /* This flag determines alignment, but ARM3 does not yet support it */
-    ASSERT((AllocationType & MEM_DOS_LIM) == 0);
-
     /* First, increase the map count. No purging is supported yet */
     Status = MiCheckPurgeAndUpMapCount(ControlArea, FALSE);
     if (!NT_SUCCESS(Status)) return Status;
@@ -1250,9 +1311,12 @@ MiMapViewOfDataSection(IN PCONTROL_AREA ControlArea,
     /* We must be dealing with a 64KB aligned offset. This is a Windows ASSERT */
     ASSERT((SectionOffset->LowPart & ((ULONG)_64K - 1)) == 0);
 
-    /* It's illegal to try to map more than 2GB */
-    /* FIXME: Should dereference the control area */
-    if (*ViewSize >= 0x80000000) return STATUS_INVALID_VIEW_SIZE;
+    /* It's illegal to try to map more than overflows a LONG_PTR */
+    if (*ViewSize >= MAXLONG_PTR)
+    {
+        MiDereferenceControlArea(ControlArea);
+        return STATUS_INVALID_VIEW_SIZE;
+    }
 
     /* Windows ASSERTs for this flag */
     ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0);
@@ -1283,75 +1347,15 @@ MiMapViewOfDataSection(IN PCONTROL_AREA ControlArea,
     /* Compute how much commit space the segment will take */
     if ((CommitSize) && (Segment->NumberOfCommittedPages < Segment->TotalNumberOfPtes))
     {
-        PointerPte = &Subsection->SubsectionBase[PteOffset];
-        LastPte = PointerPte + BYTES_TO_PAGES(CommitSize);
-        QuotaCharge = (ULONG)(LastPte - PointerPte);
+        /* Charge for the maximum pages */
+        QuotaCharge = BYTES_TO_PAGES(CommitSize);
     }
 
     /* ARM3 does not currently support large pages */
     ASSERT(Segment->SegmentFlags.LargePages == 0);
 
-    /* Did the caller specify an address? */
-    if (!(*BaseAddress) && !(Section->Address.StartingVpn))
-    {
-        /* ARM3 does not support these flags yet */
-        ASSERT(Process->VmTopDown == 0);
-        ASSERT(ZeroBits == 0);
-
-        /* Which way should we search? */
-        if (AllocationType & MEM_TOP_DOWN)
-        {
-            /* No, find an address top-down */
-            Status = MiFindEmptyAddressRangeDownTree(*ViewSize,
-                                                     (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS,
-                                                     _64K,
-                                                     &Process->VadRoot,
-                                                     &StartAddress,
-                                                     (PMMADDRESS_NODE*)&Process->VadFreeHint);
-            ASSERT(NT_SUCCESS(Status));
-        }
-        else
-        {
-            /* No, find an address bottom-up */
-            Status = MiFindEmptyAddressRangeInTree(*ViewSize,
-                                                   _64K,
-                                                   &Process->VadRoot,
-                                                   (PMMADDRESS_NODE*)&Process->VadFreeHint,
-                                                   &StartAddress);
-            ASSERT(NT_SUCCESS(Status));
-        }
-
-        /* Get the ending address, which is the last piece we need for the VAD */
-        EndingAddress = (StartAddress + *ViewSize - 1) | (PAGE_SIZE - 1);
-    }
-    else
-    {
-        /* Is it SEC_BASED, or did the caller manually specify an address? */
-        if (!(*BaseAddress))
-        {
-            /* It is a SEC_BASED mapping, use the address that was generated */
-            StartAddress = Section->Address.StartingVpn + SectionOffset->LowPart;
-            DPRINT("BASED: 0x%p\n", StartAddress);
-        }
-        else
-        {
-            /* Just align what the caller gave us */
-            StartAddress = ROUND_UP((ULONG_PTR)*BaseAddress, _64K);
-        }
-
-        /* Get the ending address, which is the last piece we need for the VAD */
-        EndingAddress = (StartAddress + *ViewSize - 1) | (PAGE_SIZE - 1);
-
-        /* Make sure it doesn't conflict with an existing allocation */
-        if (MiCheckForConflictingNode(StartAddress >> PAGE_SHIFT,
-                                      EndingAddress >> PAGE_SHIFT,
-                                      &Process->VadRoot))
-        {
-            DPRINT1("Conflict with SEC_BASED or manually based section!\n");
-            MiDereferenceControlArea(ControlArea);
-            return STATUS_CONFLICTING_ADDRESSES;
-        }
-    }
+    /* Calculate how many pages the region spans */
+    ViewSizeInPages = BYTES_TO_PAGES(*ViewSize);
 
     /* A VAD can now be allocated. Do so and zero it out */
     /* FIXME: we are allocating a LONG VAD for ReactOS compatibility only */
@@ -1362,13 +1366,13 @@ MiMapViewOfDataSection(IN PCONTROL_AREA ControlArea,
         MiDereferenceControlArea(ControlArea);
         return STATUS_INSUFFICIENT_RESOURCES;
     }
+
     RtlZeroMemory(Vad, sizeof(MMVAD_LONG));
     Vad->u4.Banked = (PVOID)0xDEADBABE;
 
     /* Write all the data required in the VAD for handling a fault */
-    Vad->StartingVpn = StartAddress >> PAGE_SHIFT;
-    Vad->EndingVpn = EndingAddress >> PAGE_SHIFT;
     Vad->ControlArea = ControlArea;
+    Vad->u.VadFlags.CommitCharge = 0;
     Vad->u.VadFlags.Protection = ProtectionMask;
     Vad->u2.VadFlags2.FileOffset = (ULONG)(SectionOffset->QuadPart >> 16);
     Vad->u2.VadFlags2.Inherit = (InheritDisposition == ViewShare);
@@ -1381,7 +1385,7 @@ MiMapViewOfDataSection(IN PCONTROL_AREA ControlArea,
 
     /* Finally, write down the first and last prototype PTE */
     Vad->FirstPrototypePte = &Subsection->SubsectionBase[PteOffset];
-    PteOffset += (Vad->EndingVpn - Vad->StartingVpn);
+    PteOffset += ViewSizeInPages - 1;
     ASSERT(PteOffset < Subsection->PtesInSubsection);
     Vad->LastContiguousPte = &Subsection->SubsectionBase[PteOffset];
 
@@ -1391,18 +1395,6 @@ MiMapViewOfDataSection(IN PCONTROL_AREA ControlArea,
     /* FIXME: Should setup VAD bitmap */
     Status = STATUS_SUCCESS;
 
-    /* Pretend as if we own the working set */
-    MiLockProcessWorkingSetUnsafe(Process, Thread);
-
-    /* Insert the VAD */
-    MiInsertVad((PMMVAD)Vad, Process);
-
-    /* Release the working set */
-    MiUnlockProcessWorkingSetUnsafe(Process, Thread);
-
-    /* Windows stores this for accounting purposes, do so as well */
-    if (!Segment->u2.FirstMappedVa) Segment->u2.FirstMappedVa = (PVOID)StartAddress;
-
     /* Check if anything was committed */
     if (QuotaCharge)
     {
@@ -1412,7 +1404,7 @@ MiMapViewOfDataSection(IN PCONTROL_AREA ControlArea,
         TempPte = Segment->SegmentPteTemplate;
 
         /* Acquire the commit lock and loop all prototype PTEs to be committed */
-        KeAcquireGuardedMutexUnsafe(&MmSectionCommitMutex);
+        KeAcquireGuardedMutex(&MmSectionCommitMutex);
         while (PointerPte < LastPte)
         {
             /* Make sure the PTE is already invalid */
@@ -1438,11 +1430,42 @@ MiMapViewOfDataSection(IN PCONTROL_AREA ControlArea,
         ASSERT(Segment->NumberOfCommittedPages <= Segment->TotalNumberOfPtes);
 
         /* Now that we're done, release the lock */
-        KeReleaseGuardedMutexUnsafe(&MmSectionCommitMutex);
+        KeReleaseGuardedMutex(&MmSectionCommitMutex);
     }
 
+    /* Is it SEC_BASED, or did the caller manually specify an address? */
+    if (*BaseAddress != NULL)
+    {
+        /* Just align what the caller gave us */
+        StartAddress = ALIGN_DOWN_BY((ULONG_PTR)*BaseAddress, Granularity);
+    }
+    else if (Section->Address.StartingVpn != 0)
+    {
+        /* It is a SEC_BASED mapping, use the address that was generated */
+        StartAddress = Section->Address.StartingVpn + SectionOffset->LowPart;
+    }
+    else
+    {
+        StartAddress = 0;
+    }
+
+    /* Insert the VAD */
+    Status = MiInsertVadEx((PMMVAD)Vad,
+                           &StartAddress,
+                           ViewSizeInPages * PAGE_SIZE,
+                           MAXULONG_PTR >> ZeroBits,
+                           Granularity,
+                           AllocationType);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    /* Windows stores this for accounting purposes, do so as well */
+    if (!Segment->u2.FirstMappedVa) Segment->u2.FirstMappedVa = (PVOID)StartAddress;
+
     /* Finally, let the caller know where, and for what size, the view was mapped */
-    *ViewSize = (ULONG_PTR)EndingAddress - (ULONG_PTR)StartAddress + 1;
+    *ViewSize = ViewSizeInPages * PAGE_SIZE;
     *BaseAddress = (PVOID)StartAddress;
     DPRINT("Start and region: 0x%p, 0x%p\n", *BaseAddress, *ViewSize);
     return STATUS_SUCCESS;
@@ -1541,6 +1564,9 @@ MiCreatePagingFileMap(OUT PSEGMENT *Segment,
     if (AllocationAttributes & SEC_RESERVE) ControlArea->u.Flags.Reserve = 1;
     if (AllocationAttributes & SEC_COMMIT) ControlArea->u.Flags.Commit = 1;
 
+    /* We just allocated it */
+    ControlArea->u.Flags.BeingCreated = 1;
+
     /* The subsection follows, write the mask, PTE count and point back to the CA */
     Subsection = (PSUBSECTION)(ControlArea + 1);
     Subsection->ControlArea = ControlArea;
@@ -1585,6 +1611,69 @@ MiCreatePagingFileMap(OUT PSEGMENT *Segment,
     return STATUS_SUCCESS;
 }
 
+NTSTATUS
+NTAPI
+MiGetFileObjectForSectionAddress(
+    IN PVOID Address,
+    OUT PFILE_OBJECT *FileObject)
+{
+    PMMVAD Vad;
+    PCONTROL_AREA ControlArea;
+
+    /* Get the VAD */
+    Vad = MiLocateAddress(Address);
+    if (Vad == NULL)
+    {
+        /* Fail, the address does not exist */
+        DPRINT1("Invalid address\n");
+        return STATUS_INVALID_ADDRESS;
+    }
+
+    /* Check if this is a RosMm memory area */
+    if (Vad->u.VadFlags.Spare != 0)
+    {
+        PMEMORY_AREA MemoryArea = (PMEMORY_AREA)Vad;
+        PROS_SECTION_OBJECT Section;
+
+        /* Check if it's a section view (RosMm section) */
+        if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW)
+        {
+            /* Get the section pointer to the SECTION_OBJECT */
+            Section = MemoryArea->Data.SectionData.Section;
+            *FileObject = Section->FileObject;
+        }
+        else
+        {
+            ASSERT(MemoryArea->Type == MEMORY_AREA_CACHE);
+            DPRINT1("Address is a cache section!\n");
+            return STATUS_SECTION_NOT_IMAGE;
+        }
+    }
+    else
+    {
+        /* Make sure it's not a VM VAD */
+        if (Vad->u.VadFlags.PrivateMemory == 1)
+        {
+            DPRINT1("Address is not a section\n");
+            return STATUS_SECTION_NOT_IMAGE;
+        }
+
+        /* Get the control area */
+        ControlArea = Vad->ControlArea;
+        if (!(ControlArea) || !(ControlArea->u.Flags.Image))
+        {
+            DPRINT1("Address is not a section\n");
+            return STATUS_SECTION_NOT_IMAGE;
+        }
+
+        /* Get the file object */
+        *FileObject = ControlArea->FilePointer;
+    }
+
+    /* Return success */
+    return STATUS_SUCCESS;
+}
+
 PFILE_OBJECT
 NTAPI
 MmGetFileObjectForSection(IN PVOID SectionObject)
@@ -1605,6 +1694,59 @@ MmGetFileObjectForSection(IN PVOID SectionObject)
     return ((PROS_SECTION_OBJECT)SectionObject)->FileObject;
 }
 
+static
+PFILE_OBJECT
+MiGetFileObjectForVad(
+    _In_ PMMVAD Vad)
+{
+    PCONTROL_AREA ControlArea;
+    PFILE_OBJECT FileObject;
+
+    /* Check if this is a RosMm memory area */
+    if (Vad->u.VadFlags.Spare != 0)
+    {
+        PMEMORY_AREA MemoryArea = (PMEMORY_AREA)Vad;
+        PROS_SECTION_OBJECT Section;
+
+        /* Check if it's a section view (RosMm section) */
+        if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW)
+        {
+            /* Get the section pointer to the SECTION_OBJECT */
+            Section = MemoryArea->Data.SectionData.Section;
+            FileObject = Section->FileObject;
+        }
+        else
+        {
+            ASSERT(MemoryArea->Type == MEMORY_AREA_CACHE);
+            DPRINT1("VAD is a cache section!\n");
+            return NULL;
+        }
+    }
+    else
+    {
+        /* Make sure it's not a VM VAD */
+        if (Vad->u.VadFlags.PrivateMemory == 1)
+        {
+            DPRINT1("VAD is not a section\n");
+            return NULL;
+        }
+
+        /* Get the control area */
+        ControlArea = Vad->ControlArea;
+        if ((ControlArea == NULL) || !ControlArea->u.Flags.Image)
+        {
+            DPRINT1("Address is not a section\n");
+            return NULL;
+        }
+
+        /* Get the file object */
+        FileObject = ControlArea->FilePointer;
+    }
+
+    /* Return the file object */
+    return FileObject;
+}
+
 VOID
 NTAPI
 MmGetImageInformation (OUT PSECTION_IMAGE_INFORMATION ImageInformation)
@@ -1617,7 +1759,6 @@ MmGetImageInformation (OUT PSECTION_IMAGE_INFORMATION ImageInformation)
     ASSERT(MiIsRosSectionObject(SectionObject) == TRUE);
 
     /* Return the image information */
-    DPRINT1("HERE!\n");
     *ImageInformation = ((PROS_SECTION_OBJECT)SectionObject)->ImageSection->ImageInformation;
 }
 
@@ -1688,92 +1829,57 @@ NTAPI
 MmGetFileNameForAddress(IN PVOID Address,
                         OUT PUNICODE_STRING ModuleName)
 {
-   PVOID Section;
-   PMEMORY_AREA MemoryArea;
-   POBJECT_NAME_INFORMATION ModuleNameInformation;
-   PVOID AddressSpace;
-   NTSTATUS Status;
-   PFILE_OBJECT FileObject = NULL;
-   PMMVAD Vad;
-   PCONTROL_AREA ControlArea;
-
-   /* Lock address space */
-   AddressSpace = MmGetCurrentAddressSpace();
-   MmLockAddressSpace(AddressSpace);
-
-   /* Locate the memory area for the process by address */
-   MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address);
-   if (!MemoryArea)
-   {
-       /* Fail, the address does not exist */
-InvalidAddress:
-       DPRINT1("Invalid address\n");
-       MmUnlockAddressSpace(AddressSpace);
-       return STATUS_INVALID_ADDRESS;
-   }
-
-   /* Check if it's a section view (RosMm section) or ARM3 section */
-   if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW)
-   {
-      /* Get the section pointer to the SECTION_OBJECT */
-      Section = MemoryArea->Data.SectionData.Section;
-
-      /* Unlock address space */
-      MmUnlockAddressSpace(AddressSpace);
-
-      /* Get the filename of the section */
-      Status = MmGetFileNameForSection(Section, &ModuleNameInformation);
-   }
-   else if (MemoryArea->Type == MEMORY_AREA_OWNED_BY_ARM3)
-   {
-       /* Get the VAD */
-       Vad = MiLocateAddress(Address);
-       if (!Vad) goto InvalidAddress;
-
-       /* Make sure it's not a VM VAD */
-       if (Vad->u.VadFlags.PrivateMemory == 1)
-       {
-NotSection:
-           DPRINT1("Address is not a section\n");
-           MmUnlockAddressSpace(AddressSpace);
-           return STATUS_SECTION_NOT_IMAGE;
-       }
-
-       /* Get the control area */
-       ControlArea = Vad->ControlArea;
-       if (!(ControlArea) || !(ControlArea->u.Flags.Image)) goto NotSection;
-
-       /* Get the file object */
-       FileObject = ControlArea->FilePointer;
-       ASSERT(FileObject != NULL);
-       ObReferenceObject(FileObject);
-
-       /* Unlock address space */
-       MmUnlockAddressSpace(AddressSpace);
-
-       /* Get the filename of the file object */
-       Status = MmGetFileNameForFileObject(FileObject, &ModuleNameInformation);
-
-       /* Dereference it */
-       ObDereferenceObject(FileObject);
-   }
-   else
-   {
-       /* Trying to access virtual memory or something */
-       goto InvalidAddress;
-   }
-
-   /* Check if we were able to get the file object name */
-   if (NT_SUCCESS(Status))
-   {
+    POBJECT_NAME_INFORMATION ModuleNameInformation;
+    PVOID AddressSpace;
+    NTSTATUS Status;
+    PMMVAD Vad;
+    PFILE_OBJECT FileObject = NULL;
+
+    /* Lock address space */
+    AddressSpace = MmGetCurrentAddressSpace();
+    MmLockAddressSpace(AddressSpace);
+
+    /* Get the VAD */
+    Vad = MiLocateAddress(Address);
+    if (Vad == NULL)
+    {
+        /* Fail, the address does not exist */
+        DPRINT1("No VAD at address %p\n", Address);
+        MmUnlockAddressSpace(AddressSpace);
+        return STATUS_INVALID_ADDRESS;
+    }
+
+    /* Get the file object pointer for the VAD */
+    FileObject = MiGetFileObjectForVad(Vad);
+    if (FileObject == NULL)
+    {
+        DPRINT1("Failed to get file object for Address %p\n", Address);
+        MmUnlockAddressSpace(AddressSpace);
+        return STATUS_SECTION_NOT_IMAGE;
+    }
+
+    /* Reference the file object */
+    ObReferenceObject(FileObject);
+
+    /* Unlock address space */
+    MmUnlockAddressSpace(AddressSpace);
+
+    /* Get the filename of the file object */
+    Status = MmGetFileNameForFileObject(FileObject, &ModuleNameInformation);
+
+    /* Dereference the file object */
+    ObDereferenceObject(FileObject);
+
+    /* Check if we were able to get the file object name */
+    if (NT_SUCCESS(Status))
+    {
         /* Init modulename */
-       RtlCreateUnicodeString(ModuleName,
-                              ModuleNameInformation->Name.Buffer);
+        RtlCreateUnicodeString(ModuleName, ModuleNameInformation->Name.Buffer);
 
-       /* Free temp taged buffer from MmGetFileNameForFileObject() */
-       ExFreePoolWithTag(ModuleNameInformation, TAG_MM);
-       DPRINT("Found ModuleName %S by address %p\n", ModuleName->Buffer, Address);
-   }
+        /* Free temp taged buffer from MmGetFileNameForFileObject() */
+        ExFreePoolWithTag(ModuleNameInformation, TAG_MM);
+        DPRINT("Found ModuleName %S by address %p\n", ModuleName->Buffer, Address);
+    }
 
    /* Return status */
    return Status;
@@ -1850,7 +1956,7 @@ MiFlushTbAndCapture(IN PMMVAD FoundVad,
                     IN PMMPTE PointerPte,
                     IN ULONG ProtectionMask,
                     IN PMMPFN Pfn1,
-                    IN BOOLEAN CaptureDirtyBit)
+                    IN BOOLEAN UpdateDirty)
 {
     MMPTE TempPte, PreviousPte;
     KIRQL OldIrql;
@@ -1914,10 +2020,7 @@ MiFlushTbAndCapture(IN PMMVAD FoundVad,
     //
     // Write the new PTE, making sure we are only changing the bits
     //
-    ASSERT(PointerPte->u.Hard.Valid == 1);
-    ASSERT(TempPte.u.Hard.Valid == 1);
-    ASSERT(PointerPte->u.Hard.PageFrameNumber == TempPte.u.Hard.PageFrameNumber);
-    MI_WRITE_VALID_PTE(PointerPte, TempPte);
+    MI_UPDATE_VALID_PTE(PointerPte, TempPte);
 
     //
     // Flush the TLB
@@ -1929,7 +2032,13 @@ MiFlushTbAndCapture(IN PMMVAD FoundVad,
     //
     // Windows updates the relevant PFN1 information, we currently don't.
     //
-    if (CaptureDirtyBit) DPRINT1("Warning, not handling dirty bit\n");
+    if (UpdateDirty && PreviousPte.u.Hard.Dirty)
+    {
+        if (!Pfn1->u3.e1.Modified)
+        {
+            DPRINT1("FIXME: Mark PFN as dirty\n");
+        }
+    }
 
     //
     // Not supported in ARM3
@@ -2039,7 +2148,7 @@ MiSetProtectionOnSection(IN PEPROCESS Process,
         //
         if ((((ULONG_PTR)PointerPte) & (SYSTEM_PD_SIZE - 1)) == 0)
         {
-            PointerPde = MiAddressToPte(PointerPte);
+            PointerPde = MiPteToPde(PointerPte);
             MiMakePdeExistAndMakeValid(PointerPde, Process, MM_NOIRQL);
         }
 
@@ -2121,13 +2230,15 @@ MiRemoveMappedPtes(IN PVOID BaseAddress,
                    IN PCONTROL_AREA ControlArea,
                    IN PMMSUPPORT Ws)
 {
-    PMMPTE PointerPte;//, FirstPte;
+    PMMPTE PointerPte, ProtoPte;//, FirstPte;
     PMMPDE PointerPde, SystemMapPde;
     PMMPFN Pfn1, Pfn2;
     MMPTE PteContents;
     KIRQL OldIrql;
     DPRINT("Removing mapped view at: 0x%p\n", BaseAddress);
 
+    ASSERT(Ws == NULL);
+
     /* Get the PTE and loop each one */
     PointerPte = MiAddressToPte(BaseAddress);
     //FirstPte = PointerPte;
@@ -2141,13 +2252,15 @@ MiRemoveMappedPtes(IN PVOID BaseAddress,
             Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(&PteContents));
 
             /* Get the PTE */
-            PointerPde = MiAddressToPte(PointerPte);
+            PointerPde = MiPteToPde(PointerPte);
 
             /* Lock the PFN database and make sure this isn't a mapped file */
             OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
             ASSERT(((Pfn1->u3.e1.PrototypePte) && (Pfn1->OriginalPte.u.Soft.Prototype)) == 0);
 
-            /* FIXME: Dirty bit management */
+            /* Mark the page as modified accordingly */
+            if (MI_IS_PAGE_DIRTY(&PteContents))
+                Pfn1->u3.e1.Modified = 1;
 
             /* Was the PDE invalid */
             if (PointerPde->u.Long == 0)
@@ -2160,13 +2273,14 @@ MiRemoveMappedPtes(IN PVOID BaseAddress,
                 ASSERT(SystemMapPde->u.Hard.Valid == 1);
                 MI_WRITE_VALID_PDE(PointerPde, *SystemMapPde);
 #else
+                DBG_UNREFERENCED_LOCAL_VARIABLE(SystemMapPde);
                 ASSERT(FALSE);
 #endif
             }
 
             /* Dereference the PDE and the PTE */
             Pfn2 = MiGetPfnEntry(PFN_FROM_PTE(PointerPde));
-            //MiDecrementShareCount(Pfn2, PFN_FROM_PTE(PointerPde));
+            MiDecrementShareCount(Pfn2, PFN_FROM_PTE(PointerPde));
             DBG_UNREFERENCED_LOCAL_VARIABLE(Pfn2);
             MiDecrementShareCount(Pfn1, PFN_FROM_PTE(&PteContents));
 
@@ -2178,8 +2292,15 @@ MiRemoveMappedPtes(IN PVOID BaseAddress,
             /* Windows ASSERT */
             ASSERT((PteContents.u.Long == 0) || (PteContents.u.Soft.Prototype == 1));
 
-            /* But not handled in ARM3 */
-            ASSERT(PteContents.u.Soft.Prototype == 0);
+            /* Check if this is a prototype pointer PTE */
+            if (PteContents.u.Soft.Prototype == 1)
+            {
+                /* Get the prototype PTE */
+                ProtoPte = MiProtoPteToPte(&PteContents);
+
+                /* We don't support anything else atm */
+                ASSERT(ProtoPte->u.Long == 0);
+            }
         }
 
         /* Make the PTE into a zero PTE */
@@ -2304,6 +2425,7 @@ MmCreateArm3Section(OUT PVOID *SectionObject,
     BOOLEAN FileLock = FALSE, KernelCall = FALSE;
     KIRQL OldIrql;
     PFILE_OBJECT File;
+    BOOLEAN UserRefIncremented = FALSE;
     PVOID PreviousSectionPointer;
 
     /* Make the same sanity checks that the Nt interface should've validated */
@@ -2401,6 +2523,7 @@ MmCreateArm3Section(OUT PVOID *SectionObject,
 
         /* Write down that this CA is being created, and set it */
         ControlArea->u.Flags.BeingCreated = TRUE;
+        ASSERT((AllocationAttributes & SEC_IMAGE) == 0);
         PreviousSectionPointer = File->SectionObjectPointer;
         File->SectionObjectPointer->DataSectionObject = ControlArea;
 
@@ -2420,8 +2543,47 @@ MmCreateArm3Section(OUT PVOID *SectionObject,
                                      SectionPageProtection,
                                      AllocationAttributes,
                                      KernelCall);
+        if (!NT_SUCCESS(Status))
+        {
+            /* Lock the PFN database while we play with the section pointers */
+            OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+            /* Reset the waiting-for-deletion event */
+            ASSERT(ControlArea->WaitingForDeletion == NULL);
+            ControlArea->WaitingForDeletion = NULL;
+
+            /* Set the file pointer NULL flag */
+            ASSERT(ControlArea->u.Flags.FilePointerNull == 0);
+            ControlArea->u.Flags.FilePointerNull = TRUE;
+
+            /* Delete the data section object */
+            ASSERT((AllocationAttributes & SEC_IMAGE) == 0);
+            File->SectionObjectPointer->DataSectionObject = NULL;
+
+            /* No longer being created */
+            ControlArea->u.Flags.BeingCreated = FALSE;
+
+            /* We can release the PFN lock now */
+            KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+
+            /* Check if we locked and set the IRP */
+            if (FileLock)
+            {
+                /* Undo */
+                IoSetTopLevelIrp(NULL);
+                //FsRtlReleaseFile(File);
+            }
+
+            /* Free the control area and de-ref the file object */
+            ExFreePool(ControlArea);
+            ObDereferenceObject(File);
+
+            /* All done */
+            return Status;
+        }
+
+        /* On success, we expect this */
         ASSERT(PreviousSectionPointer == File->SectionObjectPointer);
-        ASSERT(NT_SUCCESS(Status));
 
         /* Check if a maximum size was specified */
         if (!InputMaximumSize->QuadPart)
@@ -2453,6 +2615,9 @@ MmCreateArm3Section(OUT PVOID *SectionObject,
         /* Set the size here, and read the control area */
         Section.SizeOfSection.QuadPart = NewSegment->SizeOfSegment;
         ControlArea = NewSegment->ControlArea;
+
+        /* MiCreatePagingFileMap increments user references */
+        UserRefIncremented = TRUE;
     }
 
     /* Did we already have a segment? */
@@ -2497,16 +2662,16 @@ MmCreateArm3Section(OUT PVOID *SectionObject,
     /* Check if this is a user-mode read-write non-image file mapping */
     if (!(FileObject) &&
         (SectionPageProtection & (PAGE_READWRITE | PAGE_EXECUTE_READWRITE)) &&
-        (ControlArea->u.Flags.Image == 0) &&
-        (ControlArea->FilePointer != NULL))
+        !(ControlArea->u.Flags.Image) &&
+        (ControlArea->FilePointer))
     {
         /* Add a reference and set the flag */
-        Section.u.Flags.UserWritable = 1;
-        InterlockedIncrement((PLONG)&ControlArea->WritableUserReferences);
+        Section.u.Flags.UserWritable = TRUE;
+        InterlockedIncrement((volatile LONG*)&ControlArea->WritableUserReferences);
     }
 
     /* Check for image mappings or page file mappings */
-    if ((ControlArea->u.Flags.Image == 1) || !(ControlArea->FilePointer))
+    if ((ControlArea->u.Flags.Image) || !(ControlArea->FilePointer))
     {
         /* Charge the segment size, and allocate a subsection */
         PagedCharge = sizeof(SECTION) + NewSegment->TotalNumberOfPtes * sizeof(MMPTE);
@@ -2541,7 +2706,39 @@ MmCreateArm3Section(OUT PVOID *SectionObject,
                             PagedCharge,
                             NonPagedCharge,
                             (PVOID*)&NewSection);
-    ASSERT(NT_SUCCESS(Status));
+    if (!NT_SUCCESS(Status))
+    {
+        /* Check if this is a user-mode read-write non-image file mapping */
+        if (!(FileObject) &&
+            (SectionPageProtection & (PAGE_READWRITE | PAGE_EXECUTE_READWRITE)) &&
+            !(ControlArea->u.Flags.Image) &&
+            (ControlArea->FilePointer))
+        {
+            /* Remove a reference and check the flag */
+            ASSERT(Section.u.Flags.UserWritable == 1);
+            InterlockedDecrement((volatile LONG*)&ControlArea->WritableUserReferences);
+        }
+
+        /* Check if a user reference was added */
+        if (UserRefIncremented)
+        {
+            /* Acquire the PFN lock while we change counters */
+            OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+            /* Decrement the accounting counters */
+            ControlArea->NumberOfSectionReferences--;
+            ASSERT((LONG)ControlArea->NumberOfUserReferences > 0);
+            ControlArea->NumberOfUserReferences--;
+
+            /* Check if we should destroy the CA and release the lock */
+            MiCheckControlArea(ControlArea, OldIrql);
+        }
+
+        /* Return the failure code */
+        return Status;
+    }
+
+    /* NOTE: Past this point, all failures will be handled by Ob upon ref->0 */
 
     /* Now copy the local section object from the stack into this new object */
     RtlCopyMemory(NewSection, &Section, sizeof(SECTION));
@@ -2551,49 +2748,69 @@ MmCreateArm3Section(OUT PVOID *SectionObject,
     ASSERT(KernelCall == FALSE);
     NewSection->u.Flags.UserReference = TRUE;
 
-    /* Migrate the attribute into a flag */
-    if (AllocationAttributes & SEC_NO_CHANGE) NewSection->u.Flags.NoChange = TRUE;
-
-    /* If R/W access is not requested, this might eventually become a CoW mapping */
-    if (!(SectionPageProtection & (PAGE_READWRITE | PAGE_EXECUTE_READWRITE)))
-    {
-        NewSection->u.Flags.CopyOnWrite = TRUE;
-    }
-
     /* Is this a "based" allocation, in which all mappings are identical? */
     if (AllocationAttributes & SEC_BASED)
     {
-        /* Convert the flag, and make sure the section isn't too big */
-        NewSection->u.Flags.Based = TRUE;
-        if ((ULONGLONG)NewSection->SizeOfSection.QuadPart >
-            (ULONG_PTR)MmHighSectionBase)
-        {
-            DPRINT1("BASED section is too large\n");
-            ObDereferenceObject(NewSection);
-            return STATUS_NO_MEMORY;
-        }
-
         /* Lock the VAD tree during the search */
         KeAcquireGuardedMutex(&MmSectionBasedMutex);
 
-        /* Find an address top-down */
-        Status = MiFindEmptyAddressRangeDownBasedTree(NewSection->SizeOfSection.LowPart,
-                                                      (ULONG_PTR)MmHighSectionBase,
-                                                      _64K,
-                                                      &MmSectionBasedRoot,
-                                                      &NewSection->Address.StartingVpn);
-        ASSERT(NT_SUCCESS(Status));
+        /* Is it a brand new ControArea ? */
+        if (ControlArea->u.Flags.BeingCreated == 1)
+        {
+            ASSERT(ControlArea->u.Flags.Based == 1);
+            /* Then we must find a global address, top-down */
+            Status = MiFindEmptyAddressRangeDownBasedTree((SIZE_T)ControlArea->Segment->SizeOfSegment,
+                                                          (ULONG_PTR)MmHighSectionBase,
+                                                          _64K,
+                                                          &MmSectionBasedRoot,
+                                                          (ULONG_PTR*)&ControlArea->Segment->BasedAddress);
 
-        /* Compute the ending address and insert it into the VAD tree */
-        NewSection->Address.EndingVpn = NewSection->Address.StartingVpn +
-                                        NewSection->SizeOfSection.LowPart -
-                                        1;
-        MiInsertBasedSection(NewSection);
+            if (!NT_SUCCESS(Status))
+            {
+                /* No way to find a valid range. */
+                KeReleaseGuardedMutex(&MmSectionBasedMutex);
+                ControlArea->u.Flags.Based = 0;
+                NewSection->u.Flags.Based = 0;
+                ObDereferenceObject(NewSection);
+                return Status;
+            }
+
+            /* Compute the ending address and insert it into the VAD tree */
+            NewSection->Address.StartingVpn = (ULONG_PTR)ControlArea->Segment->BasedAddress;
+            NewSection->Address.EndingVpn = NewSection->Address.StartingVpn + NewSection->SizeOfSection.LowPart - 1;
+            MiInsertBasedSection(NewSection);
+        }
+        else
+        {
+            /* FIXME : Should we deny section creation if SEC_BASED is not set ? Can we have two different section objects on the same based address ? Investigate !*/
+            ASSERT(FALSE);
+        }
 
-        /* Finally release the lock */
         KeReleaseGuardedMutex(&MmSectionBasedMutex);
     }
 
+    /* The control area is not being created anymore */
+    if (ControlArea->u.Flags.BeingCreated == 1)
+    {
+        /* Acquire the PFN lock while we set control area flags */
+        OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+        /* Take off the being created flag, and then release the lock */
+        ControlArea->u.Flags.BeingCreated = 0;
+        NewSection->u.Flags.BeingCreated = 0;
+
+        KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+    }
+
+    /* Migrate the attribute into a flag */
+    if (AllocationAttributes & SEC_NO_CHANGE) NewSection->u.Flags.NoChange = TRUE;
+
+    /* If R/W access is not requested, this might eventually become a CoW mapping */
+    if (!(SectionPageProtection & (PAGE_READWRITE | PAGE_EXECUTE_READWRITE)))
+    {
+        NewSection->u.Flags.CopyOnWrite = TRUE;
+    }
+
     /* Write down if this was a kernel call */
     ControlArea->u.Flags.WasPurged |= KernelCall;
     ASSERT(ControlArea->u.Flags.WasPurged == FALSE);
@@ -2638,9 +2855,15 @@ MmMapViewOfArm3Section(IN PVOID SectionObject,
     ASSERT(Section->u.Flags.Image == 0);
     ASSERT(Section->u.Flags.NoCache == 0);
     ASSERT(Section->u.Flags.WriteCombined == 0);
-    ASSERT((AllocationType & MEM_RESERVE) == 0);
     ASSERT(ControlArea->u.Flags.PhysicalMemory == 0);
 
+    /* FIXME */
+    if ((AllocationType & MEM_RESERVE) != 0)
+    {
+        DPRINT1("MmMapViewOfArm3Section called with MEM_RESERVE, this is not implemented yet!!!\n");
+        return STATUS_NOT_IMPLEMENTED;
+    }
+
     /* Check if the mapping protection is compatible with the create */
     if (!MiIsProtectionCompatible(Section->InitialPageProtection, Protect))
     {
@@ -2715,33 +2938,20 @@ MmMapViewOfArm3Section(IN PVOID SectionObject,
         Attached = TRUE;
     }
 
-    /* Lock the address space and make sure the process is alive */
-    MmLockAddressSpace(&Process->Vm);
-    if (!Process->VmDeleted)
-    {
-        /* Do the actual mapping */
-        DPRINT("Mapping ARM3 data section\n");
-        Status = MiMapViewOfDataSection(ControlArea,
-                                        Process,
-                                        BaseAddress,
-                                        SectionOffset,
-                                        ViewSize,
-                                        Section,
-                                        InheritDisposition,
-                                        ProtectionMask,
-                                        CommitSize,
-                                        ZeroBits,
-                                        AllocationType);
-    }
-    else
-    {
-        /* The process is being terminated, fail */
-        DPRINT1("The process is dying\n");
-        Status = STATUS_PROCESS_IS_TERMINATING;
-    }
-
-    /* Unlock the address space and detatch if needed, then return status */
-    MmUnlockAddressSpace(&Process->Vm);
+    /* Do the actual mapping */
+    Status = MiMapViewOfDataSection(ControlArea,
+                                    Process,
+                                    BaseAddress,
+                                    SectionOffset,
+                                    ViewSize,
+                                    Section,
+                                    InheritDisposition,
+                                    ProtectionMask,
+                                    CommitSize,
+                                    ZeroBits,
+                                    AllocationType);
+
+    /* Detach if needed, then return status */
     if (Attached) KeUnstackDetachProcess(&ApcState);
     return Status;
 }
@@ -3027,6 +3237,50 @@ MmCommitSessionMappedView(IN PVOID MappedBase,
     return STATUS_SUCCESS;
 }
 
+VOID
+NTAPI
+MiDeleteARM3Section(PVOID ObjectBody)
+{
+    PSECTION SectionObject;
+    PCONTROL_AREA ControlArea;
+    KIRQL OldIrql;
+
+    SectionObject = (PSECTION)ObjectBody;
+
+    if (SectionObject->u.Flags.Based == 1)
+    {
+        /* Remove the node from the global section address tree */
+        KeAcquireGuardedMutex(&MmSectionBasedMutex);
+        MiRemoveNode(&SectionObject->Address, &MmSectionBasedRoot);
+        KeReleaseGuardedMutex(&MmSectionBasedMutex);
+    }
+
+    /* Lock the PFN database */
+    OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+    ASSERT(SectionObject->Segment);
+    ASSERT(SectionObject->Segment->ControlArea);
+
+    ControlArea = SectionObject->Segment->ControlArea;
+
+    /* Dereference */
+    ControlArea->NumberOfSectionReferences--;
+    ControlArea->NumberOfUserReferences--;
+
+    ASSERT(ControlArea->u.Flags.BeingDeleted == 0);
+
+    /* Check it. It will delete it if there is no more reference to it */
+    MiCheckControlArea(ControlArea, OldIrql);
+}
+
+ULONG
+NTAPI
+MmDoesFileHaveUserWritableReferences(IN PSECTION_OBJECT_POINTERS SectionPointer)
+{
+    UNIMPLEMENTED;
+    return 0;
+}
+
 /* SYSTEM CALLS ***************************************************************/
 
 NTSTATUS
@@ -3035,74 +3289,74 @@ NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage,
                         IN PVOID File2MappedAsFile)
 {
     PVOID AddressSpace;
-    PMEMORY_AREA MemoryArea1, MemoryArea2;
-    PROS_SECTION_OBJECT Section1, Section2;
+    PMMVAD Vad1, Vad2;
+    PFILE_OBJECT FileObject1, FileObject2;
+    NTSTATUS Status;
 
     /* Lock address space */
     AddressSpace = MmGetCurrentAddressSpace();
     MmLockAddressSpace(AddressSpace);
 
-    /* Locate the memory area for the process by address */
-    MemoryArea1 = MmLocateMemoryAreaByAddress(AddressSpace, File1MappedAsAnImage);
-    if (!MemoryArea1)
+    /* Get the VAD for Address 1 */
+    Vad1 = MiLocateAddress(File1MappedAsAnImage);
+    if (Vad1 == NULL)
     {
         /* Fail, the address does not exist */
-        MmUnlockAddressSpace(AddressSpace);
-        return STATUS_INVALID_ADDRESS;
+        DPRINT1("No VAD at address 1 %p\n", File1MappedAsAnImage);
+        Status = STATUS_INVALID_ADDRESS;
+        goto Exit;
     }
 
-    /* Check if it's a section view (RosMm section) or ARM3 section */
-    if (MemoryArea1->Type != MEMORY_AREA_SECTION_VIEW)
+    /* Get the VAD for Address 2 */
+    Vad2 = MiLocateAddress(File2MappedAsFile);
+    if (Vad2 == NULL)
     {
-        /* Fail, the address is not a section */
-        MmUnlockAddressSpace(AddressSpace);
-        return STATUS_CONFLICTING_ADDRESSES;
+        /* Fail, the address does not exist */
+        DPRINT1("No VAD at address 2 %p\n", File2MappedAsFile);
+        Status = STATUS_INVALID_ADDRESS;
+        goto Exit;
     }
 
-    /* Get the section pointer to the SECTION_OBJECT */
-    Section1 = MemoryArea1->Data.SectionData.Section;
-    if (Section1->FileObject == NULL)
+    /* Get the file object pointer for VAD 1 */
+    FileObject1 = MiGetFileObjectForVad(Vad1);
+    if (FileObject1 == NULL)
     {
-        MmUnlockAddressSpace(AddressSpace);
-        return STATUS_CONFLICTING_ADDRESSES;
+        DPRINT1("Failed to get file object for Address 1 %p\n", File1MappedAsAnImage);
+        Status = STATUS_CONFLICTING_ADDRESSES;
+        goto Exit;
     }
 
-    /* Locate the memory area for the process by address */
-    MemoryArea2 = MmLocateMemoryAreaByAddress(AddressSpace, File2MappedAsFile);
-    if (!MemoryArea2)
+    /* Get the file object pointer for VAD 2 */
+    FileObject2 = MiGetFileObjectForVad(Vad2);
+    if (FileObject2 == NULL)
     {
-        /* Fail, the address does not exist */
-        MmUnlockAddressSpace(AddressSpace);
-        return STATUS_INVALID_ADDRESS;
+        DPRINT1("Failed to get file object for Address 2 %p\n", File2MappedAsFile);
+        Status = STATUS_CONFLICTING_ADDRESSES;
+        goto Exit;
     }
 
-    /* Check if it's a section view (RosMm section) or ARM3 section */
-    if (MemoryArea2->Type != MEMORY_AREA_SECTION_VIEW)
+    /* Make sure Vad1 is an image mapping */
+    if (Vad1->u.VadFlags.VadType != VadImageMap)
     {
-        /* Fail, the address is not a section */
-        MmUnlockAddressSpace(AddressSpace);
-        return STATUS_CONFLICTING_ADDRESSES;
+        DPRINT1("Address 1 (%p) is not an image mapping\n", File1MappedAsAnImage);
+        Status = STATUS_NOT_SAME_DEVICE;
+        goto Exit;
     }
 
-    /* Get the section pointer to the SECTION_OBJECT */
-    Section2 = MemoryArea2->Data.SectionData.Section;
-    if (Section2->FileObject == NULL)
+    /* SectionObjectPointer is equal if the files are equal */
+    if (FileObject1->SectionObjectPointer == FileObject2->SectionObjectPointer)
     {
-        MmUnlockAddressSpace(AddressSpace);
-        return STATUS_CONFLICTING_ADDRESSES;
+        Status = STATUS_SUCCESS;
     }
-
-    /* The shared cache map seems to be the same if both of these are equal */
-    if (Section1->FileObject->SectionObjectPointer->SharedCacheMap ==
-        Section2->FileObject->SectionObjectPointer->SharedCacheMap)
+    else
     {
-        MmUnlockAddressSpace(AddressSpace);
-        return STATUS_SUCCESS;
+        Status = STATUS_NOT_SAME_DEVICE;
     }
 
+Exit:
     /* Unlock address space */
     MmUnlockAddressSpace(AddressSpace);
-    return STATUS_NOT_SAME_DEVICE;
+    return Status;
 }
 
 /*
@@ -3311,13 +3565,13 @@ NtMapViewOfSection(IN HANDLE SectionHandle,
     ACCESS_MASK DesiredAccess;
     ULONG ProtectionMask;
     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
-
-    /* Check for invalid zero bits */
-    if (ZeroBits > 21) // per-arch?
-    {
-        DPRINT1("Invalid zero bits\n");
-        return STATUS_INVALID_PARAMETER_4;
-    }
+#ifdef _M_IX86
+    static const ULONG ValidAllocationType = (MEM_TOP_DOWN | MEM_LARGE_PAGES |
+            MEM_DOS_LIM | SEC_NO_CHANGE | MEM_RESERVE);
+#else
+    static const ULONG ValidAllocationType = (MEM_TOP_DOWN | MEM_LARGE_PAGES |
+            SEC_NO_CHANGE | MEM_RESERVE);
+#endif
 
     /* Check for invalid inherit disposition */
     if ((InheritDisposition > ViewUnmap) || (InheritDisposition < ViewShare))
@@ -3327,8 +3581,7 @@ NtMapViewOfSection(IN HANDLE SectionHandle,
     }
 
     /* Allow only valid allocation types */
-    if ((AllocationType & ~(MEM_TOP_DOWN | MEM_LARGE_PAGES | MEM_DOS_LIM |
-                            SEC_NO_CHANGE | MEM_RESERVE)))
+    if (AllocationType & ~ValidAllocationType)
     {
         DPRINT1("Invalid allocation type\n");
         return STATUS_INVALID_PARAMETER_9;
@@ -3342,13 +3595,6 @@ NtMapViewOfSection(IN HANDLE SectionHandle,
         return STATUS_INVALID_PAGE_PROTECTION;
     }
 
-    /* Check for non-allocation-granularity-aligned BaseAddress */
-    if (BaseAddress && (*BaseAddress != ALIGN_DOWN_POINTER_BY(*BaseAddress, MM_VIRTMEM_GRANULARITY)))
-    {
-       DPRINT("BaseAddress is not at 64-kilobyte address boundary.");
-       return STATUS_MAPPED_ALIGNMENT;
-    }
-
     /* Now convert the protection mask into desired section access mask */
     DesiredAccess = MmMakeSectionAccess[ProtectionMask & 0x7];
 
@@ -3400,10 +3646,25 @@ NtMapViewOfSection(IN HANDLE SectionHandle,
     }
 
     /* Check for invalid zero bits */
-    if (((ULONG_PTR)SafeBaseAddress + SafeViewSize) > (0xFFFFFFFF >> ZeroBits)) // arch?
+    if (ZeroBits)
     {
-        DPRINT1("Invalid zero bits\n");
-        return STATUS_INVALID_PARAMETER_4;
+        if (ZeroBits > MI_MAX_ZERO_BITS)
+        {
+            DPRINT1("Invalid zero bits\n");
+            return STATUS_INVALID_PARAMETER_4;
+        }
+
+        if ((((ULONG_PTR)SafeBaseAddress << ZeroBits) >> ZeroBits) != (ULONG_PTR)SafeBaseAddress)
+        {
+            DPRINT1("Invalid zero bits\n");
+            return STATUS_INVALID_PARAMETER_4;
+        }
+
+        if (((((ULONG_PTR)SafeBaseAddress + SafeViewSize) << ZeroBits) >> ZeroBits) != ((ULONG_PTR)SafeBaseAddress + SafeViewSize))
+        {
+            DPRINT1("Invalid zero bits\n");
+            return STATUS_INVALID_PARAMETER_4;
+        }
     }
 
     /* Reference the process */
@@ -3428,6 +3689,39 @@ NtMapViewOfSection(IN HANDLE SectionHandle,
         return Status;
     }
 
+    if (MiIsRosSectionObject(Section) &&
+        (Section->AllocationAttributes & SEC_PHYSICALMEMORY))
+    {
+        if (PreviousMode == UserMode &&
+            SafeSectionOffset.QuadPart + SafeViewSize > MmHighestPhysicalPage << PAGE_SHIFT)
+        {
+            DPRINT1("Denying map past highest physical page.\n");
+            ObDereferenceObject(Section);
+            ObDereferenceObject(Process);
+            return STATUS_INVALID_PARAMETER_6;
+        }
+    }
+    else if (!(AllocationType & MEM_DOS_LIM))
+    {
+        /* Check for non-allocation-granularity-aligned BaseAddress */
+        if (SafeBaseAddress != ALIGN_DOWN_POINTER_BY(SafeBaseAddress, MM_VIRTMEM_GRANULARITY))
+        {
+            DPRINT("BaseAddress is not at 64-kilobyte address boundary.\n");
+            ObDereferenceObject(Section);
+            ObDereferenceObject(Process);
+            return STATUS_MAPPED_ALIGNMENT;
+        }
+
+        /* Do the same for the section offset */
+        if (SafeSectionOffset.LowPart != ALIGN_DOWN_BY(SafeSectionOffset.LowPart, MM_VIRTMEM_GRANULARITY))
+        {
+            DPRINT("SectionOffset is not at 64-kilobyte address boundary.\n");
+            ObDereferenceObject(Section);
+            ObDereferenceObject(Process);
+            return STATUS_MAPPED_ALIGNMENT;
+        }
+    }
+
     /* Now do the actual mapping */
     Status = MmMapViewOfSection(Section,
                                 Process,
@@ -3444,7 +3738,8 @@ NtMapViewOfSection(IN HANDLE SectionHandle,
     if (NT_SUCCESS(Status))
     {
         /* Check if this is an image for the current process */
-        if ((Section->AllocationAttributes & SEC_IMAGE) &&
+        if (MiIsRosSectionObject(Section) &&
+            (Section->AllocationAttributes & SEC_IMAGE) &&
             (Process == PsGetCurrentProcess()) &&
             (Status != STATUS_IMAGE_NOT_AT_BASE))
         {