[Previous] [Next]
When an application initiates a read or write operation, it provides a data buffer by giving the I/O Manager a
Figure 7-2 illustrates the first two
Figure 7-2. Accessing user-mode data buffers.
You specify your device's buffering method for reads and
NTSTATUSAddDevice(...)
{
PDEVICE_OBJECTfdo;
IoCreateDevice(...,&fdo);
fdo->Flags=DO_BUFFERED_IO;
<or>
fdo->Flags=DO_DIRECT_IO;
<or>
fdo->Flags=0;//i.e.,neitherdirectnorbuffered
}
|
You can't change your mind about the buffering method afterward. Filter drivers might copy this flag setting and will have no way to know if you do change your mind and specify a different buffering method.
When the I/O Manager creates an IRP_MJ_READ or IRP_MJ_WRITE request, it inspects the direct and buffered flags to decide how to describe the data buffer in the new I/O request packet (IRP). If DO_BUFFERED_IO is set, the I/O Manager
PVOIDuva;// |
In other words, the system (copy) buffer address is in the IRP's
AssociatedIrp.SystemBuffer
field, and the request length is in the
stack->Parameters
union. This process includes additional details that you and I don't need to know to write drivers. For example, the copy that occurs after a successful read operation actually happens during an asynchronous procedure call (APC) in the original thread context and in a different subroutine than the one that constructs the IRP. The I/O Manager saves the user-mode virtual address (my
uva
variable in the
The I/O Manager also takes care of releasing the free storage obtained for the system copy buffer when something eventually completes the IRP.
If you specified DO_DIRECT_IO in the device object, the I/O Manager creates a MDL to describe locked pages containing the user-mode data buffer. The MDL structure has the following declaration:
typedefstruct_MDL{
struct_MDL*Next;
CSHORTSize;
CSHORTMdlFlags;
struct_EPROCESS*Process;
PVOIDMappedSystemVa;
PVOIDStartVa;
ULONGByteCount;
ULONGByteOffset;
}MDL,*PMDL;
|
Figure 7-3 illustrates the role of the MDL. The
StartVa
member gives the virtual address—valid only in the context of the user-mode process that owns the data—of the buffer.
ByteOffset
is the offset of the beginning of the buffer within a page frame, and
ByteCount
is the size of the buffer in bytes. The
Pages
array, which is not
Figure 7-3. The memory descriptor list structure.
We never, by the way, access
Table 7-2. Macros and support functions for accessing an MDL.
| Macro or Function | Description |
|---|---|
| IoAllocateMdl | Creates an MDL |
| IoBuildPartialMdl | Builds an MDL for a subset of an existing MDL |
| IoFreeMdl | Destroys an MDL |
| MmBuildMdlForNonPagedPool | Modifies an MDL to describe a region of kernel-mode nonpaged memory |
| MmGetMdlByteCount | Determines byte size of buffer |
| MmGetMdlByteOffset | Gets buffer offset within first page |
| MmGetMdlVirtualAddress | Gets virtual address |
| MmGetPhysicalAddress | Gets physical address corresponding to a virtual address within the MDL-described region |
| MmGetSystemAddressForMdl | Creates a kernel-mode virtual address that maps to the same locations in memory |
| MmGetSystemAddressForMdlSafe | Same as MmGetSystemAddressForMdl but preferred in Windows 2000 |
| MmInitializeMdl | (Re)initializes an MDL to describe a given virtual buffer |
| MmPrepareMdlForReuse | Reinitializes an MDL |
| MmProbeAndLockPages | Locks pages after verifying address validity |
| MmSizeOfMdl | Determines how much memory would be needed to create an MDL to describe a given virtual buffer |
| MmUnlockPages | Unlocks the pages for this MDL |
You can imagine the I/O Manager executing code like the following to perform a direct-method read or write:
KPROCESSOR_MODEmode;// |
The I/O Manager first creates an MDL to describe the user buffer. The third argument to IoAllocateMdl (FALSE) indicates this is the primary data buffer. The fourth argument (TRUE) indicates that the Memory Manager should charge the process quota. The last argument ( Irp ) specifies the IRP to which this MDL should be attached. Internally, IoAllocateMdl sets Irp->MdlAddress to the address of the newly created MDL, which is how you find it and how the I/O Manager eventually finds it so as to clean up.
The key event in this code sequence is the call to
MmProbeAndLockPages
, shown in boldface. This function verifies that the data buffer is valid and can be accessed in the appropriate mode. If we're writing to the device, we must be able to read the buffer. If we're reading from the device, we must be able to write to the buffer. In addition, the function locks the physical pages containing the data buffer and fills in the array of page numbers that follows the MDL proper in memory. In effect, a locked page becomes part of the nonpaged pool until as many
The thing you'll most likely do with an MDL in a direct-method read or write is to pass it as an argument to something else. DMA transfers, for example, require an MDL for the MapTransfer step you'll read about later in this chapter in "Performing DMA Transfers." Universal serial bus (USB) reads and writes, to give another example, always work internally with an MDL, so you might as well specify DO_DIRECT_IO and pass the resulting MDLs along to the USB bus driver.
Incidentally, the I/O Manager does save the read or write request length in the stack->Parameters union. It's nonetheless customary for drivers to learn the request length directly from the MDL:
ULONGlength=MmGetMdlByteCount(mdl); |
If you omit both the DO_DIRECT_IO and DO_BUFFERED_IO flags in the device object, you get the neither method by default. The I/O Manager simply gives you a user-mode virtual address and a byte count (as shown in boldface) and
Irp->UserBuffer=uva; PIO_STACK_LOCATIONstack=IoGetNextIrpStackLocation(Irp); if(reading) stack->Parameters.Read.Length=length; else stack->Parameters.Write.Length=length; <codetosendandawaitIRP> |

The Windows 2000 Device Driver Book: A Guide for Programmers (2nd Edition)

Windows System Programming (4th Edition) (Addison-Wesley Microsoft Technology Series)

Developing Drivers with the Windows Driver Foundation (Pro Developer)

Windowsu00ae Internals: Including Windows Server 2008 and Windows Vista, Fifth Edition (Pro Developer)