mirror of
https://github.com/reactos/reactos.git
synced 2025-07-04 19:21:23 +00:00
make mdl impl. more windows compliant
svn path=/trunk/; revision=9188
This commit is contained in:
parent
87b81bac7c
commit
d169532a77
2 changed files with 234 additions and 113 deletions
|
@ -52,7 +52,7 @@ PHYSICAL_PAGE, *PPHYSICAL_PAGE;
|
||||||
/* GLOBALS ****************************************************************/
|
/* GLOBALS ****************************************************************/
|
||||||
|
|
||||||
static PPHYSICAL_PAGE MmPageArray;
|
static PPHYSICAL_PAGE MmPageArray;
|
||||||
static ULONG MmPageArraySize;
|
ULONG MmPageArraySize;
|
||||||
|
|
||||||
static KSPIN_LOCK PageListLock;
|
static KSPIN_LOCK PageListLock;
|
||||||
static LIST_ENTRY UsedPageListHeads[MC_MAXIMUM];
|
static LIST_ENTRY UsedPageListHeads[MC_MAXIMUM];
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $Id: mdl.c,v 1.61 2004/04/10 22:35:25 gdalsnes Exp $
|
/* $Id: mdl.c,v 1.62 2004/04/20 18:59:00 gdalsnes Exp $
|
||||||
*
|
*
|
||||||
* COPYRIGHT: See COPYING in the top level directory
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
* PROJECT: ReactOS kernel
|
* PROJECT: ReactOS kernel
|
||||||
|
@ -30,6 +30,18 @@ static PVOID MiMdlMappingRegionBase = NULL;
|
||||||
static RTL_BITMAP MiMdlMappingRegionAllocMap;
|
static RTL_BITMAP MiMdlMappingRegionAllocMap;
|
||||||
static ULONG MiMdlMappingRegionHint;
|
static ULONG MiMdlMappingRegionHint;
|
||||||
static KSPIN_LOCK MiMdlMappingRegionLock;
|
static KSPIN_LOCK MiMdlMappingRegionLock;
|
||||||
|
extern ULONG MmPageArraySize;
|
||||||
|
|
||||||
|
/*
|
||||||
|
MDL Flags desc.
|
||||||
|
|
||||||
|
MDL_PAGES_LOCKED MmProbelAndLockPages has been called for this mdl
|
||||||
|
MDL_SOURCE_IS_NONPAGED_POOL mdl has been build by MmBuildMdlForNonPagedPool
|
||||||
|
MDL_PARTIAL mdl has been built by IoBuildPartialMdl
|
||||||
|
MDL_MAPPING_CAN_FAIL in case of an error, MmMapLockedPages will return NULL instead of to bugcheck
|
||||||
|
MDL_MAPPED_TO_SYSTEM_VA mdl has been mapped into kernel space using MmMapLockedPages
|
||||||
|
MDL_PARTIAL_HAS_BEEN_MAPPED mdl flagged MDL_PARTIAL has been mapped into kernel space using MmMapLockedPages
|
||||||
|
*/
|
||||||
|
|
||||||
/* FUNCTIONS *****************************************************************/
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
|
@ -82,7 +94,7 @@ MmGetMdlPageAddress(PMDL Mdl, PVOID Offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @unimplemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
VOID STDCALL
|
VOID STDCALL
|
||||||
MmUnlockPages(PMDL Mdl)
|
MmUnlockPages(PMDL Mdl)
|
||||||
|
@ -93,11 +105,38 @@ MmUnlockPages(PMDL Mdl)
|
||||||
* NOTES: The memory described by the specified MDL must have been locked
|
* NOTES: The memory described by the specified MDL must have been locked
|
||||||
* previously by a call to MmProbeAndLockPages. As the pages unlocked, the
|
* previously by a call to MmProbeAndLockPages. As the pages unlocked, the
|
||||||
* MDL is updated
|
* MDL is updated
|
||||||
|
*
|
||||||
|
* May be called in any process context.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
ULONG i;
|
ULONG i;
|
||||||
PULONG MdlPages;
|
PULONG MdlPages;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MmProbeAndLockPages MUST have been called to lock this mdl!
|
||||||
|
*
|
||||||
|
* Windows will bugcheck if you pass MmUnlockPages an mdl that hasn't been
|
||||||
|
* locked with MmLockAndProbePages, but (for now) we'll be more forgiving...
|
||||||
|
*/
|
||||||
|
if (!(Mdl->MdlFlags & MDL_PAGES_LOCKED))
|
||||||
|
{
|
||||||
|
DPRINT1("MmUnlockPages called for non-locked mdl!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If mdl buffer is mapped io space -> do nothing */
|
||||||
|
if (Mdl->MdlFlags & MDL_IO_SPACE)
|
||||||
|
{
|
||||||
|
Mdl->MdlFlags &= ~MDL_PAGES_LOCKED;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Automagically undo any calls to MmGetSystemAddressForMdl's for this mdl */
|
||||||
|
if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
|
||||||
|
{
|
||||||
|
MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FIXME: I don't know whether this right, but it looks sensible
|
* FIXME: I don't know whether this right, but it looks sensible
|
||||||
*/
|
*/
|
||||||
|
@ -107,13 +146,6 @@ MmUnlockPages(PMDL Mdl)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* FIXME: Seems sensible
|
|
||||||
*/
|
|
||||||
if (!(Mdl->MdlFlags & MDL_PAGES_LOCKED))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MdlPages = (PULONG)(Mdl + 1);
|
MdlPages = (PULONG)(Mdl + 1);
|
||||||
for (i=0; i<(PAGE_ROUND_UP(Mdl->ByteCount+Mdl->ByteOffset)/PAGE_SIZE); i++)
|
for (i=0; i<(PAGE_ROUND_UP(Mdl->ByteCount+Mdl->ByteOffset)/PAGE_SIZE); i++)
|
||||||
|
@ -130,9 +162,12 @@ MmUnlockPages(PMDL Mdl)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
Mdl->MdlFlags = Mdl->MdlFlags & (~MDL_PAGES_LOCKED);
|
|
||||||
|
Mdl->MdlFlags &= ~MDL_PAGES_LOCKED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @implemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
|
@ -141,30 +176,28 @@ MmMapLockedPages(PMDL Mdl, KPROCESSOR_MODE AccessMode)
|
||||||
/*
|
/*
|
||||||
* FUNCTION: Maps the physical pages described by a given MDL
|
* FUNCTION: Maps the physical pages described by a given MDL
|
||||||
* ARGUMENTS:
|
* ARGUMENTS:
|
||||||
* Mdl = Points to an MDL updated by MmProbeAndLockPages
|
* Mdl = Points to an MDL updated by MmProbeAndLockPages, MmBuildMdlForNonPagedPool
|
||||||
|
* or IoBuildPartialMdl.
|
||||||
* AccessMode = Specifies the portion of the address space to map the
|
* AccessMode = Specifies the portion of the address space to map the
|
||||||
* pages.
|
* pages.
|
||||||
* RETURNS: The base virtual address that maps the locked pages for the
|
* RETURNS: The base virtual address that maps the locked pages for the
|
||||||
* range described by the MDL
|
* range described by the MDL
|
||||||
|
*
|
||||||
|
* If mapping into user space, pages are mapped into current address space.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
PVOID Base;
|
PVOID Base;
|
||||||
ULONG i;
|
ULONG i;
|
||||||
PULONG MdlPages;
|
PULONG MdlPages;
|
||||||
KIRQL oldIrql;
|
KIRQL oldIrql;
|
||||||
ULONG RegionSize;
|
ULONG PageCount;
|
||||||
ULONG StartingOffset;
|
ULONG StartingOffset;
|
||||||
PEPROCESS CurrentProcess, OldProcess;
|
PEPROCESS CurrentProcess;
|
||||||
|
|
||||||
DPRINT("MmMapLockedPages(Mdl %x, AccessMode %x)\n", Mdl, AccessMode);
|
DPRINT("MmMapLockedPages(Mdl %x, AccessMode %x)\n", Mdl, AccessMode);
|
||||||
|
|
||||||
if ((Mdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL) && AccessMode != UserMode)
|
|
||||||
{
|
|
||||||
return(Mdl->MappedSystemVa);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Calculate the number of pages required. */
|
/* Calculate the number of pages required. */
|
||||||
RegionSize = PAGE_ROUND_UP(Mdl->ByteCount + Mdl->ByteOffset) / PAGE_SIZE;
|
PageCount = PAGE_ROUND_UP(Mdl->ByteCount + Mdl->ByteOffset) / PAGE_SIZE;
|
||||||
|
|
||||||
if (AccessMode == UserMode)
|
if (AccessMode == UserMode)
|
||||||
{
|
{
|
||||||
|
@ -172,22 +205,20 @@ MmMapLockedPages(PMDL Mdl, KPROCESSOR_MODE AccessMode)
|
||||||
LARGE_INTEGER BoundaryAddressMultiple;
|
LARGE_INTEGER BoundaryAddressMultiple;
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
/* pretty sure you can't map partial mdl's to user space */
|
||||||
|
assert(!(Mdl->MdlFlags & MDL_PARTIAL));
|
||||||
|
|
||||||
BoundaryAddressMultiple.QuadPart = 0;
|
BoundaryAddressMultiple.QuadPart = 0;
|
||||||
Base = NULL;
|
Base = NULL;
|
||||||
|
|
||||||
CurrentProcess = OldProcess = PsGetCurrentProcess();
|
CurrentProcess = PsGetCurrentProcess();
|
||||||
if (Mdl->Process != CurrentProcess)
|
|
||||||
{
|
|
||||||
KeAttachProcess(Mdl->Process);
|
|
||||||
CurrentProcess = Mdl->Process;
|
|
||||||
}
|
|
||||||
|
|
||||||
MmLockAddressSpace(&CurrentProcess->AddressSpace);
|
MmLockAddressSpace(&CurrentProcess->AddressSpace);
|
||||||
Status = MmCreateMemoryArea(CurrentProcess,
|
Status = MmCreateMemoryArea(CurrentProcess,
|
||||||
&CurrentProcess->AddressSpace,
|
&CurrentProcess->AddressSpace,
|
||||||
MEMORY_AREA_MDL_MAPPING,
|
MEMORY_AREA_MDL_MAPPING,
|
||||||
&Base,
|
&Base,
|
||||||
RegionSize * PAGE_SIZE,
|
PageCount * PAGE_SIZE,
|
||||||
0, /* PAGE_READWRITE? */
|
0, /* PAGE_READWRITE? */
|
||||||
&Result,
|
&Result,
|
||||||
FALSE,
|
FALSE,
|
||||||
|
@ -196,22 +227,40 @@ MmMapLockedPages(PMDL Mdl, KPROCESSOR_MODE AccessMode)
|
||||||
MmUnlockAddressSpace(&CurrentProcess->AddressSpace);
|
MmUnlockAddressSpace(&CurrentProcess->AddressSpace);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
|
if (Mdl->MdlFlags & MDL_MAPPING_CAN_FAIL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
KEBUGCHECK(0);
|
KEBUGCHECK(0);
|
||||||
/* FIXME: handle this? */
|
/* FIXME: handle this? */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else /* if (AccessMode == KernelMode) */
|
||||||
{
|
{
|
||||||
CurrentProcess = OldProcess = NULL;
|
/* can't map mdl twice */
|
||||||
|
assert(!(Mdl->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA|MDL_PARTIAL_HAS_BEEN_MAPPED)));
|
||||||
|
/* can't map mdl buildt from non paged pool into kernel space */
|
||||||
|
assert(!(Mdl->MdlFlags & (MDL_SOURCE_IS_NONPAGED_POOL)));
|
||||||
|
|
||||||
|
CurrentProcess = NULL;
|
||||||
|
|
||||||
/* Allocate that number of pages from the mdl mapping region. */
|
/* Allocate that number of pages from the mdl mapping region. */
|
||||||
KeAcquireSpinLock(&MiMdlMappingRegionLock, &oldIrql);
|
KeAcquireSpinLock(&MiMdlMappingRegionLock, &oldIrql);
|
||||||
|
|
||||||
StartingOffset = RtlFindClearBitsAndSet(&MiMdlMappingRegionAllocMap, RegionSize, MiMdlMappingRegionHint);
|
StartingOffset = RtlFindClearBitsAndSet(&MiMdlMappingRegionAllocMap, PageCount, MiMdlMappingRegionHint);
|
||||||
|
|
||||||
if (StartingOffset == 0xffffffff)
|
if (StartingOffset == 0xffffffff)
|
||||||
{
|
{
|
||||||
|
KeReleaseSpinLock(&MiMdlMappingRegionLock, oldIrql);
|
||||||
|
|
||||||
DPRINT1("Out of MDL mapping space\n");
|
DPRINT1("Out of MDL mapping space\n");
|
||||||
|
|
||||||
|
if (Mdl->MdlFlags & MDL_MAPPING_CAN_FAIL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
KEBUGCHECK(0);
|
KEBUGCHECK(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,7 +268,7 @@ MmMapLockedPages(PMDL Mdl, KPROCESSOR_MODE AccessMode)
|
||||||
|
|
||||||
if (MiMdlMappingRegionHint == StartingOffset)
|
if (MiMdlMappingRegionHint == StartingOffset)
|
||||||
{
|
{
|
||||||
MiMdlMappingRegionHint +=RegionSize;
|
MiMdlMappingRegionHint += PageCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
KeReleaseSpinLock(&MiMdlMappingRegionLock, oldIrql);
|
KeReleaseSpinLock(&MiMdlMappingRegionLock, oldIrql);
|
||||||
|
@ -229,7 +278,7 @@ MmMapLockedPages(PMDL Mdl, KPROCESSOR_MODE AccessMode)
|
||||||
|
|
||||||
/* Set the virtual mappings for the MDL pages. */
|
/* Set the virtual mappings for the MDL pages. */
|
||||||
MdlPages = (PULONG)(Mdl + 1);
|
MdlPages = (PULONG)(Mdl + 1);
|
||||||
for (i = 0; i < RegionSize; i++)
|
for (i = 0; i < PageCount; i++)
|
||||||
{
|
{
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
#if !defined(__GNUC__)
|
#if !defined(__GNUC__)
|
||||||
|
@ -250,18 +299,28 @@ MmMapLockedPages(PMDL Mdl, KPROCESSOR_MODE AccessMode)
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
DbgPrint("Unable to create virtual mapping\n");
|
DbgPrint("Unable to create virtual mapping\n");
|
||||||
|
if (Mdl->MdlFlags & MDL_MAPPING_CAN_FAIL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
KEBUGCHECK(0);
|
KEBUGCHECK(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AccessMode == UserMode && CurrentProcess != OldProcess)
|
/* Mark the MDL has having being mapped. */
|
||||||
|
if (AccessMode == KernelMode)
|
||||||
{
|
{
|
||||||
KeDetachProcess();
|
if (Mdl->MdlFlags & MDL_PARTIAL)
|
||||||
|
{
|
||||||
|
Mdl->MdlFlags |= MDL_PARTIAL_HAS_BEEN_MAPPED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Mdl->MdlFlags |= MDL_MAPPED_TO_SYSTEM_VA;
|
||||||
|
}
|
||||||
|
Mdl->MappedSystemVa = (char*)Base + Mdl->ByteOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mark the MDL has having being mapped. */
|
|
||||||
Mdl->MdlFlags = Mdl->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA;
|
|
||||||
Mdl->MappedSystemVa = (char*)Base + Mdl->ByteOffset;
|
|
||||||
return((char*)Base + Mdl->ByteOffset);
|
return((char*)Base + Mdl->ByteOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,13 +334,14 @@ MmUnmapLockedPages(PVOID BaseAddress, PMDL Mdl)
|
||||||
* ARGUMENTS:
|
* ARGUMENTS:
|
||||||
* BaseAddress = Base virtual address to which the pages were mapped
|
* BaseAddress = Base virtual address to which the pages were mapped
|
||||||
* MemoryDescriptorList = MDL describing the mapped pages
|
* MemoryDescriptorList = MDL describing the mapped pages
|
||||||
|
*
|
||||||
|
* User space unmappings _must_ be done from the original process context!
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
KIRQL oldIrql;
|
KIRQL oldIrql;
|
||||||
ULONG i;
|
ULONG i;
|
||||||
ULONG RegionSize;
|
ULONG PageCount;
|
||||||
ULONG Base;
|
ULONG Base;
|
||||||
PEPROCESS CurrentProcess, OldProcess;
|
|
||||||
|
|
||||||
DPRINT("MmUnmapLockedPages(BaseAddress %x, Mdl %x)\n", BaseAddress, Mdl);
|
DPRINT("MmUnmapLockedPages(BaseAddress %x, Mdl %x)\n", BaseAddress, Mdl);
|
||||||
|
|
||||||
|
@ -295,36 +355,18 @@ MmUnmapLockedPages(PVOID BaseAddress, PMDL Mdl)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ULONG_PTR)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. */
|
/* Calculate the number of pages we mapped. */
|
||||||
RegionSize = PAGE_ROUND_UP(Mdl->ByteCount + Mdl->ByteOffset) / PAGE_SIZE;
|
PageCount = PAGE_ROUND_UP(Mdl->ByteCount + Mdl->ByteOffset) / PAGE_SIZE;
|
||||||
#if defined(__GNUC__)
|
|
||||||
|
|
||||||
BaseAddress -= Mdl->ByteOffset;
|
/*
|
||||||
#else
|
* Docs says that BaseAddress should be a _base_ address, but every example
|
||||||
|
* I've seen pass the actual address. -Gunnar
|
||||||
{
|
*/
|
||||||
char* pTemp = BaseAddress;
|
BaseAddress = PAGE_ALIGN(BaseAddress);
|
||||||
pTemp -= Mdl->ByteOffset;
|
|
||||||
BaseAddress = pTemp;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Unmap all the pages. */
|
/* Unmap all the pages. */
|
||||||
for (i = 0; i < RegionSize; i++)
|
for (i = 0; i < PageCount; i++)
|
||||||
{
|
{
|
||||||
MmDeleteVirtualMapping(NULL,
|
MmDeleteVirtualMapping(NULL,
|
||||||
(char*)BaseAddress + (i * PAGE_SIZE),
|
(char*)BaseAddress + (i * PAGE_SIZE),
|
||||||
|
@ -335,38 +377,39 @@ MmUnmapLockedPages(PVOID BaseAddress, PMDL Mdl)
|
||||||
|
|
||||||
if ((DWORD)BaseAddress >= KERNEL_BASE)
|
if ((DWORD)BaseAddress >= KERNEL_BASE)
|
||||||
{
|
{
|
||||||
|
assert(Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA);
|
||||||
|
|
||||||
KeAcquireSpinLock(&MiMdlMappingRegionLock, &oldIrql);
|
KeAcquireSpinLock(&MiMdlMappingRegionLock, &oldIrql);
|
||||||
/* Deallocate all the pages used. */
|
/* Deallocate all the pages used. */
|
||||||
Base = (ULONG)((char*)BaseAddress - (char*)MiMdlMappingRegionBase) / PAGE_SIZE;
|
Base = (ULONG)((char*)BaseAddress - (char*)MiMdlMappingRegionBase) / PAGE_SIZE;
|
||||||
|
|
||||||
RtlClearBits(&MiMdlMappingRegionAllocMap, Base, RegionSize);
|
RtlClearBits(&MiMdlMappingRegionAllocMap, Base, PageCount);
|
||||||
|
|
||||||
MiMdlMappingRegionHint = min (MiMdlMappingRegionHint, Base);
|
MiMdlMappingRegionHint = min (MiMdlMappingRegionHint, Base);
|
||||||
|
|
||||||
KeReleaseSpinLock(&MiMdlMappingRegionLock, oldIrql);
|
KeReleaseSpinLock(&MiMdlMappingRegionLock, oldIrql);
|
||||||
|
|
||||||
|
/* Reset the MDL state. */
|
||||||
|
Mdl->MdlFlags &= ~MDL_MAPPED_TO_SYSTEM_VA;
|
||||||
|
Mdl->MappedSystemVa = NULL;
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MEMORY_AREA *Marea;
|
MEMORY_AREA *Marea;
|
||||||
|
|
||||||
Marea = MmOpenMemoryAreaByAddress( &CurrentProcess->AddressSpace, BaseAddress );
|
assert(Mdl->Process == PsGetCurrentProcess());
|
||||||
|
|
||||||
|
Marea = MmOpenMemoryAreaByAddress( &Mdl->Process->AddressSpace, BaseAddress );
|
||||||
if (Marea == NULL)
|
if (Marea == NULL)
|
||||||
{
|
{
|
||||||
DPRINT1( "Couldn't open memory area when unmapping user-space pages!\n" );
|
DPRINT1( "Couldn't open memory area when unmapping user-space pages!\n" );
|
||||||
KEBUGCHECK(0);
|
KEBUGCHECK(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
MmFreeMemoryArea( &CurrentProcess->AddressSpace, Marea->BaseAddress, 0, NULL, NULL );
|
MmFreeMemoryArea( &Mdl->Process->AddressSpace, Marea->BaseAddress, 0, NULL, NULL );
|
||||||
|
|
||||||
if (CurrentProcess != OldProcess)
|
|
||||||
{
|
|
||||||
KeDetachProcess();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reset the MDL state. */
|
|
||||||
Mdl->MdlFlags = Mdl->MdlFlags & ~MDL_MAPPED_TO_SYSTEM_VA;
|
|
||||||
Mdl->MappedSystemVa = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -376,17 +419,19 @@ MmBuildMdlFromPages(PMDL Mdl, PULONG Pages)
|
||||||
ULONG i;
|
ULONG i;
|
||||||
PULONG MdlPages;
|
PULONG MdlPages;
|
||||||
|
|
||||||
Mdl->MdlFlags = Mdl->MdlFlags |
|
|
||||||
(MDL_PAGES_LOCKED | MDL_IO_PAGE_READ);
|
|
||||||
|
|
||||||
MdlPages = (PULONG)(Mdl + 1);
|
MdlPages = (PULONG)(Mdl + 1);
|
||||||
|
|
||||||
for (i=0;i<(PAGE_ROUND_UP(Mdl->ByteOffset+Mdl->ByteCount)/PAGE_SIZE);i++)
|
for (i=0;i<(PAGE_ROUND_UP(Mdl->ByteOffset+Mdl->ByteCount)/PAGE_SIZE);i++)
|
||||||
{
|
{
|
||||||
MdlPages[i] = Pages[i];
|
MdlPages[i] = Pages[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//FIXME: this flag should be set by the caller perhaps?
|
||||||
|
Mdl->MdlFlags |= MDL_IO_PAGE_READ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @unimplemented
|
* @unimplemented
|
||||||
*/
|
*/
|
||||||
|
@ -399,6 +444,11 @@ VOID STDCALL MmProbeAndLockPages (PMDL Mdl,
|
||||||
* Mdl = MDL to probe
|
* Mdl = MDL to probe
|
||||||
* AccessMode = Access at which to probe the buffer
|
* AccessMode = Access at which to probe the buffer
|
||||||
* Operation = Operation to probe for
|
* Operation = Operation to probe for
|
||||||
|
*
|
||||||
|
* This function can be seen as a safe version of MmBuildMdlForNonPagedPool
|
||||||
|
* used in cases where you know that the mdl address is paged memory or
|
||||||
|
* you don't know where the mdl address comes from. MmProbeAndLockPages will
|
||||||
|
* work no matter what kind of mdl address you have.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
PULONG MdlPages;
|
PULONG MdlPages;
|
||||||
|
@ -406,47 +456,65 @@ VOID STDCALL MmProbeAndLockPages (PMDL Mdl,
|
||||||
ULONG NrPages;
|
ULONG NrPages;
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
KPROCESSOR_MODE Mode;
|
KPROCESSOR_MODE Mode;
|
||||||
PEPROCESS CurrentProcess = NULL;
|
PEPROCESS CurrentProcess = PsGetCurrentProcess();
|
||||||
|
|
||||||
DPRINT("MmProbeAndLockPages(Mdl %x)\n", Mdl);
|
DPRINT("MmProbeAndLockPages(Mdl %x)\n", Mdl);
|
||||||
|
|
||||||
/*
|
assert(!(Mdl->MdlFlags & (MDL_PAGES_LOCKED|MDL_MAPPED_TO_SYSTEM_VA|MDL_PARTIAL|
|
||||||
* FIXME: Check behaviour against NT
|
MDL_IO_SPACE|MDL_SOURCE_IS_NONPAGED_POOL)));
|
||||||
*/
|
|
||||||
if (Mdl->MdlFlags & MDL_PAGES_LOCKED)
|
MdlPages = (ULONG *)(Mdl + 1);
|
||||||
|
NrPages = PAGE_ROUND_UP(Mdl->ByteOffset + Mdl->ByteCount) / PAGE_SIZE;
|
||||||
|
|
||||||
|
/* mdl must have enough page entries */
|
||||||
|
assert(NrPages <= (Mdl->Size - sizeof(MDL))/sizeof(ULONG));
|
||||||
|
|
||||||
|
|
||||||
|
if (Mdl->StartVa >= (PVOID)KERNEL_BASE &&
|
||||||
|
(MmGetPhysicalAddressForProcess(NULL, Mdl->StartVa).u.LowPart >> PAGE_SHIFT) > MmPageArraySize)
|
||||||
{
|
{
|
||||||
|
/* phys addr is not phys memory so this must be io memory */
|
||||||
|
|
||||||
|
for (i = 0; i < NrPages; i++)
|
||||||
|
{
|
||||||
|
MdlPages[i] = MmGetPhysicalAddressForProcess(NULL, (char*)Mdl->StartVa + (i*PAGE_SIZE)).u.LowPart;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mdl->MdlFlags |= MDL_PAGES_LOCKED|MDL_IO_SPACE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (Mdl->StartVa >= (PVOID)KERNEL_BASE)
|
if (Mdl->StartVa >= (PVOID)KERNEL_BASE)
|
||||||
{
|
{
|
||||||
|
//FIXME: why isn't AccessMode used?
|
||||||
Mode = KernelMode;
|
Mode = KernelMode;
|
||||||
|
Mdl->Process = NULL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
//FIXME: why isn't AccessMode used?
|
||||||
Mode = UserMode;
|
Mode = UserMode;
|
||||||
CurrentProcess = PsGetCurrentProcess();
|
Mdl->Process = CurrentProcess;
|
||||||
if (Mdl->Process != CurrentProcess)
|
|
||||||
{
|
|
||||||
KeAttachProcess(Mdl->Process);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Lock the pages
|
* Lock the pages
|
||||||
*/
|
*/
|
||||||
|
MmLockAddressSpace(&CurrentProcess->AddressSpace);
|
||||||
|
|
||||||
MmLockAddressSpace(&Mdl->Process->AddressSpace);
|
|
||||||
MdlPages = (ULONG *)(Mdl + 1);
|
|
||||||
NrPages = PAGE_ROUND_UP(Mdl->ByteOffset + Mdl->ByteCount) / PAGE_SIZE;
|
|
||||||
for (i = 0; i < NrPages; i++)
|
for (i = 0; i < NrPages; i++)
|
||||||
{
|
{
|
||||||
PVOID Address;
|
PVOID Address;
|
||||||
|
|
||||||
Address = (char*)Mdl->StartVa + (i*PAGE_SIZE);
|
Address = (char*)Mdl->StartVa + (i*PAGE_SIZE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME: skip the probing/access stuff if buffer is nonpaged kernel space?
|
||||||
|
* -Gunnar
|
||||||
|
*/
|
||||||
|
|
||||||
if (!MmIsPagePresent(NULL, Address))
|
if (!MmIsPagePresent(NULL, Address))
|
||||||
{
|
{
|
||||||
Status = MmNotPresentFault(Mode, (ULONG)Address, TRUE);
|
Status = MmNotPresentFault(Mode, (ULONG)Address, TRUE);
|
||||||
|
@ -473,6 +541,7 @@ VOID STDCALL MmProbeAndLockPages (PMDL Mdl,
|
||||||
{
|
{
|
||||||
MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
|
MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((Operation == IoWriteAccess || Operation == IoModifyAccess) &&
|
if ((Operation == IoWriteAccess || Operation == IoModifyAccess) &&
|
||||||
(!(MmGetPageProtect(NULL, (PVOID)Address) & PAGE_READWRITE)))
|
(!(MmGetPageProtect(NULL, (PVOID)Address) & PAGE_READWRITE)))
|
||||||
{
|
{
|
||||||
|
@ -511,12 +580,9 @@ VOID STDCALL MmProbeAndLockPages (PMDL Mdl,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
MmUnlockAddressSpace(&Mdl->Process->AddressSpace);
|
|
||||||
if (Mode == UserMode && Mdl->Process != CurrentProcess)
|
MmUnlockAddressSpace(&CurrentProcess->AddressSpace);
|
||||||
{
|
Mdl->MdlFlags |= MDL_PAGES_LOCKED;
|
||||||
KeDetachProcess();
|
|
||||||
}
|
|
||||||
Mdl->MdlFlags = Mdl->MdlFlags | MDL_PAGES_LOCKED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -552,16 +618,33 @@ MmBuildMdlForNonPagedPool (PMDL Mdl)
|
||||||
* ARGUMENTS:
|
* 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
|
* byte offset and length
|
||||||
|
*
|
||||||
|
* This function can be seen as a fast version of MmProbeAndLockPages in case
|
||||||
|
* you _know_ that the mdl address is within nonpaged kernel space.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
ULONG va;
|
ULONG i;
|
||||||
Mdl->MdlFlags = Mdl->MdlFlags |
|
ULONG PageCount;
|
||||||
(MDL_SOURCE_IS_NONPAGED_POOL | MDL_PAGES_LOCKED);
|
|
||||||
for (va=0; va < ((Mdl->Size - sizeof(MDL)) / sizeof(ULONG)); va++)
|
/*
|
||||||
|
* mdl buffer must (at least) be in kernel space, thou this doesn't
|
||||||
|
* necesarely mean that the buffer in within _nonpaged_ kernel space...
|
||||||
|
*/
|
||||||
|
assert((ULONG)Mdl->StartVa >= KERNEL_BASE);
|
||||||
|
|
||||||
|
PageCount = PAGE_ROUND_UP(Mdl->ByteOffset + Mdl->ByteCount) / PAGE_SIZE;
|
||||||
|
|
||||||
|
/* mdl must have enough page entries */
|
||||||
|
assert(PageCount <= (Mdl->Size - sizeof(MDL))/sizeof(ULONG));
|
||||||
|
|
||||||
|
for (i=0; i < PageCount; i++)
|
||||||
{
|
{
|
||||||
((PULONG)(Mdl + 1))[va] =
|
((PULONG)(Mdl + 1))[i] =
|
||||||
(MmGetPhysicalAddress((char*)Mdl->StartVa + (va * PAGE_SIZE))).u.LowPart;
|
(MmGetPhysicalAddress((char*)Mdl->StartVa + (i * PAGE_SIZE))).u.LowPart;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Mdl->MdlFlags |= MDL_SOURCE_IS_NONPAGED_POOL;
|
||||||
|
Mdl->Process = NULL;
|
||||||
Mdl->MappedSystemVa = (char*)Mdl->StartVa + Mdl->ByteOffset;
|
Mdl->MappedSystemVa = (char*)Mdl->StartVa + Mdl->ByteOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -570,7 +653,7 @@ MmBuildMdlForNonPagedPool (PMDL Mdl)
|
||||||
* @implemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
PMDL STDCALL
|
PMDL STDCALL
|
||||||
MmCreateMdl (PMDL MemoryDescriptorList,
|
MmCreateMdl (PMDL Mdl,
|
||||||
PVOID Base,
|
PVOID Base,
|
||||||
ULONG Length)
|
ULONG Length)
|
||||||
/*
|
/*
|
||||||
|
@ -583,22 +666,22 @@ MmCreateMdl (PMDL MemoryDescriptorList,
|
||||||
* RETURNS: A pointer to initalized MDL
|
* RETURNS: A pointer to initalized MDL
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
if (MemoryDescriptorList == NULL)
|
if (Mdl == NULL)
|
||||||
{
|
{
|
||||||
ULONG Size;
|
ULONG Size;
|
||||||
|
|
||||||
Size = MmSizeOfMdl(Base,Length);
|
Size = MmSizeOfMdl(Base,Length);
|
||||||
MemoryDescriptorList =
|
Mdl =
|
||||||
(PMDL)ExAllocatePoolWithTag(NonPagedPool, Size, TAG_MDL);
|
(PMDL)ExAllocatePoolWithTag(NonPagedPool, Size, TAG_MDL);
|
||||||
if (MemoryDescriptorList == NULL)
|
if (Mdl == NULL)
|
||||||
{
|
{
|
||||||
return(NULL);
|
return(NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MmInitializeMdl(MemoryDescriptorList, (char*)Base, Length);
|
MmInitializeMdl(Mdl, (char*)Base, Length);
|
||||||
|
|
||||||
return(MemoryDescriptorList);
|
return(Mdl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -620,6 +703,31 @@ MmAllocatePagesForMdl ( IN PHYSICAL_ADDRESS LowAddress,
|
||||||
IN PHYSICAL_ADDRESS SkipBytes,
|
IN PHYSICAL_ADDRESS SkipBytes,
|
||||||
IN SIZE_T Totalbytes )
|
IN SIZE_T Totalbytes )
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
MmAllocatePagesForMdl allocates zero-filled, nonpaged, physical memory pages to an MDL
|
||||||
|
|
||||||
|
MmAllocatePagesForMdlSearch the PFN database for free, zeroed or standby
|
||||||
|
pagesAllocates pages and puts in MDLDoes not map pages (caller responsibility)
|
||||||
|
Designed to be used by an AGP driver
|
||||||
|
|
||||||
|
LowAddress is the lowest acceptable physical address it wants to allocate
|
||||||
|
and HighAddress is the highest. SkipBytes are the number of bytes that the
|
||||||
|
kernel should keep free above LowAddress and below the address at which it
|
||||||
|
starts to allocate physical memory. TotalBytes are the number of bytes that
|
||||||
|
the driver wants to allocate. The return value of the function is a MDL
|
||||||
|
that if non-zero describes the physical memory the kernel has given the
|
||||||
|
driver. To access portions of the memory the driver must create sub-MDLs
|
||||||
|
from the returned MDL that describe appropriate portions of the physical
|
||||||
|
memory. When a driver wants to access physical memory described by a
|
||||||
|
sub-MDL it must map the sub-MDL using MmGetSystemAddressForMdlSafe.
|
||||||
|
|
||||||
|
Konstantin Gusev
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* SkipBytes must be a multiple of the page size */
|
||||||
|
assert((SkipBytes.QuadPart % PAGE_SIZE) == 0);
|
||||||
|
|
||||||
DPRINT1("MmAllocatePagesForMdl(): Unimplemented.\n");
|
DPRINT1("MmAllocatePagesForMdl(): Unimplemented.\n");
|
||||||
return(NULL);
|
return(NULL);
|
||||||
}
|
}
|
||||||
|
@ -627,6 +735,19 @@ MmAllocatePagesForMdl ( IN PHYSICAL_ADDRESS LowAddress,
|
||||||
VOID STDCALL
|
VOID STDCALL
|
||||||
MmFreePagesFromMdl ( IN PMDL Mdl )
|
MmFreePagesFromMdl ( IN PMDL Mdl )
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
Drivers use the MmFreePagesFromMdl, the kernel-mode equivalent of
|
||||||
|
FreeUserPhysicalPages, to free the physical memory it has allocated with
|
||||||
|
MmAllocatePagesForMdl. This function is also prototyped in ntddk.h:
|
||||||
|
|
||||||
|
Note that a driver is responsible for deallocating the MDL returned by
|
||||||
|
MmAllocatePagesForMdl with a call to ExFreePool, since MmFreePagesFromMdl
|
||||||
|
does not free the MDL.
|
||||||
|
|
||||||
|
Konstantin Gusev
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
DPRINT1("MmFreePagesFromMdl(): Unimplemented.\n");
|
DPRINT1("MmFreePagesFromMdl(): Unimplemented.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue