Memory Allocation


WDF drivers use and allocate memory as a general resource and in several specific ways:

  • For local storage

  • As WDF memory objects

This section provides basic information about allocating memory for local storage and about creating and allocating buffers and memory objects.

Local Storage

In some situations, a driver requires local storage that is not associated with an I/O request or that must be passed outside the framework to another component.

 UMDF  Depending on the type of required storage, UMDF drivers can use new, malloc, and other Windows user-mode and language-specific allocation techniques.

 KMDF   KMDF drivers use Windows kernel-mode DDIs, typically ExAllocatePoolWithTag, to allocate memory that is not part of a WDF memory object. For example, the following sample drivers use ExAllocatePoolWithTag:

  • The Firefly sample allocates a buffer to send down its device stack in a synchronous IOCTL.

    In a synchronous request, the use of a WDF memory object incurs additional overhead without any benefit. The driver waits for the request to complete, so the memory is unlikely to be freed at the wrong time.

  • The Featured Toaster sample allocates memory to use in calls to IoWmiXxx functions.

    In this case, the IoWmiXxx functions free the memory on behalf of the caller. WDF drivers must not use WDF memory objects in calls to IoWmiXxx functions because such functions cannot free the memory objects.

  • The KMDF 1394 sample driver allocates memory for control blocks that it sends to its bus driver.

    The bus driver expects parameters packaged in an IEEE 1394 I/O request block.

ExAllocatePoolWithTag can allocate either paged or nonpaged pool. The framework does not track references on memory that system functions allocate, so the driver must call ExFreePoolWithTag before it unloads to free any memory that ExAllocatePoolWithTag allocated.

The Pooltag.txt file lists the pool tags that are used by kernel-mode components and drivers supplied with Windows, along with the associated file or component, and the name of the component. Pooltag.txt is installed with Debugging Tools for Windows (in %windbg%\triage) and with the WDK (in %wdk%\tools\other\platform\poolmon, where platform is amd64, i386, or ia64).

 Tip   See "Allocating System-Space Memory" in the WDK for general information on ExAllocatePoolWithTag and other WDM memory allocation functions-online at http://go.microsoft.com/fwlink/?LinkId=81580.

Memory Objects and I/O Buffers

A WDF memory object is a reference-counted object that describes a buffer. When the framework passes an I/O request to a driver, the request contains WDF memory objects that describe the buffers in which the driver receives and returns data.

WDF memory objects are not limited to use in I/O requests. A driver can also use a WDF memory object internally for other purposes, such as an internal buffer that is shared among several driver functions. The reference count decreases the chance that a driver will inadvertently free the memory at the wrong time or try to access memory that has already been freed. By default, the parent of a driver-created memory object is the driver itself, so by default the memory object persists until the driver is unloaded.

Each memory object contains the length of the buffer that it represents. WDF methods that copy data to and from the buffer validate the length of every transfer to prevent buffer overruns and underruns, which can result in corrupt data or security breaches.

Chapter 8, "I/O Flow and Dispatching," and Chapter 9, "I/O Targets," provide more information about using memory objects and buffers in I/O requests and include details about the lifetimes of buffers and memory objects.

UMDF Memory Objects and Interfaces

The methods that a UMDF driver calls to create a memory object and associated buffer are the same regardless of how the driver uses the memory object. Typically, the driver simultaneously allocates the buffer and creates the memory object by calling IWDFDriver::CreateWdfMemory so that the lifetime of the object and the buffer are the same. If the buffer requires a longer lifetime than the memory object, the driver should instead use the IWDFDriver::CreatePreallocatedWdfMemory method.

Chapter 9, "I/O Targets," describes additional creation and lifetime scenarios.

The driver uses the IWDFMemory methods to manipulate a memory object and access the underlying buffer. Table 12-1 summarizes these methods.

Table 12-1: IWDFMemory Methods
Open table as spreadsheet

Method

Description

CopyFromBuffer

Copies data from a source buffer to a memory object.

CopyFromMemory

Copies data from one memory object to another memory object and prevents overruns that the copy operation might otherwise cause.

CopyToBuffer

Copies data from a memory object to a buffer.

GetDataBuffer

Retrieves the data buffer that is associated with a memory object.

GetSize

Retrieves the length of the data buffer that is associated with a memory object.

SetBuffer

Assigns a buffer to a memory object that a driver created by calling IWDFDriver::CreatePreallocatedWdfMemory.

The IWDFIoRequest interface includes methods with which a driver can retrieve a memory object that is embedded in an I/O request.

Chapter 8, "I/O Flow and Dispatching," contains more information about these methods.

KMDF Memory Objects and Methods

A KMDF driver can simultaneously allocate a buffer and create a memory object by calling WdfMemoryCreate. If the driver often uses buffers of the same size, it can create a lookaside list that contains buffers of the required size and then call WdfMemoryCreateFromLookaside to assign a buffer from the list to a new memory object.

The framework defines WdfMemoryXxx methods to manipulate WDF memory objects and to read and write their buffers. These methods take a handle to a memory object and transfer data between the memory object's buffer and an external buffer. Table 12-2 summarizes these methods.

Table 12-2: KMDF Memory Object Methods
Open table as spreadsheet

Method

Description

WdfMemoryAssignBuffer

Assigns a specified buffer to a memory object that a driver created.

WdfMemoryCopyFromBuffer

Copies data from a source buffer into a memory object's buffer.

WdfMemoryCopyToBuffer

Copies data from a memory object's buffer into a different buffer.

WdfMemoryCreate

