none
How do I know if my data buffer comes from non-paged pool? (Mdl allocation) RRS feed

  • Question

  • Hi,

    A year and a half ago I developed a device driver for some acquisition card we have in my research group, and so far it has been working without troubles. But recently, someone complained about problems and I am trying to see if it could come from my driver or not...

    Inside my driver, I do the following to allocate an mdl after an I/O call:

    mdl = IoAllocateMdl(pDevContext->BufferAddress,
    			pDevContext->MemLength,
    			FALSE,
    			FALSE,
    			NULL);
    
    if(!mdl) {
    		return STATUS_INSUFFICIENT_RESOURCES;
    		KdPrint(("IoAllocateMdl failed 0x%x\n", status));
        }
    
    // Save the Mdl for later de-allocation
    pDevContext->MemoryMDL = mdl;
    
    // Build Mdl to describe memory pages
    MmBuildMdlForNonPagedPool(mdl);
    
    // Map the buffer into user space
    __try
    {
    	pDevContext->UserVirtualAddress = (PUCHAR) MmMapLockedPagesSpecifyCache(mdl, // MDL
    										UserMode,     // Mode
    										MmNonCached,  // Caching
    										NULL,         // Address
    										FALSE,        // Bugcheck?
    										NormalPagePriority); // Priority
    
    	// If we get NULL back, the request didn't work.
    	if(!(pDevContext->UserVirtualAddress))  {
    		MmFreePagesFromMdl(mdl);        
    		IoFreeMdl(mdl);
    		return STATUS_INSUFFICIENT_RESOURCES;
    		KdPrint(("MmMapLockedPagesSpecifyCache failed 0x%x\n", status));
    	}
    
    	pDevContext->MemoryIsUserMapped = TRUE;
    		
    	KdPrint(("UserVA = 0x%0x\n", pDevContext->UserVirtualAddress));
    	KdPrint(("Leaving LMBufferCreateAndMapMemory.\n"));
    
    	return STATUS_SUCCESS;
    	}
    
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
    	pDevContext->UserVirtualAddress = 0x0; 
    	KdPrint (("MmMapLockedPagesSpecifyCache caused exception: %x\n",GetExceptionCode()));
    	KdPrint(("Leaving LMBufferCreateAndMapMemory.\n"));
    
    	return STATUS_UNSUCCESSFUL;
    }
    
    pDevContext->MemoryIsUserMapped = TRUE;
    		
    KdPrint(("UserVA = 0x%0x\n", pDevContext->UserVirtualAddress));
    KdPrint(("Leaving LMBufferCreateAndMapMemory.\n"));
    
    return STATUS_SUCCESS;
    
    

    And then later, when I want to unmap:

    // Make sure we have an MDL to free.
    if(!(pDevContext->MemoryMDL)) {
    	KdPrint(("LMBufferUnMapAndFreeMemory : there was no mdl to free"));
    	return STATUS_SUCCESS;
    }
    	
    // Release the MDL.
    KdPrint(("Release MDL.\n"));
    IoFreeMdl(pDevContext->MemoryMDL);
    
    // Set the mapping bool to FALSE
    KdPrint(("Reset the bool.\n"));
    pDevContext->MemoryIsUserMapped = FALSE;
    
    return STATUS_SUCCESS;

    Please note that I tested these functions, and did not have problems with mapping/unmapping memory, accessing the buffers, reading and writing to the buffers... etc.

    But now, a year and a half and a few gray hair later, I am wondering if I did things correctly, and what I did not test. Here are a few concerns:

    1. I used MmBuildMdlForNonPagedPool , and I don't remember why. But what if my buffer data comes from a paged-pool? Wouldn't that lead to some errors? How can I know if my buffer comes from a paged pool or not?

    2. What did I not test in read and write or allocate/deallocate that could potentially lead to some errors?

    3. The person who complained about errors said "I can still read from the acquisition card, even after I call the routine that supposedly closes communication" (that is: my IoFreeMdl). Am I not de-allocating it properly?

    Thank you to anyone who could help me, I am in big doubts now!

    Wednesday, February 19, 2014 7:15 PM

Answers

  • Yes you don't want to free the pages with MmFreePagesFromMdl you need to free them with ExFreePool.


    Don Burn Windows Filesystem and Driver Consulting Website: http://www.windrvr.com Blog: http://msmvps.com/blogs/WinDrvr

    Friday, February 21, 2014 12:03 AM

