> From: Peter Wieland [mailto:xxxxx@windows.microsoft.com]
I believe reserve addresses are always in the kernel address space and
thus are available in any process context.
-p
Peter,
yes, you are right, I was wrong here.
MmAllocateMappingAddress() reserves system adress space.
Christiaan,
something is wrong in your implementation. Here is the relevant code from
my test driver that works perfectly under high memory pressure on XP SP1.
It implements your Scenarios 1 and 3:
#define MAPPED_TAG ‘tpaM’
MDL *mdl1, *mdl3;
void* mapping;
MDL*
AllocatePages(size_t numPages)
{
MDL* mdl;
PHYSICAL_ADDRESS zero;
PHYSICAL_ADDRESS topMemory;
zero.QuadPart = 0;
topMemory.QuadPart = -1;
/* allocate MDL, allocate pages, fill in the MDL */
mdl = MmAllocatePagesForMdl(zero, topMemory, zero, numPages * PAGE_SIZE);
if (mdl == NULL) {
DbgPrint((“Can’t MmAllocatePagesForMdl() to allocate %u pages\n”,
numPages));
return NULL;
}
if (MmGetMdlByteCount(mdl) != numPages * PAGE_SIZE) {
DbgPrint((“MmAllocatePagesForMdl() allocated only %u from %u requested
pages\n”,
MmGetMdlByteCount(mdl)/ PAGE_SIZE, numPages));
MmFreePagesFromMdl(mdl);
ExFreePool(mdl);
return NULL;
}
return mdl;
}
void
FreePages(MDL* mdl)
{
if (mdl) {
MmFreePagesFromMdl(mdl);
ExFreePool(mdl);
}
}
void*
ReserveSystemAdressSpace(size_t numPages)
{
return MmAllocateMappingAddress(numPages * PAGE_SIZE, MAPPED_TAG);
}
void
UnreserveSystemAdressSpace(void* ptr)
{
if (ptr) {
MmFreeMappingAddress(ptr, MAPPED_TAG);
}
}
void
MapWriteUmmapMem1(MDL* mdl)
{
static char c;
void* ptr;
ptr = MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority);
if (!ptr) {
KdBreakPoint();
return;
}
RtlFillMemory(ptr, MmGetMdlByteCount(mdl), c++);
MmUnmapLockedPages(ptr, mdl);
}
void
MapWriteUmmapMem3(MDL* mdl, void* reservedAddr)
{
static char c;
void* ptr;
ptr = MmMapLockedPagesWithReservedMapping (reservedAddr, MAPPED_TAG, mdl,
MmCached);
if (!ptr) {
KdBreakPoint();
return;
}
RtlFillMemory(ptr, MmGetMdlByteCount(mdl), c++);
MmUnmapReservedMapping(ptr, MAPPED_TAG, mdl);
}
LockMemDrvDeviceControl()
{
…
switch ( ioControlCode ) {
…
case IOCTL_LOCKMEM_MAP1: {
MapWriteUmmapMem1(mdl1);
break;
}
case IOCTL_LOCKMEM_MAP3: {
MapWriteUmmapMem3(mdl3, mapping);
break;
}
}
…
}
DriverEntry()
{
…
mdl1 = AllocatePages(16*1024*1024/PAGE_SIZE);
mdl3 = AllocatePages(16*1024*1024/PAGE_SIZE);
mapping = ReserveSystemAdressSpace(16*1024*1024/PAGE_SIZE);
…
}
LockMemDrvUnload()
{
…
FreePages(mdl1);
FreePages(mdl3);
UnreserveSystemAdressSpace(mapping);
…
}
Dmitriy Budko, VMware
-----Original Message-----
From: Christiaan Ghijselinck
[mailto:xxxxx@CompaqNet.be]
Sent: Tuesday, July 20, 2004 10:29 AM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] MmAllocatePagesForMdl and MmUnmapLockedPages
Many thanks for your answer.
Personally I did not notice that MmUnmapLockedPages() did
let hang the
MDL_MAPPED_TO_SYSTEM_VA flag. It has been cleared every time.
Probably because I build and linked the driver for XP ( DDK
2600 ) or due
of the latest W2000 service packs ( SP4 is installed ).
However, I did found out that MDL_PAGES_LOCKED is set by
MmAllocatePagesForMdl while running on XP and NOT while
running W2000.
Nevertheless, the PAGE_FAULT_IN_NONPAGED_AREA occurs also on XP
when using *scenario 1*. Could it have something to do with
the different
process contexts of MyAddDevice and MyReadWrite ? It’s
hardly to believe
that this is the cause of the problem, otherwise *Scenario 2*
would fail too.
Any ideas or suggestions are still very welcome !
*Scenario 3* is thus not an alternative, just because
MyReadWrite may be called
from different ( unknown ) processes. Or there should be a
way to circumvent that
behavior. It 's regrettable that those functions have such a
restricted usage.
Christiaan
----- Original Message -----
From: “Dmitriy Budko”
> To: “Windows System Software Devs Interest List”
> Cc:
> Sent: Tuesday, July 20, 2004 4:33 AM
> Subject: RE: [ntdev] MmAllocatePagesForMdl and MmUnmapLockedPages
>
>
> > Christiaan,
> >
> > MmGetSystemAddressForMdlSafe() is a macro that checks
> > MDL_MAPPED_TO_SYSTEM_VA flag inside the MDL.
> > If it is not set then the macro calls MmMapLockedPagesSpecifyCache()
> > See ddk.h for the definition of this macro.
> >
> > It seems that Windows 2000 MmUnmapLockedPages() has a bug: it
> > doesn’t clear MDL_MAPPED_TO_SYSTEM_VA
> > so you have to do it explicitly by doing
> >
> > MmUnmapLockedPages(…, mdl);
> > mdl->MdlFlags ~= MDL_MAPPED_TO_SYSTEM_VA;
> >
> > XP MmUnmapLockedPages() does it by itself.
> >
> >
> > In Scenario 3 it is very likely that you reserve virtual
> address space in the
> > context
> > of System process (PnP Manager) but then you try to use
> this address space in
> >
> > the arbitrary context (any process that reads/writes from
> you device if your
> > driver is
> > the top driver).
> >
> >
> > Dmitriy Budko, VMware
> >
> >
> >
> > > -----Original Message-----
> > > From: Christiaan Ghijselinck
> > >
> > > Sent: Sunday, July 18, 2004 1:39 PM
> > > To: Windows System Software Devs Interest List
> > > Subject: [ntdev] MmAllocatePagesForMdl and MmUnmapLockedPages
> > >
> > >
> > >
> > >
> > > Hello ,
> > >
> > >
> > > I like to reserve several chunks of memory and only map them
> > > when I need them. When I use the Scenario 1 flow on
> W2k, all seems
> > > to work until I call “MyReadWrite” for the second time. It
> > > seems to be that the “MmUnmapLockedPages” call does not
> > > revert the state
> > > of the MDL allocated pages as they were after I called
> > > MmGetSystemAddressForMdlSafe. Most of the time I get a
> > > “PAGE_FAULT_IN_NONPAGED_AREA” when accessing the “*PMemory”
> > > during the second call of “MyReadWrite”, sometimes it occurs
> > > during the
> > > 3rd of later call.
> > >
> > > When I tried out Scenario 2 , everything runs perfect !
> > > Now, I assume that when calling “MmUnmapLockedPages” and
> > > “MmGetSystemAddressForMdlSafe” shortly after each other, the
> > > allocated memory remains intact. When there is big time
> gab between
> > > those calls, the OS takes the time to unlock ( or whatever )
> > > the memory after the first call of “MmUnmapLockedPages”.
> > >
> > > When I try out Scenario 3 on Xp using the new
> > > “XP-and-higher” functions, I get literally the message “The
> > > driver is mismanaging
> > > system PTEs”.
> > >
> > > All scenario calls run at PASSIVE_LEVEL. Using the
> > > equivalents “MmMapLockedPagesSpecifyCache” or
> > > “MmMapLockedPages” instead of
> > > “MmGetSystemAddressForMdlSafe” brought no relief.
> > >
> > > When I looked around for samples in the DDK that also used
> > > MmAllocatePagesForMdl, I did found “intrface.c” at
> \kernel\agp\agplib.
> > > That sample adds MDL_PAGES_LOCKED into the Mdl flags after
> > > the call of MmAllocatePagesForMdl, but that didn’t solve the
> > > problem. Is
> > > there a way or trick to bring the memory described by the MDL
> > > back into a “good and healthy” status ?
> > >
> > > The scenarios are pseudo code only. All success/no-success
> > > defensive checks are omitted
> > >
> > > Scenario 1 ( Windows 2000 ) :
> > > ----------------------------
> > > MyAddDevice ( )
> > > {
> > > …
> > > DeviceExtension->pMDL = MmAllocatePagesForMdl ( LowAddress
> > > , HghAddress, SkipSize , ulChunkSize ) ;
> > > …
> > > }
> > > MyReadWrite ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
> > > {
> > > …
> > > DeviceExtension->pMemory = MmGetSystemAddressForMdlSafe (
> > > DeviceExtension->pMDL , HighPagePriority ) ;
> > >
> > > *(DeviceExtension->pMemory) = … // access the
> memory here …
> > >
> > > MmUnmapLockedPages ( DeviceExtension->pMemory ,
> > > DeviceExtension->pMDL ) ;
> > > }
> > >
> > > Scenario 2 ( Windows 2000 ) :
> > > ----------------------------
> > > MyAddDevice ( )
> > > {
> > > …
> > > DeviceExtension->pMDL = MmAllocatePagesForMdl (
> > > LowAddress , HghAddress, SkipSize , ulChunkSize ) ;
> > > DeviceExtension->pMemory = MmGetSystemAddressForMdlSafe (
> > > DeviceExtension->pMDL , HighPagePriority ) ;
> > > …
> > > }
> > > MyReadWrite ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
> > > {
> > > …
> > > MmUnmapLockedPages ( DeviceExtension->pMemory ,
> > > DeviceExtension->pMDL ) ;
> > > DeviceExtension->pMemory =
> > > MmGetSystemAddressForMdlSafe ( DeviceExtension->pMDL ,
> > > HighPagePriority ) ;
> > >
> > > *pMemory = … // access the memory here …
> > >
> > > //// commented out : MmUnmapLockedPages ( pMemory ,
> > > DeviceExtension->pMDL ) ;
> > > }
> > >
> > > Scenario 3 ( Windows XP ) :
> > > ----------------------------
> > > MyAddDevice ( )
> > > {
> > > …
> > > DeviceExtension->pMDL = MmAllocatePagesForMdl (
> > > LowAddress,HghAddress,SkipSize,ulChunkSize ) ;
> > > DeviceExtension->pMapping = MmAllocateMappingAddress (
> > > _size , uTag ) ;
> > > …
> > > }
> > > MyReadWrite ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
> > > {
> > > …
> > >
> > > DeviceExtension->pMemory =
> > > MmMapLockedPagesWithReservedMapping (
> > > DeviceExtension->pMapping , uTag , DeviceExtension->pMDL ,
> > > mNonCached ) ;
> > >
> > > *(DeviceExtension->pMemory) = … // access the
> memory here …
> > >
> > > MmUnmapReservedMapping ( DeviceExtension->pMemory , uTag
> > > , DeviceExtension->pMDL ) ;
> > > …
> > > }