Jump-start your project by learning from devs who
write Windows drivers and file systems every day.
Take an OSR seminar!

Upcoming OSR Seminars:
WDM Lab, Seattle, WA 16 August 2010
WDF Lab, Santa Clara, CA 27 September 2010
Debug Lab, Portland, OR 18 October 2010
Windows Internals & Software Drivers Lab, Santa Clara, CA 15 November 2010


Go Back   OSR Online Lists > ntdev
Welcome, Guest
You must login to post to this list
  Message 1 of 15  
18 Jun 09 10:55
Jason Summerour
xxxxxx@gmail.com
Join Date: 11 Jul 2007
Posts To This List: 114
MmAllocatePagesForMdl() cleanup

Hey guys, I have a kmdf video/audio driver that I'm buttoning up, and I seem to have a problem cleaning up userland memory that I have allocated using MmAllocatePagesForMdl() when closing a handle to the driver from a userland application. Using the document 'A Common Topic Explained - Sharing Memory Between Drivers and Applications', I'm using his second example for allocating shared memory. This memory is allocated when a user app opens up a handle to my driver (and should be in the user apps process context). The memory is allocated correctly, and I'm able to use it all day long to transfer video/audo frames down from userland to driver. I'm basically mapping about 500MB (60 frames - 2 seconds worth of 8MB video/audo buffers) between userland and the driver. When I close the app which utilizes the shared memory, I get no error when I perform the cleanup (I perform the cleanup in the EvtDeviceFileClose handler). However, when I open the app back up (and it tries to re-allocate the shared memory again), it gets to a point where I get an invalid kernel virutal address pointer during a call to MmGetSystemAddressForMdlSafe(). Please note that some initial requests to map the memory succeed, and it only returns an invalid kernel virtual address pointer after about 20 frames (or ~167MB of memory) have been allocated. So, it's like I'm not correctly freeing the memory in the previous close, and in the second open, it's basically using up all off the available memory. Do I need to do an MmUnmapLockedPages() on the kvAddr, in additon to the uvAddr below in my UnmapUserBuffer() call? // Allocate and initialize an MDL describing the dma common buffer memory // and map the memory to user space. NTSTATUS CreateAndMapUserBuffer(PVOID &uvAddr, PMDL &mdl, PVOID &kvAddr, size_t size, HANDLE pid) { PHYSICAL_ADDRESS lowAddr; PHYSICAL_ADDRESS highAddr; size_t allocated; // Set max/min physical memory addresses: lowAddr.QuadPart = 0; highAddr.QuadPart = _4G; // We're going to have to create an MDL for each frame!!! // This is zero filled, non-paged main memory pages: mdl = MmAllocatePagesForMdl(lowAddr, highAddr, lowAddr, size); if (!mdl) { DbgPrint("MmAllocatePagesForMdl() failed\n"); return STATUS_INSUFFICIENT_RESOURCES; } // Check to see how much memory was actually allocated to the mdl, versus requested: allocated = MmGetMdlByteCount(mdl); if (allocated < size) { DbgPrint("MmAllocatePagesForMdl() allocated less memory than we requested: req: 0x%08x allocated: 0x%08x\n", size, allocated); return STATUS_INSUFFICIENT_RESOURCES; } //DbgPrint("MmAllocatePagesForMdl(): requested: 0x%08x allocated: 0x%08x\n", size, allocated); // Get Kernel Virtual Address: // returns a nonpaged system-space virtual address for the buffer described by the mdl, // which can be used across any process contexts, and at any IRQL: // MmGetSystemAddressForMdl(Safe)(...) takes a buffer described by an MDL and // maps it into the high 2GB of kernel virtual addressing space. If the MDL // was built CORRECTLY, and the kernel virtual address that represents the data // buffer is in the high 2GB of kernel virtual address space, then the return // from these two functions will indeed be the same. kvAddr = MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority ); if (!kvAddr) { DbgPrint("Unable to get nonpaged kernel virtual address\n"); return STATUS_INSUFFICIENT_RESOURCES; } // Maps the physical pages that are described by the MDL and // specify the cache attribute that is used to create the mapping: // It returns the user virtual address of the memory: uvAddr = MmMapLockedPagesSpecifyCache(mdl, UserMode, // access mode MmCached, // v-to-p addr xlations cached NULL, // let system choose base addr FALSE, // no bug check on failure NormalPagePriority); if (!uvAddr) { DbgPrint("MmMapLockedPagesSpecifyCache()unable to map user address\n"); MmFreePagesFromMdl(mdl); IoFreeMdl(mdl); return STATUS_INSUFFICIENT_RESOURCES; } return STATUS_SUCCESS; } NTSTATUS UnmapUserBuffer(PMDL mdl, PVOID userVa) { // Clean up userland memory: if (mdl) { MmUnmapLockedPages(userVa, mdl); MmFreePagesFromMdl(mdl); IoFreeMdl(mdl); } else { return STATUS_UNSUCCESSFUL; } return STATUS_SUCCESS; } I'm sure it's obvious to one of you as to what I'm doing wrong... Any help would be greatly appreciated! Thanks guys! Jason
  Message 2 of 15  