All replies

  • The code you have for the MDL is typically for one where you allocate the buffer, so you should know whether it is non-paged pool or not.  Of course why you would map a buffer into user space for each I/O request is another mystery since this is a high overhead operation, and when people map memory to user space they normally do it at the IRP_MJ_CREATE time (or shortly thereafter).

    We would need to understand more how the driver works, but I suspect there are a number of problems in the driver.


    Don Burn Windows Filesystem and Driver Consulting Website: http://www.windrvr.com Blog: http://msmvps.com/blogs/WinDrvr

    Wednesday, February 19, 2014 7:30 PM
  • Hi Don,

    Thank you for your reply.

    Indeed, I allocate the buffer earlier using MmMapIoSpace, I still don't know if it is pooled or not.

    I map a buffer into user space only once, not every time there is an I/O request. Actually, my only I/O requests are map or unmap. I read and write directly into the the mapped buffer.
    The flow goes like this: 1. application is launched => I/O request to map, 2. bunch of acquisitions that read the buffer, 3. application is closed => I/O request to unmap. 

    I honestly do not know why it was made to be this way: I did not design the hardware, and I certainly did not design the driver (as a matter of fact, I looked at the old driver that was made 15 yrs ago and re-wrote it so we could use it in newer systems.).
    Full disclaimer: I am not a driver developer or even a software engineer ;-)

    Anyway, thanks for the help. I would post the entire driver code if you wanted it.

    Wednesday, February 19, 2014 8:58 PM
  • Ok,  understanding the model now, I looked at more detail.  Are you calling MmUnmapLockedPages before you call IoFreeMdl?  If you are not, the memory will still be mapped to the user process.


    Don Burn Windows Filesystem and Driver Consulting Website: http://www.windrvr.com Blog: http://msmvps.com/blogs/WinDrvr

    Wednesday, February 19, 2014 9:06 PM
  • No, I do not call MmUnmapLockedPages, I thought I did not have to do anything because I called MmBuildMdlForNonPagedPool.

    I guess I mis-understood this. I will try adding a call to MmUnmapLockedPages. Thank you.
    Do you think I should also replace MmBuildMdlForNonPagedPool by a MmProbeAndLockPages?

    Thanks again.

    Wednesday, February 19, 2014 10:16 PM
  • No you should not need to replace MmBuildMdlForNonPagedPool, it is appropriate for what you are doing.


    Don Burn Windows Filesystem and Driver Consulting Website: http://www.windrvr.com Blog: http://msmvps.com/blogs/WinDrvr

    Wednesday, February 19, 2014 10:34 PM
  • I'm curious if this worked.  I was also going to comment you may want to add code to your driver so that is the handle that issued the map pages is closed, the call to unmap pages is done automatically.

    When I have done mapping into user space, I typically set things up so the create of the handle does the mapping and the close does unmap.


    Don Burn Windows Filesystem and Driver Consulting Website: http://www.windrvr.com Blog: http://msmvps.com/blogs/WinDrvr

    Thursday, February 20, 2014 7:01 PM
  • Hi Don,

    I finally got to compile and test my driver, and I have another question for you:

    I now do the unmapping using the following:

    MmUnmapLockedPages(pDevContext->UserVirtualAddress,
    		   pDevContext->MemoryMDL);
    IoFreeMdl(pDevContext->MemoryMDL);
    This seems to work. I will have to investigate a bit further though, to make sure the problem that was raised does not happen again.

    Out of curiosity, I went back to the OSR paper I read about this when working on the driver, and the cleanup method suggested in it was the following:

    void UnMapAndFreeMemory(PMDL PMdl,PVOID UserVa)
    {
     //
     // Make sure we have an MDL to free
    //
     if(!PMdl) {
      return;
     }
     
     //
     // Return the allocated resources.
     //
     MmUnmapLockedPages(UserVa, PMdl);
     
     MmFreePagesFromMdl(PMdl);       
     IoFreeMdl(PMdl);
     
     
    }

    I tried this also, however I got a BSOD with "memory_management" error. I wonder if the MmFreePagesFromMdl should not be called in my case?

    When I do the mapping, I call it in case the MmMapLockedPagesSpecifyCache routine is not successful... should I change that so that no-one gets a BSOD from my driver ever?

    Thanks for your help, I really appreciate it. If you send me your physical address I will mail you a box of chocolates.

    Friday, February 21, 2014 12:01 AM
  • Yes you don't want to free the pages with MmFreePagesFromMdl you need to free them with ExFreePool.


    Don Burn Windows Filesystem and Driver Consulting Website: http://www.windrvr.com Blog: http://msmvps.com/blogs/WinDrvr

    Friday, February 21, 2014 12:03 AM