Author: sir_richard
Date: Mon Apr  2 07:23:49 2012
New Revision: 56317

URL: http://svn.reactos.org/svn/reactos?rev=56317&view=rev
Log:
[NTOS]: Add support for unmapping ARM3 sections. Trunk should now be ready for 
switching to ARM3 shared-memory, pagefile-backed sections, instead of Ros Mm.

Modified:
    trunk/reactos/ntoskrnl/mm/ARM3/section.c
    trunk/reactos/ntoskrnl/mm/section.c

Modified: trunk/reactos/ntoskrnl/mm/ARM3/section.c
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/section.c?rev=56317&r1=56316&r2=56317&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/section.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/section.c [iso-8859-1] Mon Apr  2 07:23:49 
2012
@@ -688,6 +688,111 @@
 
 NTSTATUS
 NTAPI
+MiUnmapViewOfSection(IN PEPROCESS Process,
+                     IN PVOID BaseAddress,
+                     IN ULONG Flags)
+{
+    PMEMORY_AREA MemoryArea;
+    BOOLEAN Attached = FALSE;
+    KAPC_STATE ApcState;
+    PMMVAD Vad;
+    PVOID DbgBase = NULL;
+    SIZE_T RegionSize;
+    NTSTATUS Status;
+    PAGED_CODE();
+
+    /* Check for Mm Region */
+    MemoryArea = MmLocateMemoryAreaByAddress(&Process->Vm, BaseAddress);
+    if ((MemoryArea) && (MemoryArea->Type != MEMORY_AREA_OWNED_BY_ARM3))
+    {
+        /* Call Mm API */
+        return MiRosUnmapViewOfSection(Process, BaseAddress, Flags);
+    }
+
+    /* Check if we should attach to the process */
+    if (PsGetCurrentProcess() != Process)
+    {
+        /* The process is different, do an attach */
+        KeStackAttachProcess(&Process->Pcb, &ApcState);
+        Attached = TRUE;
+    }
+
+    /* Check if we need to lock the address space */
+    if (!Flags) MmLockAddressSpace(&Process->Vm);
+
+    /* Check if the process is already daed */
+    if (Process->VmDeleted)
+    {
+        /* Fail the call */
+        DPRINT1("Process died!\n");
+        if (!Flags) MmUnlockAddressSpace(&Process->Vm);
+        Status = STATUS_PROCESS_IS_TERMINATING;
+        goto Quickie;
+    }
+
+    /* Find the VAD for the address and make sure it's a section VAD */
+    Vad = MiLocateAddress(BaseAddress);
+    if (!(Vad) || (Vad->u.VadFlags.PrivateMemory))
+    {
+        /* Couldn't find it, or invalid VAD, fail */
+        DPRINT1("No VAD or invalid VAD\n");
+        if (!Flags) MmUnlockAddressSpace(&Process->Vm);
+        Status = STATUS_NOT_MAPPED_VIEW;
+        goto Quickie;
+    }
+
+    /* We should be attached */
+    ASSERT(Process == PsGetCurrentProcess());
+
+    /* We need the base address for the debugger message on image-backed VADs 
*/
+    if (Vad->u.VadFlags.VadType == VadImageMap)
+    {
+        DbgBase = (PVOID)(Vad->StartingVpn >> PAGE_SHIFT);
+    }
+
+    /* Compute the size of the VAD region */
+    RegionSize = PAGE_SIZE + ((Vad->EndingVpn - Vad->StartingVpn) << 
PAGE_SHIFT);
+
+    /* For SEC_NO_CHANGE sections, we need some extra checks */
+    if (Vad->u.VadFlags.NoChange == 1)
+    {
+        DPRINT1("Unmapping SEC_NO_CHANGE. Should validate if allowed!\n");
+    }
+
+    /* Not currently supported */
+    ASSERT(Vad->u.VadFlags.VadType != VadRotatePhysical);
+
+    /* FIXME: Remove VAD charges */
+
+    /* Lock the working set */
+    MiLockWorkingSet(PsGetCurrentThread(), &Process->Vm);
+
+    /* Remove the VAD */
+    ASSERT(Process->VadRoot.NumberGenericTableElements >= 1);
+    MiRemoveNode((PMMADDRESS_NODE)Vad, &Process->VadRoot);
+
+    /* Remove the PTEs for this view */
+    MiRemoveMappedView(Process, Vad);
+
+    /* FIXME: Remove commitment */
+
+    /* Update performance counter and release the lock */
+    Process->VirtualSize -= RegionSize;
+    if (!Flags) MmUnlockAddressSpace(&Process->Vm);
+
+    /* Destroy the VAD and return success */
+    ExFreePool(Vad);
+    Status = STATUS_SUCCESS;
+
+    /* Failure and success case -- send debugger message, detach, and return */
+Quickie:
+    if (DbgBase) DbgkUnMapViewOfSection(DbgBase);
+    if (Attached) KeUnstackDetachProcess(&ApcState);
+    return Status;
+}
+
+NTSTATUS
+NTAPI
 MiMapViewInSystemSpace(IN PVOID Section,
                        IN PMMSESSION Session,
                        OUT PVOID *MappedBase,
@@ -1355,6 +1460,404 @@
     }
     ObDereferenceObject(Process);
     return Status;