18 Jun 09 11:10
Doron Holan
xxxxxx@microsoft.com
Join Date: 08 Sep 2005
Posts To This List: 5313
RE: MmAllocatePagesForMdl() cleanup

Evtfileclose is not guaranteed to be in app's context, only evtfilecleanup has that guarantee (if that matters). Did you enable driver verifier and see if it finds anything? d Sent from my phone with no t9, all spilling mistakes are not intentional. -----Original Message----- From: xxxxx@gmail.com <xxxxx@gmail.com> Sent: Thursday, June 18, 2009 7:55 AM To: Windows System Software Devs Interest List <xxxxx@lists.osr.com> Subject: [ntdev] MmAllocatePagesForMdl() cleanup Hey guys, I have a kmdf video/audio driver that I'm buttoning up, and I seem to have a problem cleaning up userland memory that I have allocated using MmAllocatePagesForMdl() when closing a handle to the driver from a userland application. Using the document 'A Common Topic Explained - Sharing Memory Between Drivers and Applications', I'm using his second example for allocating shared memory. This memory is allocated when a user app opens up a handle to my driver (and should be in the user apps process context). The memory is allocated correctly, and I'm able to use it all day long to transfer video/audo frames down from userland to driver. I'm basically mapping about 500MB (60 frames - 2 seconds worth of 8MB video/audo buffers) between userland and the driver. When I close the app which utilizes the shared memory, I get no error when I perform the cleanup (I perform the cleanup in the EvtDeviceFileClose handler). However, when I open the app back up (and it tries to re-allocate the shared memory again), it gets to a point where I get an invalid kernel virutal address pointer during a call to MmGetSystemAddressForMdlSafe(). Please note that some initial requests to map the memory succeed, and it only returns an invalid kernel virtual address pointer after about 20 frames (or ~167MB of memory) have been allocated. So, it's like I'm not correctly freeing the memory in the previous close, and in the second open, it's basically using up all off the available memory. Do I need to do an MmUnmapLockedPages() on the kvAddr, in additon to the uvAddr below in my UnmapUserBuffer() call? // Allocate and initialize an MDL describing the dma common buffer memory // and map the memory to user space. NTSTATUS CreateAndMapUserBuffer(PVOID &uvAddr, PMDL &mdl, PVOID &kvAddr, size_t size, HANDLE pid) { PHYSICAL_ADDRESS lowAddr; PHYSICAL_ADDRESS highAddr; size_t allocated; // Set max/min physical memory addresses: lowAddr.QuadPart = 0; highAddr.QuadPart = _4G; // We're going to have to create an MDL for each frame!!! // This is zero filled, non-paged main memory pages: mdl = MmAllocatePagesForMdl(lowAddr, highAddr, lowAddr, size); if (!mdl) { DbgPrint("MmAllocatePagesForMdl() failed\n"); return STATUS_INSUFFICIENT_RESOURCES; } // Check to see how much memory was actually allocated to the mdl, versus requested: allocated = MmGetMdlByteCount(mdl); if (allocated < size) { DbgPrint("MmAllocatePagesForMdl() allocated less memory than we requested: req: 0x%08x allocated: 0x%08x\n", size, allocated); return STATUS_INSUFFICIENT_RESOURCES; } //DbgPrint("MmAllocatePagesForMdl(): requested: 0x%08x allocated: 0x%08x\n", size, allocated); // Get Kernel Virtual Address: // returns a nonpaged system-space virtual address for the buffer described by the mdl, // which can be used across any process contexts, and at any IRQL: // MmGetSystemAddressForMdl(Safe)(...) takes a buffer described by an MDL and // maps it into the high 2GB of kernel virtual addressing space. If the MDL // was built CORRECTLY, and the kernel virtual address that represents the data // buffer is in the high 2GB of kernel virtual address space, then the return // from these two functions will indeed be the same. kvAddr = MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority ); if (!kvAddr) { DbgPrint("Unable to get nonpaged kernel virtual address\n"); return STATUS_INSUFFICIENT_RESOURCES; } // Maps the physical pages that are described by the MDL and // specify the cache attribute that is used to create the mapping: // It returns the user virtual address of the memory: uvAddr = MmMapLockedPagesSpecifyCache(mdl, UserMode, // access mode MmCached, // v-to-p addr xlations cached NULL, // let system choose base addr FALSE, // no bug check on failure NormalPagePriority); if (!uvAddr) { DbgPrint("MmMapLockedPagesSpecifyCache()unable to map user address\n"); MmFreePagesFromMdl(mdl); IoFreeMdl(mdl); return STATUS_INSUFFICIENT_RESOURCES; } return STATUS_SUCCESS; } NTSTATUS UnmapUserBuffer(PMDL mdl, PVOID userVa) { // Clean up userland memory: if (mdl) { MmUnmapLockedPages(userVa, mdl); MmFreePagesFromMdl(mdl); IoFreeMdl(mdl); } else { return STATUS_UNSUCCESSFUL; } return STATUS_SUCCESS; } I'm sure it's obvious to one of you as to what I'm doing wrong... Any help would be greatly appreciated! Thanks guys! Jason --- NTDEV is sponsored by OSR For our schedule of WDF, WDM, debugging and other seminars visit: http://www.osr.com/seminars To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer
  Message 3 of 15  
