> I think I just need some pointers on how to re-align my thinking since I am
in the
Windows world. Can these DMA API’s good actually alleviate the need for
obtaining contiguous memory?
Usual NT kernel/WDM (not KMDF) has the 2 sets of DMA APIs: common-buffer and
MDL-based.
Common-buffer APIs allows you to allocate the DMA-safe kernel nonpaged memory.
The memory is contiguous both virtual address side and DMA side, you get the
starting DMA address for it, and the PVOID to it.
MDL-based APIs allow you to run the DMA over the user app’s buffer directly.
Some words about MDLs.
In Windows kernel, MDL is the buffer descriptor which describes the buffer in
terms of the underlying physical pages. Its structure is “struct _MDL”,
followed by the array of physical page numbers.
To create a MDL, one of the following (I simplify a bit) can be used:
-
IoAllocateMdl+MmProbeAndLockPages, to create a MDL around user or kernel
paged buffer. MmProbeAndLockPages can fail by throwing a __try/__except
exception. It actually locks the physical pages in memory, and puts their page
numbers to the array at MDL’s tail. MmUnlockPages+IoFreeMdl is the undo.
-
IoAllocateMdl+MmBuildMdlForNonPagedPool, to create a MDL around the kernel
nonpaged memory. It cannot fail, and has the simple IoFreeMdl as undo.
-
IoAllocateMdl+IoBuildPartialMdl, to create a sub-MDL over existing parent
MDL. NOTE: you must guarantee that you destroy the sub-MDL before the parent
MDL can be destroyed, violation of this rule gives you PFN_LIST_CORRUPT BSOD.
How can you use a MDL?
- As a parent MDL in IoBuildPartialMdl
- Map these pages to kernel addresses available from any context (ISRs
included) by MmGetSystemAddressForMdlSafe. This is usually used for ISR-driven
PIO hardware.
- Use it for DMA.
Also note that, for DO_DIRECT_IO devices, the Io manager automatically does
IoAllocateMdl+MmProbeAndLockPages around the app’s buffer and sends this MDL to
you as Irp->MdlAddress. So is done in METHOD_xxx_DIRECT IOCTLs.
So, Irp->MdlAddress is a MDL pre-built by Io and describing the app’s buffer it
passed to Read/WriteFile.
Now the MDL-based DMA itself. These routines translate the MDL, actually its
tail with physical page numbers, to a scatter-gather list - a list of
(StartDmaAddress, ByteLength) pairs. You can then send this list to your
hardware if you need so.
MDL-based DMA API has 2 APIs actually: old and new. The old is
AllocateAdapterChannel (allocates the necessary resources for MDL -> SGL
mapping) and MapTransfer (each next MapTransfer call returns you 1 next SGL
element - PhysicalAddress and length). FlushAdapterBuffers is the undo.
The new API is GetScatterGatherList and BuildScatterGatherList. They return you
the fully built SGL as a single entity in a single call.
You can use any of these APIs in your driver. Note that all of them need
IoGetDmaAdapter first.
As about Linux - I remember seeing “struct kiobuf” in some Linux kernel
sources, which was IIRC the same as MDL in Windows.
–
Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com