mirror of
https://github.com/reactos/reactos.git
synced 2025-08-04 02:36:13 +00:00
[NTOS:MM]
- Implement MiMapLockedPagesInUserSpace and MiUnmapLockedPagesInUserSpace. CORE-13444 #resolve svn path=/trunk/; revision=75087
This commit is contained in:
parent
acaa894b33
commit
764f83d90d
2 changed files with 329 additions and 19 deletions
|
@ -21,6 +21,327 @@ BOOLEAN MmTrackPtes;
|
||||||
BOOLEAN MmTrackLockedPages;
|
BOOLEAN MmTrackLockedPages;
|
||||||
SIZE_T MmSystemLockPagesCount;
|
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 ***********************************************************/
|
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -460,8 +781,7 @@ MmMapLockedPagesSpecifyCache(IN PMDL Mdl,
|
||||||
return Base;
|
return Base;
|
||||||
}
|
}
|
||||||
|
|
||||||
UNIMPLEMENTED;
|
return MiMapLockedPagesInUserSpace(Mdl, Base, CacheType, BaseAddress);
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -573,7 +893,7 @@ MmUnmapLockedPages(IN PVOID BaseAddress,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED;
|
MiUnmapLockedPagesInUserSpace(BaseAddress, Mdl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1876,22 +1876,6 @@ MiAllocatePagesForMdl(
|
||||||
IN ULONG Flags
|
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
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
MiInsertPageInList(
|
MiInsertPageInList(
|
||||||
|
@ -2075,6 +2059,12 @@ MiCheckSecuredVad(
|
||||||
IN ULONG ProtectionMask
|
IN ULONG ProtectionMask
|
||||||
);
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
MiInsertVad(
|
||||||
|
_Inout_ PMMVAD Vad,
|
||||||
|
_Inout_ PMM_AVL_TABLE VadRoot);
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
NTAPI
|
NTAPI
|
||||||
MiInsertVadEx(
|
MiInsertVadEx(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue