Author: tfaber
Date: Sun Jun 18 11:18:41 2017
New Revision: 75087
URL:
http://svn.reactos.org/svn/reactos?rev=75087&view=rev
Log:
[NTOS:MM]
- Implement MiMapLockedPagesInUserSpace and MiUnmapLockedPagesInUserSpace.
CORE-13444 #resolve
Modified:
trunk/reactos/ntoskrnl/mm/ARM3/mdlsup.c
trunk/reactos/ntoskrnl/mm/ARM3/miarm.h
Modified: trunk/reactos/ntoskrnl/mm/ARM3/mdlsup.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/mdlsup.c?…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/mdlsup.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/mdlsup.c [iso-8859-1] Sun Jun 18 11:18:41 2017
@@ -20,6 +20,327 @@
BOOLEAN MmTrackPtes;
BOOLEAN MmTrackLockedPages;
SIZE_T MmSystemLockPagesCount;
+
+/* INTERNAL FUNCTIONS *********************************************************/
+static
+PVOID
+NTAPI
+MiMapLockedPagesInUserSpace(
+ _In_ PMDL Mdl,
+ _In_ PVOID StartVa,
+ _In_ MEMORY_CACHING_TYPE CacheType,
+ _In_opt_ PVOID BaseAddress)
+{
+ NTSTATUS Status;
+ PEPROCESS Process = PsGetCurrentProcess();
+ PETHREAD Thread = PsGetCurrentThread();
+ TABLE_SEARCH_RESULT Result;
+ MI_PFN_CACHE_ATTRIBUTE CacheAttribute;
+ BOOLEAN IsIoMapping;
+ KIRQL OldIrql;
+ ULONG_PTR StartingVa;
+ ULONG_PTR EndingVa;
+ PMMADDRESS_NODE Parent;
+ PMMVAD_LONG Vad;
+ ULONG NumberOfPages;
+ PMMPTE PointerPte;
+ PMMPDE PointerPde;
+ MMPTE TempPte;
+ PPFN_NUMBER MdlPages;
+ PMMPFN Pfn1;
+ PMMPFN Pfn2;
+ BOOLEAN AddressSpaceLocked = FALSE;
+
+ PAGED_CODE();
+
+ DPRINT("MiMapLockedPagesInUserSpace(%p, %p, 0x%x, %p)\n",
+ Mdl, StartVa, CacheType, BaseAddress);
+
+ NumberOfPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(StartVa,
+ MmGetMdlByteCount(Mdl));
+ MdlPages = MmGetMdlPfnArray(Mdl);
+
+ ASSERT(CacheType <= MmWriteCombined);
+
+ IsIoMapping = (Mdl->MdlFlags & MDL_IO_SPACE) != 0;
+ CacheAttribute = MiPlatformCacheAttributes[IsIoMapping][CacheType];
+
+ /* Large pages are always cached, make sure we're not asking for those */
+ if (CacheAttribute != MiCached)
+ {
+ DPRINT1("FIXME: Need to check for large pages\n");
+ }
+
+ /* Allocate a VAD for our mapped region */
+ Vad = ExAllocatePoolWithTag(NonPagedPool, sizeof(MMVAD_LONG), 'ldaV');
+ if (Vad == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Error;
+ }
+
+ /* Initialize PhysicalMemory VAD */
+ RtlZeroMemory(Vad, sizeof(*Vad));
+ Vad->u2.VadFlags2.LongVad = 1;
+ Vad->u.VadFlags.VadType = VadDevicePhysicalMemory;
+ Vad->u.VadFlags.Protection = MM_READWRITE;
+ Vad->u.VadFlags.PrivateMemory = 1;
+
+ /* Did the caller specify an address? */
+ if (BaseAddress == NULL)
+ {
+ /* We get to pick the address */
+ MmLockAddressSpace(&Process->Vm);
+ AddressSpaceLocked = TRUE;
+ if (Process->VmDeleted)
+ {
+ Status = STATUS_PROCESS_IS_TERMINATING;
+ goto Error;
+ }
+
+ Result = MiFindEmptyAddressRangeInTree(NumberOfPages << PAGE_SHIFT,
+ MM_VIRTMEM_GRANULARITY,
+ &Process->VadRoot,
+ &Parent,
+ &StartingVa);
+ if (Result == TableFoundNode)
+ {
+ Status = STATUS_NO_MEMORY;
+ goto Error;
+ }
+ EndingVa = StartingVa + NumberOfPages * PAGE_SIZE - 1;
+ BaseAddress = (PVOID)StartingVa;
+ }
+ else
+ {
+ /* Caller specified a base address */
+ StartingVa = (ULONG_PTR)BaseAddress;
+ EndingVa = StartingVa + NumberOfPages * PAGE_SIZE - 1;
+
+ /* Make sure it's valid */
+ if (BYTE_OFFSET(StartingVa) != 0 ||
+ EndingVa <= StartingVa ||
+ EndingVa > (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS)
+ {
+ Status = STATUS_INVALID_ADDRESS;
+ goto Error;
+ }
+
+ MmLockAddressSpace(&Process->Vm);
+ AddressSpaceLocked = TRUE;
+ if (Process->VmDeleted)
+ {
+ Status = STATUS_PROCESS_IS_TERMINATING;
+ goto Error;
+ }
+
+ /* Check if it's already in use */
+ Result = MiCheckForConflictingNode(StartingVa >> PAGE_SHIFT,
+ EndingVa >> PAGE_SHIFT,
+ &Process->VadRoot,
+ &Parent);
+ if (Result == TableFoundNode)
+ {
+ Status = STATUS_CONFLICTING_ADDRESSES;
+ goto Error;
+ }
+ }
+
+ Vad->StartingVpn = StartingVa >> PAGE_SHIFT;
+ Vad->EndingVpn = EndingVa >> PAGE_SHIFT;
+
+ MiLockProcessWorkingSetUnsafe(Process, Thread);
+
+ ASSERT(Vad->EndingVpn >= Vad->StartingVpn);
+
+ MiInsertVad((PMMVAD)Vad, &Process->VadRoot);
+
+ /* Check if this is uncached */
+ if (CacheAttribute != MiCached)
+ {
+ /* Flush all caches */
+ KeFlushEntireTb(TRUE, TRUE);
+ KeInvalidateAllCaches();
+ }
+
+ PointerPte = MiAddressToPte(BaseAddress);
+ while (NumberOfPages != 0 &&
+ *MdlPages != LIST_HEAD)
+ {
+ PointerPde = MiPteToPde(PointerPte);
+ MiMakePdeExistAndMakeValid(PointerPde, Process, MM_NOIRQL);
+ ASSERT(PointerPte->u.Hard.Valid == 0);
+
+ /* Add a PDE reference for each page */
+ MiIncrementPageTableReferences(BaseAddress);
+
+ /* Set up our basic user PTE */
+ MI_MAKE_HARDWARE_PTE_USER(&TempPte,
+ PointerPte,
+ MM_READWRITE,
+ *MdlPages);
+
+ /* FIXME: We need to respect the PFN's caching information in some cases */
+ Pfn2 = MiGetPfnEntry(*MdlPages);
+ if (Pfn2 != NULL)
+ {
+ ASSERT(Pfn2->u3.e2.ReferenceCount != 0);
+
+ if (Pfn2->u3.e1.CacheAttribute != CacheAttribute)
+ {
+ DPRINT1("FIXME: Using caller's cache attribute instead of PFN
override\n");
+ }
+
+ /* We don't support AWE magic */
+ ASSERT(Pfn2->u3.e1.CacheAttribute != MiNotMapped);
+ }
+
+ /* Configure caching */
+ switch (CacheAttribute)
+ {
+ case MiNonCached:
+ MI_PAGE_DISABLE_CACHE(&TempPte);
+ MI_PAGE_WRITE_THROUGH(&TempPte);
+ break;
+ case MiCached:
+ break;
+ case MiWriteCombined:
+ MI_PAGE_DISABLE_CACHE(&TempPte);
+ MI_PAGE_WRITE_COMBINED(&TempPte);
+ break;
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+
+ /* Make the page valid */
+ MI_WRITE_VALID_PTE(PointerPte, TempPte);
+
+ /* Acquire a share count */
+ Pfn1 = MI_PFN_ELEMENT(PointerPde->u.Hard.PageFrameNumber);
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+ Pfn1->u2.ShareCount++;
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+
+ /* Next page */
+ MdlPages++;
+ PointerPte++;
+ NumberOfPages--;
+ BaseAddress = (PVOID)((ULONG_PTR)BaseAddress + PAGE_SIZE);
+ }
+
+ MiUnlockProcessWorkingSetUnsafe(Process, Thread);
+ ASSERT(AddressSpaceLocked);
+ MmUnlockAddressSpace(&Process->Vm);
+
+ ASSERT(StartingVa != 0);
+ return (PVOID)((ULONG_PTR)StartingVa + MmGetMdlByteOffset(Mdl));
+
+Error:
+ if (AddressSpaceLocked)
+ {
+ MmUnlockAddressSpace(&Process->Vm);
+ }
+ if (Vad != NULL)
+ {
+ ExFreePoolWithTag(Vad, 'ldaV');
+ }
+ ExRaiseStatus(Status);
+}
+
+static
+VOID
+NTAPI
+MiUnmapLockedPagesInUserSpace(
+ _In_ PVOID BaseAddress,
+ _In_ PMDL Mdl)
+{
+ PEPROCESS Process = PsGetCurrentProcess();
+ PETHREAD Thread = PsGetCurrentThread();
+ PMMVAD Vad;
+ PMMPTE PointerPte;
+ PMMPDE PointerPde;
+ KIRQL OldIrql;
+ ULONG NumberOfPages;
+ PPFN_NUMBER MdlPages;
+ PFN_NUMBER PageTablePage;
+
+ DPRINT("MiUnmapLockedPagesInUserSpace(%p, %p)\n", BaseAddress, Mdl);
+
+ NumberOfPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Mdl),
+ MmGetMdlByteCount(Mdl));
+ ASSERT(NumberOfPages != 0);
+ MdlPages = MmGetMdlPfnArray(Mdl);
+
+ /* Find the VAD */
+ MmLockAddressSpace(&Process->Vm);
+ Vad = MiLocateAddress(BaseAddress);
+ if (!Vad ||
+ Vad->u.VadFlags.VadType != VadDevicePhysicalMemory)
+ {
+ DPRINT1("MiUnmapLockedPagesInUserSpace invalid for %p\n",
BaseAddress);
+ MmUnlockAddressSpace(&Process->Vm);
+ return;
+ }
+
+ MiLockProcessWorkingSetUnsafe(Process, Thread);
+
+ /* Remove it from the process VAD tree */
+ ASSERT(Process->VadRoot.NumberGenericTableElements >= 1);
+ MiRemoveNode((PMMADDRESS_NODE)Vad, &Process->VadRoot);
+
+ /* MiRemoveNode should have removed us if we were the hint */
+ ASSERT(Process->VadRoot.NodeHint != Vad);
+
+ PointerPte = MiAddressToPte(BaseAddress);
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+ while (NumberOfPages != 0 &&
+ *MdlPages != LIST_HEAD)
+ {
+ ASSERT(MiAddressToPte(PointerPte)->u.Hard.Valid == 1);
+ ASSERT(PointerPte->u.Hard.Valid == 1);
+
+ /* Dereference the page */
+ MiDecrementPageTableReferences(BaseAddress);
+
+ /* Invalidate it */
+ MI_ERASE_PTE(PointerPte);
+
+ /* We invalidated this PTE, so dereference the PDE */
+ PointerPde = MiAddressToPde(BaseAddress);
+ PageTablePage = PointerPde->u.Hard.PageFrameNumber;
+ MiDecrementShareCount(MiGetPfnEntry(PageTablePage), PageTablePage);
+
+ /* Next page */
+ PointerPte++;
+ NumberOfPages--;
+ BaseAddress = (PVOID)((ULONG_PTR)BaseAddress + PAGE_SIZE);
+ MdlPages++;
+
+ /* Moving to a new PDE? */
+ if (PointerPde != MiAddressToPde(BaseAddress))
+ {
+ /* See if we should delete it */
+ KeFlushProcessTb();
+ PointerPde = MiPteToPde(PointerPte - 1);
+ ASSERT(PointerPde->u.Hard.Valid == 1);
+ if (MiQueryPageTableReferences(BaseAddress) == 0)
+ {
+ ASSERT(PointerPde->u.Long != 0);
+ MiDeletePte(PointerPde,
+ MiPteToAddress(PointerPde),
+ Process,
+ NULL);
+ }
+ }
+ }
+
+ KeFlushProcessTb();
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+ MiUnlockProcessWorkingSetUnsafe(Process, Thread);
+ MmUnlockAddressSpace(&Process->Vm);
+ ExFreePoolWithTag(Vad, 'ldaV');
+}
/* PUBLIC FUNCTIONS ***********************************************************/
@@ -460,8 +781,7 @@
return Base;
}
- UNIMPLEMENTED;
- return NULL;
+ return MiMapLockedPagesInUserSpace(Mdl, Base, CacheType, BaseAddress);
}
/*
@@ -573,7 +893,7 @@
}
else
{
- UNIMPLEMENTED;
+ MiUnmapLockedPagesInUserSpace(BaseAddress, Mdl);
}
}
Modified: trunk/reactos/ntoskrnl/mm/ARM3/miarm.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/miarm.h?r…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/miarm.h [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/miarm.h [iso-8859-1] Sun Jun 18 11:18:41 2017
@@ -1876,22 +1876,6 @@
IN ULONG Flags
);
-PVOID
-NTAPI
-MiMapLockedPagesInUserSpace(
- IN PMDL Mdl,
- IN PVOID BaseVa,
- IN MEMORY_CACHING_TYPE CacheType,
- IN PVOID BaseAddress
-);
-
-VOID
-NTAPI
-MiUnmapLockedPagesInUserSpace(
- IN PVOID BaseAddress,
- IN PMDL Mdl
-);
-
VOID
NTAPI
MiInsertPageInList(
@@ -2075,6 +2059,12 @@
IN ULONG ProtectionMask
);
+VOID
+NTAPI
+MiInsertVad(
+ _Inout_ PMMVAD Vad,
+ _Inout_ PMM_AVL_TABLE VadRoot);
+
NTSTATUS
NTAPI
MiInsertVadEx(