IoAllocateMdl

来源:互联网 发布:软件技术学校 编辑:程序博客网 时间:2024/05/17 04:04
PMDLIoAllocateMdl(    IN PVOID VirtualAddress,    IN ULONG Length,    IN BOOLEAN SecondaryBuffer,    IN BOOLEAN ChargeQuota,    IN OUT PIRP Irp OPTIONAL    )/*++Routine Description:分配一块内存描述符,由参数VirtualAddress和Length指定了MDL需要映射的大小。如果参数指定了一个IRP,那么将以合适的方式把该MDL挂接到IRP中。    如果例程没有指定IRP参数,那么由调用者负责设定需要申请MDL的IRP的MDL地址    如果没有指定一个IRP,由调用者负责将他写入为之申请的IRP中(如果需要)。    注意MDL的头部信息在调用成功后也会被初始化。Arguments:    VirtualAddress - 将要映射的起始虚拟地址。    Length - 虚拟地址空间需要映射的长度,以字节为单位。    SecondaryBuffer - 此参数仅当指定了IRP时有效。如果SecondaryBuffer为TRUE,那么将链接MDL到IRP的MDL链表中(通过MDL->next),否则将申请到的MDL替换掉原来IRP的MDL(替换Irp->MdlAddress)    ChargeQuota - 指定MDL的配额控制。注意,在WRK1.2中此参数被忽略。    Irp - 指定MDL服务的IRP,为可选的参数。Return Value:    返回申请的MDL,创建MDL失败返回NULL。如果是因为配额导致的MDL创建失败,由调用者负责捕捉这个异常。--*/{    ULONG allocateSize;    USHORT fixedSize;    PMDL mdl;    ULONG size;    PMDL tmpMdlPtr;    ASSERT(Length);//在WRK1.2中配额参数被忽略。    UNREFERENCED_PARAMETER (ChargeQuota);    //    // 如果请求映射的长度超过2Gb,我们无法映射这个内存。因此请求失败。    //    if (Length & 0x80000000) {        return NULL;    }    //    // 从lookaside列表或者是内存池分配一个Allocate。    //    mdl = NULL;    fixedSize = 0;//计算需要的页面数量    size = ADDRESS_AND_SIZE_TO_SPAN_PAGES(VirtualAddress, Length);//1.如果需要的页面数大于IOP_FIXED_SIZE_MDL_PFNS(0x17)那么计算需要申请的内存大小。并且从全局内存池中申请。//2.否则从LookasideList列表中申请一块MDL内存,在LookasideMdlList中申请的页面数是个固定大小IOP_FIXED_SIZE_MDL_PFNS(0x17)。及时需要的PFN数量<IOP_FIXED_SIZE_MDL_PFNS//  如果从LookasideList列表中申请失败,最后还是从内存池中分配内存。    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;        }    }    //    // 填充MDL的头部。如果是固定大小(从LookasideList中分配内存)设置标志位MDL_ALLOCATED_FIXED_SIZE。    //    MmInitializeMdl(mdl, VirtualAddress, Length);    mdl->MdlFlags |= (fixedSize);    //    // 最后,如果指定了一个IRP参数,那么将MDL填入到MDL中。    // 填充方式基于SecondaryBuffer的设定,如果为TRUE,挂入到IRP的MDL链表中。如果为FALSE,直接替换IRP->MdlAddress.    //    if (Irp) {        if (!SecondaryBuffer) {            Irp->MdlAddress = mdl;        } else {            tmpMdlPtr = Irp->MdlAddress;            while (tmpMdlPtr->Next != NULL) {                tmpMdlPtr = tmpMdlPtr->Next;            }            tmpMdlPtr->Next = mdl;        }    }    return mdl;}

0 0
原创粉丝点击