+}
+
+VOID
+NTAPI
+MiFlushTbAndCapture(IN PMMVAD FoundVad,
+                    IN PMMPTE PointerPte,
+                    IN ULONG ProtectionMask,
+                    IN PMMPFN Pfn1,
+                    IN BOOLEAN CaptureDirtyBit)
+{
+    MMPTE TempPte, PreviousPte;
+    KIRQL OldIrql;
+
+    //
+    // User for sanity checking later on
+    //
+    PreviousPte = *PointerPte;
+
+    //
+    // Build the PTE and acquire the PFN lock
+    //
+    MI_MAKE_HARDWARE_PTE_USER(&TempPte,
+                              PointerPte,
+                              ProtectionMask,
+                              PreviousPte.u.Hard.PageFrameNumber);
+    OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+    //
+    // We don't support I/O mappings in this path yet, and only cached memory
+    //
+    ASSERT(Pfn1 != NULL);
+    ASSERT(Pfn1->u3.e1.CacheAttribute == MiCached);
+    ASSERT((ProtectionMask & (MM_NOCACHE | MM_NOACCESS)) == 0);
+
+    //
+    // 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);
+    *PointerPte = TempPte;
+
+    //
+    // Flush the TLB
+    //
+    ASSERT(PreviousPte.u.Hard.Valid == 1);
+    KeFlushCurrentTb();
+    ASSERT(PreviousPte.u.Hard.Valid == 1);
+
+    //
+    // Windows updates the relevant PFN1 information, we currently don't.
+    //
+    if (CaptureDirtyBit) DPRINT1("Warning, not handling dirty bit\n");
+
+    //
+    // Not supported in ARM3
+    //
+    ASSERT(FoundVad->u.VadFlags.VadType != VadWriteWatch);
+
+    //
+    // Release the PFN lock, we are done
+    //
+    KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+}
+
+//
+// NOTE: This function gets a lot more complicated if we want Copy-on-Write 
support
+//
+NTSTATUS
+NTAPI
+MiSetProtectionOnSection(IN PEPROCESS Process,
+                         IN PMMVAD FoundVad,
+                         IN PVOID StartingAddress,
+                         IN PVOID EndingAddress,
+                         IN ULONG NewProtect,
+                         OUT PULONG CapturedOldProtect,
+                         IN ULONG DontCharge,
+                         OUT PULONG Locked)
+{
+    PMMPTE PointerPte, LastPte;
+    MMPTE TempPte, PteContents;
+    PMMPDE PointerPde;
+    PMMPFN Pfn1;
+    ULONG ProtectionMask, QuotaCharge = 0;
+    PUSHORT UsedPageTableEntries;
+    //PETHREAD Thread = PsGetCurrentThread();
+    PAGED_CODE();
+
+    //
+    // Tell caller nothing is being locked
+    //
+    *Locked = FALSE;
+
+    //
+    // This function should only be used for section VADs. Windows ASSERT */
+    //
+    ASSERT(FoundVad->u.VadFlags.PrivateMemory == 0);
+
+    //
+    // We don't support these features in ARM3
+    //
+    ASSERT(FoundVad->u.VadFlags.VadType != VadImageMap);
+    ASSERT(FoundVad->u2.VadFlags2.CopyOnWrite == 0);
+
+    //
+    // Convert and validate the protection mask
+    //
+    ProtectionMask = MiMakeProtectionMask(NewProtect);
+    if (ProtectionMask == MM_INVALID_PROTECTION)
+    {
+        DPRINT1("Invalid section protect\n");
+        return STATUS_INVALID_PAGE_PROTECTION;
+    }
+
+    //
+    // Get the PTE and PDE for the address, as well as the final PTE
+    //
+    //MiLockProcessWorkingSet(Thread, Process);
+    PointerPde = MiAddressToPde(StartingAddress);
+    PointerPte = MiAddressToPte(StartingAddress);
+    LastPte = MiAddressToPte(EndingAddress);
+
+    //
+    // Make the PDE valid, and check the status of the first PTE
+    //
+    MiMakePdeExistAndMakeValid(PointerPde, Process, MM_NOIRQL);
+    if (PointerPte->u.Long)
+    {
+        //
+        // Not supported in ARM3
+        //
+        ASSERT(FoundVad->u.VadFlags.VadType != VadRotatePhysical);
+
+        //
+        // Capture the page protection and make the PDE valid
+        //
+        *CapturedOldProtect = MiGetPageProtection(PointerPte);
+        MiMakePdeExistAndMakeValid(PointerPde, Process, MM_NOIRQL);
+    }
+    else
+    {
+        //
+        // Only pagefile-backed section VADs are supported for now
+        //
+        ASSERT(FoundVad->u.VadFlags.VadType != VadImageMap);
+
+        //
+        // Grab the old protection from the VAD itself
+        //
+        *CapturedOldProtect = 
MmProtectToValue[FoundVad->u.VadFlags.Protection];
+    }
+
+    //
+    // Loop all the PTEs now
+    //
+    MiMakePdeExistAndMakeValid(PointerPde, Process, MM_NOIRQL);
+    while (PointerPte <= LastPte)
+    {
+        //
+        // Check if we've crossed a PDE boundary and make the new PDE valid too
+        //
+        if ((((ULONG_PTR)PointerPte) & (SYSTEM_PD_SIZE - 1)) == 0)
+        {
+            PointerPde = MiAddressToPte(PointerPte);
+            MiMakePdeExistAndMakeValid(PointerPde, Process, MM_NOIRQL);
+        }
+
+        //
+        // Capture the PTE and see what we're dealing with
+        //
+        PteContents = *PointerPte;
+        if (PteContents.u.Long == 0)
+        {
+            //
+            // This used to be a zero PTE and it no longer is, so we must add a
+            // reference to the pagetable.
+            //
+            UsedPageTableEntries = 
&MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(MiPteToAddress(PointerPte))];
+            (*UsedPageTableEntries)++;
+            ASSERT((*UsedPageTableEntries) <= PTE_COUNT);
+
+            //
+            // Create the demand-zero prototype PTE
+            //
+            TempPte = PrototypePte;
+            TempPte.u.Soft.Protection = ProtectionMask;
+            MI_WRITE_INVALID_PTE(PointerPte, TempPte);
+        }
+        else if (PteContents.u.Hard.Valid == 1)
+        {
+            //
+            // Get the PFN entry
+            //
+            Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(&PteContents));
+
+            //
+            // We don't support these yet
+            //
+            ASSERT((NewProtect & (PAGE_NOACCESS | PAGE_GUARD)) == 0);
+            ASSERT(Pfn1->u3.e1.PrototypePte == 0);
+
+            //
+            // Write the protection mask and write it with a TLB flush
+            //
+            Pfn1->OriginalPte.u.Soft.Protection = ProtectionMask;
+            MiFlushTbAndCapture(FoundVad,
+                                PointerPte,
+                                ProtectionMask,
+                                Pfn1,
+                                TRUE);
+        }
+        else
+        {
+            //
+            // We don't support these cases yet
+            //
+            ASSERT(PteContents.u.Soft.Prototype == 0);
+            ASSERT(PteContents.u.Soft.Transition == 0);
+
+            //
+            // The PTE is already demand-zero, just update the protection mask
+            //
+            PointerPte->u.Soft.Protection = ProtectionMask;
+        }
+
+        PointerPte++;
+    }
+
+    //
+    // Unlock the working set and update quota charges if needed, then return
+    //
+    //MiUnlockProcessWorkingSet(Thread, Process);
+    if ((QuotaCharge > 0) && (!DontCharge))
+    {
+        FoundVad->u.VadFlags.CommitCharge -= QuotaCharge;
+        Process->CommitCharge -= QuotaCharge;
+    }
+    return STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+MiRemoveMappedPtes(IN PVOID BaseAddress,
+                   IN ULONG NumberOfPtes,
+                   IN PCONTROL_AREA ControlArea,
+                   IN PMMSUPPORT Ws)
+{
+    PMMPTE PointerPte, FirstPte;
+    PMMPDE PointerPde, SystemMapPde;
+    PMMPFN Pfn1, Pfn2;
+    MMPTE PteContents;
+    KIRQL OldIrql;
+    DPRINT("Removing mapped view at: 0x%p\n", BaseAddress);
+
+    /* Get the PTE and loop each one */
+    PointerPte = MiAddressToPte(BaseAddress);
+    FirstPte = PointerPte;
+    while (NumberOfPtes)
+    {
+        /* Check if the PTE is already valid */
+        PteContents = *PointerPte;
+        if (PteContents.u.Hard.Valid == 1)
+        {
+            /* Get the PFN entry */
+            Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(&PteContents));
+
+            /* Get the PTE */
+            PointerPde = MiAddressToPte(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 */
+
+            /* Was the PDE invalid */
+            if (PointerPde->u.Long == 0)
+            {
+                /* Find the system double-mapped PDE that describes this 
mapping */
+                SystemMapPde = &MmSystemPagePtes[((ULONG_PTR)PointerPde & 
(SYSTEM_PD_SIZE - 1)) / sizeof(MMPTE)];
+
+                /* Make it valid */
+                ASSERT(SystemMapPde->u.Hard.Valid == 1);
+                MI_WRITE_VALID_PDE(PointerPde, *SystemMapPde);
+            }
+
+            /* Dereference the PDE and the PTE */
+            Pfn2 = MiGetPfnEntry(PFN_FROM_PTE(PointerPde));
+            //MiDecrementShareCount(Pfn2, PFN_FROM_PTE(PointerPde));
+            MiDecrementShareCount(Pfn1, PFN_FROM_PTE(&PteContents));
+
+            /* Release the PFN lock */
+            KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+        }
+        else
+        {
+            /* Windows ASSERT */
+            ASSERT((PteContents.u.Long == 0) || (PteContents.u.Soft.Prototype 
== 1));
+
+            /* But not handled in ARM3 */
+            ASSERT(PteContents.u.Soft.Prototype == 0);
+        }
+
+        /* Make the PTE into a zero PTE */
+        PointerPte->u.Long = 0;
+
+        /* Move to the next PTE */
+        PointerPte++;
+        NumberOfPtes--;
+    }
+
+    /* Flush the TLB */
+    KeFlushCurrentTb();
+
+    /* Acquire the PFN lock */
+    OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+    /* Decrement the accounting counters */
+    ControlArea->NumberOfUserReferences--;
+    ControlArea->NumberOfMappedViews--;
+
+    /* Check if we should destroy the CA and release the lock */
+    MiCheckControlArea(ControlArea, OldIrql);
+}
+
+ULONG
+NTAPI
+MiRemoveFromSystemSpace(IN PMMSESSION Session,
+                        IN PVOID Base,
+                        OUT PCONTROL_AREA *ControlArea)
+{
+    ULONG Hash, Size, Count = 0, Entry;
+    PAGED_CODE();
+
+    /* Compute the hash for this entry and loop trying to find it */
+    Entry = (ULONG_PTR)Base >> 16;
+    Hash = Entry % Session->SystemSpaceHashKey;
+    while ((Session->SystemSpaceViewTable[Hash].Entry >> 16) != Entry)
+    {
+        /* Check if we overflew past the end of the hash table */
+        if (++Hash >= Session->SystemSpaceHashSize)
+        {
+            /* Reset the hash to zero and keep searching from the bottom */
+            Hash = 0;
+            if (++Count == 2)
+            {
+                /* But if we overflew twice, then this is not a real mapping */
+                KeBugCheckEx(0xD7, //DRIVER_UNMAPPING_INVALID_VIEW,
+                             (ULONG_PTR)Base,
+                             1,
+                             0,
+                             0);
+            }
+        }
+    }
+
+    /* One less entry */
+    Session->SystemSpaceHashEntries--;
+
+    /* Extract the size and clear the entry */
+    Size = Session->SystemSpaceViewTable[Hash].Entry & 0xFFFF;
+    Session->SystemSpaceViewTable[Hash].Entry = 0;
+
+    /* Return the control area and the size */
+    *ControlArea = Session->SystemSpaceViewTable[Hash].ControlArea;
+    return Size;
+}
+
+NTSTATUS
+NTAPI
+MiUnmapViewInSystemSpace(IN PMMSESSION Session,
+                         IN PVOID MappedBase)
+{
+    ULONG Size;
+    PCONTROL_AREA ControlArea;
+    PAGED_CODE();
+
+    /* Only global mappings supported for now */
+    ASSERT(Session == &MmSession);
+
+    /* Remove this mapping */
+    KeAcquireGuardedMutex(Session->SystemSpaceViewLockPointer);
+    Size = MiRemoveFromSystemSpace(Session, MappedBase, &ControlArea);
+
+    /* Clear the bits for this mapping */
+    RtlClearBits(Session->SystemSpaceBitMap,
+                 ((ULONG_PTR)MappedBase - 
(ULONG_PTR)Session->SystemSpaceViewStart) >> 16,
+                 Size);
+
+    /* Convert the size from a bit size into the actual size */
+    Size = Size * (_64K >> PAGE_SHIFT);
+
+    /* Remove the PTEs now */
+    MiRemoveMappedPtes(MappedBase, Size, ControlArea, NULL);
+    KeReleaseGuardedMutex(Session->SystemSpaceViewLockPointer);
+
+    /* Return success */
+    return STATUS_SUCCESS;
 }
 
 /* PUBLIC FUNCTIONS 
***********************************************************/
@@ -1701,6 +2204,17 @@
  */
 NTSTATUS
 NTAPI