Creates a WDFMEMORY object and allocates a memory buffer of a specified size.

WdfMemoryCreateFromLookaside

Creates a WDFMEMORY object and gets a memory buffer from a lookaside list.

WdfMemoryCreatePreallocated

Creates a WDFMEMORY object and assigns it an existing, driver-supplied buffer.

WdfMemoryGetBuffer

Returns a pointer to the buffer that is associated with a memory object.

Each I/O request that the framework dispatches to a KMDF driver contains one or more WDFMEMORY objects. A driver can use the WdfRequestRetrieveXxx methods that return the memory objects and buffers from an I/O request.

KMDF Lookaside Lists

Lookaside lists are lists of fixed-size, reusable buffers that are designed for structures that a driver allocates dynamically and frequently. A lookaside list is useful whenever a driver needs fixed-size buffers and is especially appropriate for commonly used and reused structures. For example, the Windows I/O manager allocates its own IRPs from a lookaside list.

The driver defines the size of the buffers, and the system maintains the status of the list and adjusts the number of available buffers according to demand. A lookaside list can be allocated from either the paged or the nonpaged pool, according to the driver's requirements. After the list has been initialized, all buffers from the list come from the same pool.

When a driver initializes a lookaside list, Windows creates the list and holds the buffers in reserve for future use by the driver. The number of buffers in the list at any given time depends on the amount of available memory and the size of the buffers. When the driver requires a buffer, it calls the framework to create a memory object from the lookaside list. The memory object encapsulates the buffer and is set as the owner of the buffer so that the buffer's lifetime is the same as that of the memory object. When the memory object is deleted, the buffer is returned to the lookaside list.

Example: Using Lookaside Lists

A KMDF driver creates a lookaside list by using the WdfLookasideListCreate method. By default, the driver object is the parent of a lookaside list. To specify a different parent, the driver sets the ParentObject field in the object attributes structure for the list object. The framework deletes the list when it deletes the parent object. A driver can instead delete the list manually by calling WdfObjectDelete.

Listing 12-1, which is excerpted from the Sys\Pcidrv.c file in the Pcidrv sample, shows how a driver creates a driver-wide lookaside list.

Listing 12-1: Creating a lookaside list

image from book
 status = WdfLookasideListCreate(WDF_NO_OBJECT_ATTRIBUTES,                      sizeof(MP_RFD),                      NonPagedPool,                      WDF_NO_OBJECT_ATTRIBUTES, // MemoryAttributes                      PCIDRV_POOL_TAG,                      &driverContext->RecvLookaside                      ); 
image from book

The Pcidrv sample uses the lookaside list as a source of buffers for receive structures. A single, driver-wide lookaside list serves all of the devices that the driver manages, so the driver creates the list in its DriverEntry function and stores a handle to the returned list in the driver context area. In this example, the list is allocated from nonpaged pool.

Each buffer from the list is sizeof(MP_RFD) bytes long and uses the pool tag that is defined in the PCIDRV_POOL_TAG constant. Using a unique pool tag for your driver-or even for individual modules within your driver-is important because it can help you determine the source of various memory allocations while debugging. WdfLookasideListCreate takes pointers to two object attributes structures as the first and fourth parameters. The first attributes structure describes the attributes of the lookaside list object itself, and the second attributes structure describes the attributes of the WDFMEMORY objects that the driver later allocates from the list. The driver in Listing 12-1 specifies no attributes for either type of object.

To allocate a buffer from the list, the driver calls WdfMemoryCreateFromLookaside. This method returns a WDFMEMORY object, which the driver can use just as it would any other WDFMEMORY object.

In Listing 12-2, the PCIDRV sample allocates a memory object from the lookaside list and then obtains a pointer to the buffer within that object. This example is adapted from the Pcidrv\sys\hw\Nic_init.c file.

Listing 12-2: Allocating memory from a lookaside list

image from book
 NTSTATUS NICInitRecvBuffers(     IN PFDO_DATA      FdoData     ) {     NTSTATUS        status = STATUS_INSUFFICIENT_RESOURCES;     PMP_RFD         pMpRfd;     WDFMEMORY       memoryHdl;     PDRIVER_CONTEXT  driverContext =                      GetDriverContext(WdfGetDriver());     . . . // Code omitted for brevity     status = WdfMemoryCreateFromLookaside(               driverContext->RecvLookaside,               &memoryHdl               );     if(!NT_SUCCESS(status)){         . . . // Error handling code omitted     }      pMpRfd = WdfMemoryGetBuffer(memoryHdl, NULL);     if (!pMpRfd) {         . . . // Error handling code omitted     }     . . . //More code omitted     return; } 
image from book

The sample passes the handle to the lookaside list object that it stored in the driver context area to WdfMemoryCreateFromLookaside, which returns a handle to a WDFMEMORY object in memoryHdl. After checking status, the driver calls WdfMemoryGetBuffer, which returns a pointer to the buffer that is embedded in the memory object. The first parameter is the handle to the memory object, and the second parameter is a location in which to return the length of the buffer. The driver passes NULL for the length because the driver specified the buffer length when it created the lookaside list.

When the driver has finished using the memory object, it must delete the memory object by calling WdfObjectDelete as follows:

 WdfObjectDelete(memoryHdl); 

When the driver deletes the memory object, the framework releases the buffer back to the lookaside list.




Developing Drivers with the Microsoft Windows Driver Foundation
Developing Drivers with the Windows Driver Foundation (Pro Developer)
ISBN: 0735623740
EAN: 2147483647
Year: 2007
Pages: 224

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net