I/O Buffer需要分连续虚拟内存跨越不同的物理页,物理页可能不连续。 就需要MDL结构了。
功能是分配一个MDL内存,根据VirtualAddress和长度。如果是在IRP相关调用的话(IRP非空),则
连接此MDL到IRP的相关结构。具体见如下代码:
ULONG allocateSize;
USHORT fixedSize;
PMDL mdl;
ULONG size;
PMDL tmpMdlPtr;
ASSERT(Length);
//
// If the requested length is greater than 2Gb, then we're not going
// to be able to map the memory, so fail the request.
//
if (Length & 0x80000000) {
return NULL;
}
// Allocate an MDL from the lookaside list or pool as appropriate.
//
mdl = NULL;
fixedSize = 0;
size = ADDRESS_AND_SIZE_TO_SPAN_PAGES(VirtualAddress, Length);
if (size > IOP_FIXED_SIZE_MDL_PFNS) {
allocateSize = sizeof(MDL) + (sizeof(PFN_NUMBER) * size);
if (allocateSize > MAXUSHORT) {
return NULL;
}
} else {
fixedSize = MDL_ALLOCATED_FIXED_SIZE;
allocateSize = sizeof(MDL) + (sizeof(PFN_NUMBER) * IOP_FIXED_SIZE_MDL_PFNS);
mdl = (PMDL)ExAllocateFromPPLookasideList(LookasideMdlList);
}
if (!mdl) {
mdl = ExAllocatePoolWithTag(NonPagedPool, allocateSize, ' ldM');
if (!mdl) {
return NULL;
}
}
//
// Now fill in the header of the MDL.
MmInitializeMdl(mdl, VirtualAddress, Length);
mdl->MdlFlags |= (fixedSize);
//
// Finally, if an IRP was specified, store the address of the MDL
// based on whether or not this is a secondary buffer.
//
if (Irp) {
if (!SecondaryBuffer) {
Irp->MdlAddress = mdl;
} else {
tmpMdlPtr = Irp->MdlAddress;
while (tmpMdlPtr->Next != NULL) {
tmpMdlPtr = tmpMdlPtr->Next;
}
tmpMdlPtr->Next = mdl;
}
}
return mdl;