+MmUnmapViewOfSection(IN PEPROCESS Process,
+                     IN PVOID BaseAddress)
+{
+    return MiUnmapViewOfSection(Process, BaseAddress, 0);
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
 MmUnmapViewInSystemSpace(IN PVOID MappedBase)
 {
     PMEMORY_AREA MemoryArea;
@@ -1714,10 +2228,7 @@
     }
 
     /* It was not, call the ARM3 routine */
-    ASSERT(FALSE);
-    return STATUS_SUCCESS;
-//    DPRINT("ARM3 unmapping\n");
-//    return MiUnmapViewInSystemSpace(&MmSession, MappedBase);
+    return MiUnmapViewInSystemSpace(&MmSession, MappedBase);
 }
 
 /* SYSTEM CALLS 
***************************************************************/
@@ -2188,7 +2699,7 @@
     if (!NT_SUCCESS(Status)) return Status;
 
     /* Unmap the view */
-    Status = MmUnmapViewOfSection(Process, BaseAddress);
+    Status = MiUnmapViewOfSection(Process, BaseAddress, 0);
 
     /* Dereference the process and return status */
     ObDereferenceObject(Process);

Modified: trunk/reactos/ntoskrnl/mm/section.c
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/section.c?rev=56317&r1=56316&r2=56317&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/mm/section.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/section.c [iso-8859-1] Mon Apr  2 07:23:49 2012
@@ -4198,12 +4198,11 @@
    return(Status);
 }
 
-/*
- * @implemented
- */
-NTSTATUS NTAPI
-MmUnmapViewOfSection(PEPROCESS Process,
-                     PVOID BaseAddress)
+NTSTATUS
+NTAPI
+MiRosUnmapViewOfSection(IN PEPROCESS Process,
+                        IN PVOID BaseAddress,
+                        IN ULONG Flags)
 {
    NTSTATUS Status;
    PMEMORY_AREA MemoryArea;


Reply via email to