[ros-kernel] MmMapLockedPages patch; seems to work
Gregor Anich
blight at blight.eu.org
Tue Mar 9 16:01:22 CET 2004
Hi!
I have made a patch to the memory manager to support kernel to user
space memory mapping.
MmMapLockedPages/MmUnmapLockedPages seem to work correctly, what's
missing is releasing a MDL memory area on process cleanup (in
ntoskrnl/mm/mm.c, MmReleaseMemoryArea)
I am not sure how to get/create a MDL to pass to MmUnmapLockedPages
there. Is it better to store it with the memory area (in the Data union)
when creating the mapping or just create a MDL describing the memory
area, pass it to MmUnmapLockedPages and release it?
I have tested the code with Filip's mmtest which he sent to the list a
few days ago and it prints out "Hello World!"
--blight
-------------- next part --------------
Index: ntoskrnl/mm/mdl.c
===================================================================
RCS file: /CVS/ReactOS/reactos/ntoskrnl/mm/mdl.c,v
retrieving revision 1.59
diff -u -r1.59 mdl.c
--- ntoskrnl/mm/mdl.c 6 Mar 2004 22:21:20 -0000 1.59
+++ ntoskrnl/mm/mdl.c 9 Mar 2004 15:36:37 -0000
@@ -5,7 +5,7 @@
* FILE: ntoskrnl/mm/mdl.c
* PURPOSE: Manipulates MDLs
* PROGRAMMER: David Welch (welch at cwcom.net)
- * UPDATE HISTORY:
+ * UPDATE HISTORY:
* 27/05/98: Created
*/
@@ -71,20 +71,20 @@
KeInitializeSpinLock(&MiMdlMappingRegionLock);
}
-PVOID
+PVOID
MmGetMdlPageAddress(PMDL Mdl, PVOID Offset)
{
PULONG MdlPages;
-
+
MdlPages = (PULONG)(Mdl + 1);
-
+
return((PVOID)MdlPages[((ULONG)Offset) / PAGE_SIZE]);
}
/*
* @unimplemented
*/
-VOID STDCALL
+VOID STDCALL
MmUnlockPages(PMDL Mdl)
/*
* FUNCTION: Unlocks the physical pages described by a given MDL
@@ -97,24 +97,24 @@
{
ULONG i;
PULONG MdlPages;
-
- /*
- * FIXME: I don't know whether this right, but it looks sensible
+
+ /*
+ * FIXME: I don't know whether this right, but it looks sensible
*/
if ((Mdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL) ||
(Mdl->MdlFlags & MDL_IO_PAGE_READ))
{
return;
}
-
+
/*
- * FIXME: Seems sensible
+ * FIXME: Seems sensible
*/
if (!(Mdl->MdlFlags & MDL_PAGES_LOCKED))
{
return;
}
-
+
MdlPages = (PULONG)(Mdl + 1);
for (i=0; i<(PAGE_ROUND_UP(Mdl->ByteCount+Mdl->ByteOffset)/PAGE_SIZE); i++)
{
@@ -127,7 +127,7 @@
MmUnlockPage(dummyJunkNeeded);
MmDereferencePage(dummyJunkNeeded);
#endif
- }
+ }
Mdl->MdlFlags = Mdl->MdlFlags & (~MDL_PAGES_LOCKED);
}
@@ -152,42 +152,78 @@
KIRQL oldIrql;
ULONG RegionSize;
ULONG StartingOffset;
-
+ PEPROCESS CurrentProcess, OldProcess;
+
DPRINT("MmMapLockedPages(Mdl %x, AccessMode %x)\n", Mdl, AccessMode);
- if (Mdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL)
+ if ((Mdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL) && AccessMode != UserMode)
{
return(Mdl->MappedSystemVa);
}
+ /* Calculate the number of pages required. */
+ RegionSize = PAGE_ROUND_UP(Mdl->ByteCount + Mdl->ByteOffset) / PAGE_SIZE;
+
if (AccessMode == UserMode)
{
- DPRINT1("MDL mapping to user-mode not yet handled.\n");
- KEBUGCHECK(0);
+ MEMORY_AREA *Result;
+ LARGE_INTEGER BoundaryAddressMultiple;
+ NTSTATUS Status;
+
+ BoundaryAddressMultiple.QuadPart = 0;
+ Base = NULL;
+
+ CurrentProcess = OldProcess = PsGetCurrentProcess();
+ if (Mdl->Process != CurrentProcess)
+ {
+ KeAttachProcess(Mdl->Process);
+ CurrentProcess = Mdl->Process;
+ }
+
+ MmLockAddressSpace(&CurrentProcess->AddressSpace);
+ Status = MmCreateMemoryArea(CurrentProcess,
+ &CurrentProcess->AddressSpace,
+ MEMORY_AREA_MDL_MAPPING,
+ &Base,
+ RegionSize * PAGE_SIZE,
+ 0, /* PAGE_READWRITE? */
+ &Result,
+ FALSE,
+ FALSE,
+ BoundaryAddressMultiple);
+ MmUnlockAddressSpace(&CurrentProcess->AddressSpace);
+ if (!NT_SUCCESS(Status))
+ {
+ KEBUGCHECK(0);
+ /* FIXME: handle this? */
+ }
}
+ else
+ {
+ CurrentProcess = OldProcess = NULL;
- /* Calculate the number of pages required. */
- RegionSize = PAGE_ROUND_UP(Mdl->ByteCount + Mdl->ByteOffset) / PAGE_SIZE;
+ /* Allocate that number of pages from the mdl mapping region. */
+ KeAcquireSpinLock(&MiMdlMappingRegionLock, &oldIrql);
- /* Allocate that number of pages from the mdl mapping region. */
- KeAcquireSpinLock(&MiMdlMappingRegionLock, &oldIrql);
+ StartingOffset = RtlFindClearBitsAndSet(&MiMdlMappingRegionAllocMap, RegionSize, MiMdlMappingRegionHint);
- StartingOffset = RtlFindClearBitsAndSet(&MiMdlMappingRegionAllocMap, RegionSize, MiMdlMappingRegionHint);
-
- if (StartingOffset == 0xffffffff)
- {
- DPRINT1("Out of MDL mapping space\n");
- KEBUGCHECK(0);
- }
+ if (StartingOffset == 0xffffffff)
+ {
+ DPRINT1("Out of MDL mapping space\n");
+ KEBUGCHECK(0);
+ }
+
+ Base = (char*)MiMdlMappingRegionBase + StartingOffset * PAGE_SIZE;
- Base = (char*)MiMdlMappingRegionBase + StartingOffset * PAGE_SIZE;
+ if (MiMdlMappingRegionHint == StartingOffset)
+ {
+ MiMdlMappingRegionHint +=RegionSize;
+ }
+
+ KeReleaseSpinLock(&MiMdlMappingRegionLock, oldIrql);
+ }
- if (MiMdlMappingRegionHint == StartingOffset)
- {
- MiMdlMappingRegionHint +=RegionSize;
- }
- KeReleaseSpinLock(&MiMdlMappingRegionLock, oldIrql);
/* Set the virtual mappings for the MDL pages. */
MdlPages = (PULONG)(Mdl + 1);
@@ -198,7 +234,7 @@
PHYSICAL_ADDRESS dummyJunkNeeded;
dummyJunkNeeded.QuadPart = MdlPages[i];
#endif
- Status = MmCreateVirtualMapping(NULL,
+ Status = MmCreateVirtualMapping(CurrentProcess,
(PVOID)((ULONG)Base+(i*PAGE_SIZE)),
PAGE_READWRITE,
#if defined(__GNUC__)
@@ -214,6 +250,11 @@
}
}
+ if (AccessMode == UserMode && CurrentProcess != OldProcess)
+ {
+ KeDetachProcess();
+ }
+
/* Mark the MDL has having being mapped. */
Mdl->MdlFlags = Mdl->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA;
Mdl->MappedSystemVa = (char*)Base + Mdl->ByteOffset;
@@ -223,7 +264,7 @@
/*
* @implemented
*/
-VOID STDCALL
+VOID STDCALL
MmUnmapLockedPages(PVOID BaseAddress, PMDL Mdl)
/*
* FUNCTION: Releases a mapping set up by a preceding call to MmMapLockedPages
@@ -236,6 +277,7 @@
ULONG i;
ULONG RegionSize;
ULONG Base;
+ PEPROCESS CurrentProcess, OldProcess;
DPRINT("MmUnmapLockedPages(BaseAddress %x, Mdl %x)\n", BaseAddress, Mdl);
@@ -243,11 +285,27 @@
* In this case, the MDL has the same system address as the base address
* so there is no need to free it
*/
- if (Mdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL)
+ if ((Mdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL) &&
+ //(Mdl->MappedSystemVa >= KERNEL_BASE))
+ ((DWORD)BaseAddress >= KERNEL_BASE))
{
return;
}
+ if ((DWORD)BaseAddress >= KERNEL_BASE)
+ {
+ CurrentProcess = OldProcess = NULL;
+ }
+ else
+ {
+ CurrentProcess = OldProcess = PsGetCurrentProcess();
+ if (Mdl->Process != CurrentProcess)
+ {
+ KeAttachProcess(Mdl->Process);
+ CurrentProcess = Mdl->Process;
+ }
+ }
+
/* Calculate the number of pages we mapped. */
RegionSize = PAGE_ROUND_UP(Mdl->ByteCount + Mdl->ByteOffset) / PAGE_SIZE;
#if defined(__GNUC__)
@@ -263,40 +321,61 @@
/* Unmap all the pages. */
for (i = 0; i < RegionSize; i++)
{
- MmDeleteVirtualMapping(NULL,
+ MmDeleteVirtualMapping(NULL,
(char*)BaseAddress + (i * PAGE_SIZE),
FALSE,
NULL,
NULL);
}
- KeAcquireSpinLock(&MiMdlMappingRegionLock, &oldIrql);
- /* Deallocate all the pages used. */
- Base = (ULONG)((char*)BaseAddress - (char*)MiMdlMappingRegionBase) / PAGE_SIZE;
-
- RtlClearBits(&MiMdlMappingRegionAllocMap, Base, RegionSize);
+ if ((DWORD)BaseAddress >= KERNEL_BASE)
+ {
+ KeAcquireSpinLock(&MiMdlMappingRegionLock, &oldIrql);
+ /* Deallocate all the pages used. */
+ Base = (ULONG)((char*)BaseAddress - (char*)MiMdlMappingRegionBase) / PAGE_SIZE;
+
+ RtlClearBits(&MiMdlMappingRegionAllocMap, Base, RegionSize);
- MiMdlMappingRegionHint = min (MiMdlMappingRegionHint, Base);
+ MiMdlMappingRegionHint = min (MiMdlMappingRegionHint, Base);
+
+ KeReleaseSpinLock(&MiMdlMappingRegionLock, oldIrql);
+ }
+ else
+ {
+ MEMORY_AREA *Marea;
+
+ Marea = MmOpenMemoryAreaByAddress( &CurrentProcess->AddressSpace, BaseAddress );
+ if (Marea == NULL)
+ {
+ DPRINT1( "Couldn't open memory area when unmapping user-space pages!\n" );
+ KEBUGCHECK(0);
+ }
+
+ MmFreeMemoryArea( &CurrentProcess->AddressSpace, Marea->BaseAddress, 0, NULL, NULL );
+
+ if (CurrentProcess != OldProcess)
+ {
+ KeDetachProcess();
+ }
+ }
- KeReleaseSpinLock(&MiMdlMappingRegionLock, oldIrql);
-
/* Reset the MDL state. */
Mdl->MdlFlags = Mdl->MdlFlags & ~MDL_MAPPED_TO_SYSTEM_VA;
Mdl->MappedSystemVa = NULL;
}
-VOID
+VOID
MmBuildMdlFromPages(PMDL Mdl, PULONG Pages)
{
ULONG i;
PULONG MdlPages;
-
- Mdl->MdlFlags = Mdl->MdlFlags |
+
+ Mdl->MdlFlags = Mdl->MdlFlags |
(MDL_PAGES_LOCKED | MDL_IO_PAGE_READ);
-
+
MdlPages = (PULONG)(Mdl + 1);
-
+
for (i=0;i<(PAGE_ROUND_UP(Mdl->ByteOffset+Mdl->ByteCount)/PAGE_SIZE);i++)
{
MdlPages[i] = Pages[i];
@@ -325,7 +404,7 @@
PEPROCESS CurrentProcess = NULL;
DPRINT("MmProbeAndLockPages(Mdl %x)\n", Mdl);
-
+
/*
* FIXME: Check behaviour against NT
*/
@@ -333,7 +412,7 @@
{
return;
}
-
+
if (Mdl->StartVa >= (PVOID)KERNEL_BASE)
@@ -355,14 +434,14 @@
*/
MmLockAddressSpace(&Mdl->Process->AddressSpace);
- MdlPages = (ULONG *)(Mdl + 1);
+ MdlPages = (ULONG *)(Mdl + 1);
NrPages = PAGE_ROUND_UP(Mdl->ByteOffset + Mdl->ByteCount) / PAGE_SIZE;
for (i = 0; i < NrPages; i++)
{
PVOID Address;
-
+
Address = (char*)Mdl->StartVa + (i*PAGE_SIZE);
-
+
if (!MmIsPagePresent(NULL, Address))
{
Status = MmNotPresentFault(Mode, (ULONG)Address, TRUE);
@@ -443,9 +522,9 @@
*/
{
ULONG len;
-
+
len = ADDRESS_AND_SIZE_TO_SPAN_PAGES(Base,Length);
-
+
return(sizeof(MDL)+(len*sizeof(ULONG)));
}
@@ -453,18 +532,18 @@
/*
* @implemented
*/
-VOID STDCALL
+VOID STDCALL
MmBuildMdlForNonPagedPool (PMDL Mdl)
/*
- * FUNCTION: Fills in the corresponding physical page array of a given
+ * FUNCTION: Fills in the corresponding physical page array of a given
* MDL for a buffer in nonpaged system space
* ARGUMENTS:
- * Mdl = Points to an MDL that supplies a virtual address,
+ * Mdl = Points to an MDL that supplies a virtual address,
* byte offset and length
*/
{
ULONG va;
- Mdl->MdlFlags = Mdl->MdlFlags |
+ Mdl->MdlFlags = Mdl->MdlFlags |
(MDL_SOURCE_IS_NONPAGED_POOL | MDL_PAGES_LOCKED);
for (va=0; va < ((Mdl->Size - sizeof(MDL)) / sizeof(ULONG)); va++)
{
@@ -478,7 +557,7 @@
/*
* @implemented
*/
-PMDL STDCALL
+PMDL STDCALL
MmCreateMdl (PMDL MemoryDescriptorList,
PVOID Base,
ULONG Length)
@@ -495,9 +574,9 @@
if (MemoryDescriptorList == NULL)
{
ULONG Size;
-
+
Size = MmSizeOfMdl(Base,Length);
- MemoryDescriptorList =
+ MemoryDescriptorList =
(PMDL)ExAllocatePoolWithTag(NonPagedPool, Size, TAG_MDL);
if (MemoryDescriptorList == NULL)
{
@@ -513,7 +592,7 @@
/*
* @unimplemented
*/
-VOID STDCALL
+VOID STDCALL
MmMapMemoryDumpMdl (PVOID Unknown0)
/*
* FIXME: Has something to do with crash dumps. Do we want to implement
Index: ntoskrnl/mm/mm.c
===================================================================
RCS file: /CVS/ReactOS/reactos/ntoskrnl/mm/mm.c,v
retrieving revision 1.68
diff -u -r1.68 mm.c
--- ntoskrnl/mm/mm.c 15 Feb 2004 19:03:29 -0000 1.68
+++ ntoskrnl/mm/mm.c 9 Mar 2004 15:36:38 -0000
@@ -19,7 +19,7 @@
/* $Id: mm.c,v 1.68 2004/02/15 19:03:29 hbirr Exp $
*
* COPYRIGHT: See COPYING in the top directory
- * PROJECT: ReactOS kernel
+ * PROJECT: ReactOS kernel
* FILE: ntoskrnl/mm/mm.c
* PURPOSE: kernel memory managment functions
* PROGRAMMER: David Welch (welch at cwcom.net)
@@ -52,13 +52,13 @@
NTSTATUS MmReleaseMemoryArea(PEPROCESS Process, PMEMORY_AREA Marea)
{
NTSTATUS Status;
-
+
DPRINT("MmReleaseMemoryArea(Process %x, Marea %x)\n",Process,Marea);
-
+
DPRINT("Releasing %x between %x %x (type %d)\n",
Marea, Marea->BaseAddress, (char*)Marea->BaseAddress + Marea->Length,
Marea->Type);
-
+
switch (Marea->Type)
{
case MEMORY_AREA_SECTION_VIEW:
@@ -68,7 +68,7 @@
case MEMORY_AREA_VIRTUAL_MEMORY:
MmFreeVirtualMemory(Process, Marea);
- break;
+ break;
case MEMORY_AREA_SHARED_DATA:
case MEMORY_AREA_NO_ACCESS:
@@ -78,10 +78,15 @@
NULL,
NULL);
break;
+ case MEMORY_AREA_MDL_MAPPING:
+ /* TODO: Unmap pages, free area */
+ DPRINT1( "WARNING: MEMORY_AREA_MDL_MAPPING unhandled!\n" );
+ break;
+
default:
KEBUGCHECK(0);
}
-
+
return(STATUS_SUCCESS);
}
@@ -89,10 +94,10 @@
{
PLIST_ENTRY CurrentEntry;
PMEMORY_AREA Current;
-
+
DPRINT("MmReleaseMmInfo(Process %x (%s))\n", Process,
Process->ImageFileName);
-
+
MmLockAddressSpace(&Process->AddressSpace);
while(!IsListEmpty(&Process->AddressSpace.MAreaListHead))
@@ -101,12 +106,12 @@
Current = CONTAINING_RECORD(CurrentEntry, MEMORY_AREA, Entry);
MmReleaseMemoryArea(Process, Current);
}
-
+
Mmi386ReleaseMmInfo(Process);
-
+
MmUnlockAddressSpace(&Process->AddressSpace);
MmDestroyAddressSpace(&Process->AddressSpace);
-
+
DPRINT("Finished MmReleaseMmInfo()\n");
return(STATUS_SUCCESS);
}
@@ -137,9 +142,9 @@
{
MEMORY_AREA* MemoryArea;
PMADDRESS_SPACE AddressSpace;
-
+
AddressSpace = &PsGetCurrentProcess()->AddressSpace;
-
+
MmLockAddressSpace(AddressSpace);
MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
VirtualAddress);
@@ -161,9 +166,9 @@
MEMORY_AREA* MemoryArea;
NTSTATUS Status;
BOOLEAN Locked = FromMdl;
-
+
DPRINT("MmAccessFault(Mode %d, Address %x)\n", Mode, Address);
-
+
if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
{
DbgPrint("Page fault at high IRQL was %d\n", KeGetCurrentIrql());
@@ -174,7 +179,7 @@
DbgPrint("No current process\n");
return(STATUS_UNSUCCESSFUL);
}
-
+
/*
* Find the memory area for the faulting address
*/
@@ -194,7 +199,7 @@
{
AddressSpace = &PsGetCurrentProcess()->AddressSpace;
}
-
+
if (!FromMdl)
{
MmLockAddressSpace(AddressSpace);
@@ -210,7 +215,7 @@
}
return (STATUS_UNSUCCESSFUL);
}
-
+
switch (MemoryArea->Type)
{
case MEMORY_AREA_SYSTEM:
@@ -223,7 +228,7 @@
case MEMORY_AREA_SECTION_VIEW:
Status = MmAccessFaultSectionView(AddressSpace,
- MemoryArea,
+ MemoryArea,
(PVOID)Address,
Locked);
break;
@@ -239,7 +244,7 @@
default:
Status = STATUS_UNSUCCESSFUL;
break;
- }
+ }
}
while (Status == STATUS_MM_RESTART_OPERATION);
@@ -262,7 +267,7 @@
Status = MmRequestPageMemoryConsumer(MC_PPOOL, TRUE, &AllocatedPage);
MmLockAddressSpace(MmGetKernelAddressSpace());
}
- Status =
+ Status =
MmCreateVirtualMapping(NULL,
(PVOID)PAGE_ROUND_DOWN(Address),
PAGE_READWRITE,
@@ -271,7 +276,7 @@
if (!NT_SUCCESS(Status))
{
MmUnlockAddressSpace(MmGetKernelAddressSpace());
- Status =
+ Status =
MmCreateVirtualMapping(NULL,
(PVOID)PAGE_ROUND_DOWN(Address),
PAGE_READWRITE,
@@ -287,16 +292,16 @@
}
NTSTATUS MmNotPresentFault(KPROCESSOR_MODE Mode,
- ULONG Address,
+ ULONG Address,
BOOLEAN FromMdl)
{
PMADDRESS_SPACE AddressSpace;
MEMORY_AREA* MemoryArea;
NTSTATUS Status;
BOOLEAN Locked = FromMdl;
-
+
DPRINT("MmNotPresentFault(Mode %d, Address %x)\n", Mode, Address);
-
+
if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
{
DbgPrint("Page fault at high IRQL was %d\n", KeGetCurrentIrql());
@@ -307,7 +312,7 @@
DbgPrint("No current process\n");
return(STATUS_UNSUCCESSFUL);
}
-
+
/*
* Find the memory area for the faulting address
*/
@@ -327,7 +332,7 @@
{
AddressSpace = &PsGetCurrentProcess()->AddressSpace;
}
-
+
if (!FromMdl)
{
MmLockAddressSpace(AddressSpace);
@@ -359,23 +364,23 @@
case MEMORY_AREA_SYSTEM:
Status = STATUS_UNSUCCESSFUL;
break;
-
+
case MEMORY_AREA_SECTION_VIEW:
Status = MmNotPresentFaultSectionView(AddressSpace,
- MemoryArea,
+ MemoryArea,
(PVOID)Address,
Locked);
break;
-
+
case MEMORY_AREA_VIRTUAL_MEMORY:
Status = MmNotPresentFaultVirtualMemory(AddressSpace,
MemoryArea,
(PVOID)Address,
Locked);
break;
-
+
case MEMORY_AREA_SHARED_DATA:
- Status =
+ Status =
MmCreateVirtualMapping(PsGetCurrentProcess(),
(PVOID)PAGE_ROUND_DOWN(Address),
PAGE_READONLY,
@@ -384,7 +389,7 @@
if (!NT_SUCCESS(Status))
{
MmUnlockAddressSpace(&PsGetCurrentProcess()->AddressSpace);
- Status =
+ Status =
MmCreateVirtualMapping(PsGetCurrentProcess(),
(PVOID)PAGE_ROUND_DOWN(Address),
PAGE_READONLY,
@@ -393,7 +398,7 @@
MmLockAddressSpace(&PsGetCurrentProcess()->AddressSpace);
}
break;
-
+
default:
Status = STATUS_UNSUCCESSFUL;
break;
More information about the Ros-kernel
mailing list