18 Jun 09 12:47
Jason Summerour
xxxxxx@gmail.com
Join Date: 11 Jul 2007
Posts To This List: 114
RE: MmAllocatePagesForMdl() cleanup

Hi Doron, I added an EvtFileCleanup handler, and retested. However, I'm getting the same results. I didn't have the Driver Verifier enabled at the time, but I will do that next, and see what I find. Anybody else have any clues? Thank you! Jason
  Message 4 of 15  
18 Jun 09 16:08
Peter Viscarola (OSR)
xxxxxx@osr.com
Join Date:
Posts To This List: 2475
List Moderator
RE: MmAllocatePagesForMdl() cleanup

I hate to say this (because it won't be much help), but your code looks OK to me. You reverse the call th MapPages with a call to UnMap pages. Then you reverse the call AllocatePagesForMdl with FreePagesFromMdl. You ARE taking that path in your "UnmapUserBuffer" function, right? You're not passing in NULL for the Mdl?? The only problem I've ever seen is trying to do the unmap operation in Close instead of in Cleanup. Aside from that... Peter OSR
  Message 5 of 15  
18 Jun 09 16:11
Jason Summerour
xxxxxx@gmail.com
Join Date: 11 Jul 2007
Posts To This List: 114
RE: MmAllocatePagesForMdl() cleanup

So, after a little bit more investigation, I see that the allocation of the memory via MmAllocatePagesForMdl() seems to work just fine, but it's only when I try to get a kernel virtual address of it, via MmGetSystemAddressForMdlSafe() that I get a null pointer back. If the memory was allocated correctly, why couldn't I get a kernel virtual address to it? Once I test the return status of MmGetSystemAddressForMdlSafe(), I simply return an error back to the driver open request, and the app fails to open it. I'm not getting an exception that I can trace. Any ideas? My basic allocation/deallocation algorithm above is: Allocate: mdl = MmAllocatePagesForMdl(lowAddr, highAddr, lowAddr, size); kvAddr = MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority); uvAddr = MmMapLockedPagesSpecifyCache(mdl, UserMode, MmCached, NULL, FALSE, NormalPagePriority); Deallocate:
  Message 6 of 15  
18 Jun 09 16:14
Jason Summerour
xxxxxx@gmail.com
Join Date: 11 Jul 2007
Posts To This List: 114
RE: MmAllocatePagesForMdl() cleanup

Dang it! I fat-fingered a few keys and didn't get to complete the last post... Deallocate: MmUnmapLockedPages(userVa, mdl); MmFreePagesFromMdl(mdl); IoFreeMdl(mdl); Peter, I'll double check that I'm not passing in a NULL for the mdl... Thanks guys, Jason
  Message 7 of 15  
18 Jun 09 16:14
Scott Noone
xxxxxx@osr.com
Join Date:
Posts To This List: 557
List Moderator
Re: MmAllocatePagesForMdl() cleanup

>If the memory was allocated correctly, why couldn't I get a kernel virtual >address to it? Two different resources, physical memory and a contiguous region of system PTEs to map it. How much memory are you trying to map? It could be that there isn't enough contiguous space to map it (either too fragmented or someone has a system PTE leak). Some information about the PTEs you need can be found with !sysptes in the debugger. -scott -- Scott Noone Consulting Associate OSR Open Systems Resources, Inc. http://www.osronline.com <xxxxx@gmail.com> wrote in message news:125991@ntdev... > So, after a little bit more investigation, I see that the allocation of > the memory via MmAllocatePagesForMdl() seems to work just fine, but it's > only when I try to get a kernel virtual address of it, via > MmGetSystemAddressForMdlSafe() that I get a null pointer back. If the > memory was allocated correctly, why couldn't I get a kernel virtual > address to it? > > Once I test the return status of MmGetSystemAddressForMdlSafe(), I simply > return an error back to the driver open request, and the app fails to open > it. I'm not getting an exception that I can trace. <...excess quoted lines suppressed...>
  Message 8 of 15  
18 Jun 09 16:17
Scott Noone
xxxxxx@osr.com
Join Date:
Posts To This List: 557
List Moderator
Re: MmAllocatePagesForMdl() cleanup

Aha! So *you're* the one with the system PTE leak :) You need to unmap you system virtual address also. -scott -- Scott Noone Consulting Associate OSR Open Systems Resources, Inc. http://www.osronline.com <xxxxx@gmail.com> wrote in message news:125992@ntdev... > Dang it! I fat-fingered a few keys and didn't get to complete the last > post... > > Deallocate: > > MmUnmapLockedPages(userVa, mdl); > MmFreePagesFromMdl(mdl); > IoFreeMdl(mdl); > > Peter, I'll double check that I'm not passing in a NULL for the mdl... <...excess quoted lines suppressed...>
  Message 9 of 15  
18 Jun 09 16:19
Peter Viscarola (OSR)
xxxxxx@osr.com
Join Date:
Posts To This List: 2475
List Moderator
RE: MmAllocatePagesForMdl() cleanup

If you can't get the Kernel Virtual Address Space, and you can restrict your driver to only touch the shared memory (via DMA or) when in the context of the user application, you can just refer to the memory block using the user virtual address you provide... Peter OSR
  Message 10 of 15  
18 Jun 09 16:27
Jason Summerour
xxxxxx@gmail.com
Join Date: 11 Jul 2007
Posts To This List: 114
RE: MmAllocatePagesForMdl() cleanup

Hey Scott, BAM! That worked Scott! Shoulda just tried that to begin with! Why is it a big deal that *I'm* the one w/ the system PTE leak? Are you guys lauging at me or something? LoL Before seeing your post, I was wondering if possibly another portion of my driver still had a reference to the memory, and it wasn't getting deallocated correctly or something. Thanks bro!
  Message 11 of 15  
18 Jun 09 16:31
Christiaan Ghijselinck
xxxxxx@CompaqNet.be
Join Date: 21 Mar 2002
Posts To This List: 419
Re: RE:MmAllocatePagesForMdl() cleanup

Is it correct to call IoFreeMdl(mdl); after calling MmFreePagesFromMdl(mdl); ? As far as I know , IoFreeMdl(mdl); is the counterpart of IoAllocateMdl . Furthermore , the documentation of MmAllocatePagesForMdl says to call ExFreePool to release the MDL structure itself. Regards , Christiaan ----- Original Message ----- From: <xxxxx@osr.com> To: "Windows System Software Devs Interest List" <xxxxx@lists.osr.com> Sent: Thursday, June 18, 2009 10:10 PM Subject: RE:[ntdev] MmAllocatePagesForMdl() cleanup >I hate to say this (because it won't be much help), but your code looks OK to me. You reverse the call th MapPages with a call to >UnMap pages. Then you reverse the call AllocatePagesForMdl with FreePagesFromMdl. You ARE taking that path in your >"UnmapUserBuffer" function, right? You're not passing in NULL for the Mdl?? > > The only problem I've ever seen is trying to do the unmap operation in Close instead of in Cleanup. > > Aside from that... > > Peter <...excess quoted lines suppressed...>
  Message 12 of 15  
18 Jun 09 16:31
Jason Summerour
xxxxxx@gmail.com
Join Date: 11 Jul 2007
Posts To This List: 114
RE: MmAllocatePagesForMdl() cleanup

So, for anyone else mapping shared memory between userland and a kmdf driver, here's my *working* code... // Allocate and initialize an MDL describing the dma common buffer memory // and map the memory to user space. NTSTATUS CreateAndMapUserBuffer(PVOID &uvAddr, PMDL &mdl, PVOID &kvAddr, size_t size, HANDLE pid) { PHYSICAL_ADDRESS lowAddr; PHYSICAL_ADDRESS highAddr; size_t allocated; // Set max/min physical memory addresses: lowAddr.QuadPart = 0; highAddr.QuadPart = _4G; // We're going to have to create an MDL for each frame!!! // This is zero filled, non-paged main memory pages: mdl = MmAllocatePagesForMdl(lowAddr, highAddr, lowAddr, size); if (!mdl) { DbgPrint("MmAllocatePagesForMdl() failed\n"); return STATUS_INSUFFICIENT_RESOURCES; } // Check to see how much memory was actually allocated to the mdl, versus requested: allocated = MmGetMdlByteCount(mdl); if (allocated < size) { DbgPrint("MmAllocatePagesForMdl() allocated less memory than we requested: req: 0x%08x allocated: 0x%08x\n", size, allocated); return STATUS_INSUFFICIENT_RESOURCES; } DbgPrint("MmAllocatePagesForMdl(): requested: 0x%08x allocated: 0x%08x\n", size, allocated); // Get Kernel Virtual Address: // returns a nonpaged system-space virtual address for the buffer described by the mdl, // which can be used across any process contexts, and at any IRQL: // MmGetSystemAddressForMdl(Safe)(...) takes a buffer described by an MDL and // maps it into the high 2GB of kernel virtual addressing space. If the MDL // was built CORRECTLY, and the kernel virtual address that represents the data // buffer is in the high 2GB of kernel virtual address space, then the return // from these two functions will indeed be the same. kvAddr = MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority); if (!kvAddr) { DbgPrint("Unable to get nonpaged kernel virtual address\n"); return STATUS_INSUFFICIENT_RESOURCES; } // Maps the physical pages that are described by the MDL and // specify the cache attribute that is used to create the mapping: // It returns the user virtual address of the memory: uvAddr = MmMapLockedPagesSpecifyCache(mdl, UserMode, // access mode MmCached, // v-to-p addr xlations cached NULL, // let system choose base addr FALSE, // no bug check on failure NormalPagePriority); if (!uvAddr) { DbgPrint("MmMapLockedPagesSpecifyCache()unable to map user address\n"); MmFreePagesFromMdl(mdl); IoFreeMdl(mdl); return STATUS_INSUFFICIENT_RESOURCES; } return STATUS_SUCCESS; } NTSTATUS UnmapUserBuffer(PMDL mdl, PVOID userVa, PVOID kernelVa) { // Clean up userland memory: if (mdl) { MmUnmapLockedPages(userVa, mdl); MmUnmapLockedPages(kernelVa, mdl); MmFreePagesFromMdl(mdl); IoFreeMdl(mdl); } else { return STATUS_UNSUCCESSFUL; } return STATUS_SUCCESS; }
  Message 13 of 15  
18 Jun 09 16:40
Scott Noone
xxxxxx@osr.com
Join Date:
Posts To This List: 557
List Moderator
Re: MmAllocatePagesForMdl() cleanup

That's right, good catch. It probably just works by accident (IoFreeMdl either calls ExFreePool or returns the MDL to a lookaside list). -scott -- Scott Noone Consulting Associate OSR Open Systems Resources, Inc. http://www.osronline.com "Christiaan Ghijselinck" <xxxxx@CompaqNet.be> wrote in message news:125998@ntdev... > > Is it correct to call IoFreeMdl(mdl); after calling > MmFreePagesFromMdl(mdl); ? As far as I know , IoFreeMdl(mdl); is the > counterpart of IoAllocateMdl . Furthermore , the documentation of > MmAllocatePagesForMdl says to call ExFreePool to release the MDL > structure itself. > > Regards , > > Christiaan <...excess quoted lines suppressed...>
  Message 14 of 15  
19 Jun 09 05:23
Paul Durrant
xxxxxx@gmail.com
Join Date: 19 May 2009
Posts To This List: 17
Re: MmAllocatePagesForMdl() cleanup

Scott Noone wrote: > Aha! So *you're* the one with the system PTE leak :) > > You need to unmap you system virtual address also. > Is that true? Do you really need to unmap a kva that was attained using MmGetSystemAddressForMdlSafe()? There's nothing I can find in the documentation that suggests you need to do this. Paul -- =================================== Paul Durrant http://www.linkedin.com/in/pdurrant ===================================
  Message 15 of 15  
19 Jun 09 09:06
Scott Noone
xxxxxx@osr.com
Join Date:
Posts To This List: 557
List Moderator
Re: MmAllocatePagesForMdl() cleanup

> Is that true? Do you really need to unmap a kva that was attained using > MmGetSystemAddressForMdlSafe()? With one exception (an MDL built with MmBuildMdlForNonPagedPool), yes, the MDL needs to be unmapped. See the macro definition: #define MmGetSystemAddressForMdlSafe(MDL, PRIORITY) \ (((MDL)->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA | \ MDL_SOURCE_IS_NONPAGED_POOL)) ? \ ((MDL)->MappedSystemVa) : \ (MmMapLockedPagesSpecifyCache((MDL), \ KernelMode, \ MmCached, \ NULL, \ FALSE, \ (PRIORITY)))) And cross reference that with the docs for MmMapLockedPagesSpecifyCache. (Also note that the unmap is done for you in MmUnlockPages, so lots of drivers do it indirectly) -scott -- Scott Noone Consulting Associate OSR Open Systems Resources, Inc. http://www.osronline.com "Paul Durrant" <xxxxx@gmail.com> wrote in message news:126014@ntdev... > Scott Noone wrote: >> Aha! So *you're* the one with the system PTE leak :) >> >> You need to unmap you system virtual address also. >> > > Is that true? Do you really need to unmap a kva that was attained using > MmGetSystemAddressForMdlSafe()? There's nothing I can find in the > documentation that suggests you need to do this. > <...excess quoted lines suppressed...>
Posting Rules  
You may not post new threads
You may not post replies
You may not post attachments
You must login to OSR Online AND be a member of the ntdev list to be able to post.

All times are GMT -5. The time now is 13:43.


Copyright ©2005, OSR Open Systems Resourcs, Inc.
Based on vBulletin Copyright ©2000 - 2005, Jelsoft Enterprises Ltd.
Modified under license