Using Memory Buffers
Drivers typically use memory buffers to pass data to and from the framework and other drivers or to store information locally. This topic describes framework memory objects, lookaside lists, MDLs, and local buffers.
Using Framework Memory Objects
The framework uses memory objects to describe the memory buffers that a driver receives from and passes to the framework. Each framework memory object represents one buffer.
To create a memory object, your driver calls one of the following object methods:
WdfMemoryCreate, which creates a memory object and allocates a memory buffer of a specified size.
WdfMemoryCreatePreallocated, which creates a memory object for a preallocated buffer.
To obtain a memory object that represents a received I/O request's buffers, your driver calls WdfRequestRetrieveInputMemory and WdfRequestRetrieveOutputMemory. For more information about retrieving an I/O request's buffers, see Accessing Data Buffers in Framework-Based Drivers.
To obtain the address and size of a memory object's buffer, your driver calls WdfMemoryGetBuffer.
To move data into or out of a memory object's buffer, your driver calls either WdfMemoryCopyFromBuffer or WdfMemoryCopyToBuffer. These object methods check the source and destination sizes and prevent buffer overrun errors.
When a driver sends an I/O request to an I/O target, it typically passes an input or output buffer to a framework I/O target object method. The driver specifies the buffer by either passing a WDF_MEMORY_DESCRIPTOR structure that describes the buffer or by passing a memory object handle. (I/O target object methods that send I/O requests synchronously require a WDF_MEMORY_DESCRIPTOR structure, and methods that send I/O requests asynchronously require a memory object handle.)
For information about when a memory buffer is valid, see Memory Buffer Life Cycle.
Using Lookaside Lists
If your driver will require many buffers of approximately the same size, it should allocate them from a lookaside list. The driver creates a lookaside list by calling WdfLookasideListCreate. Subsequently, the driver can obtain buffers from the lookaside list by calling WdfMemoryCreateFromLookaside.
Each time the driver calls WdfMemoryCreateFromLookaside, the framework creates a memory object, obtains a buffer from the lookaside list, and assigns the buffer to the object. When the driver has finished using one of these memory objects it calls WdfObjectDelete, which deletes the memory object and returns the buffer space to the lookaside list.
The operating system manages the memory resources that are assigned to the lookaside list. If the driver requests a buffer from the lookaside list when none are available, such as the first time that the driver calls WdfMemoryCreateFromLookaside, the system allocates a buffer and assigns it to the list. When the driver calls WdfObjectDelete (and the buffer space is returned to the lookaside list), the system keeps the now unassigned buffer in the list until the driver needs it again. The system increases the list's size as necessary; for example, drivers that more frequently request buffers receive larger lookaside lists. On the other hand, the system might reduce the number of buffers in the list if the driver is not using them all.
Some drivers use memory descriptor lists (MDLs) to describe buffers. For example, a driver for a direct memory access (DMA) device must pass a MDL to the WdfDmaTransactionInitialize method, if it calls that method.
Most framework-based drivers do not use MDLs.
Allocating Local Buffers
A driver that requires local, internal buffer space that it will not pass to the framework does not have to create memory objects to represent the buffers. The driver can call ExAllocatePoolWithTag to allocate internal buffers. When the driver has finished using the buffer, it must call ExFreePoolWithTag.
However, drivers can also use memory objects for local buffers. An advantage to using memory buffers, instead of calling ExAllocatePoolWithTag, is that the framework automatically deletes memory objects and their buffers when each object's parent object is deleted.
Your driver can use the WDF_ALIGN_SIZE_UP or WDF_ALIGN_SIZE_DOWN function to calculate a buffer size that is aligned to a specified alignment offset. This calculation is useful if your driver must allocate multiple contiguous buffers, if each buffer must begin at an address alignment boundary.