对MDL(Memory Descriptor List)的初步学习

本文介绍了MDL(Memory Descriptor List)的用途和结构,重点讲解了如何通过MDL进行内核态与用户态之间的内存映射,包括内核态分配空间用户态去映射和用户态分配空间内核态去映射两种场景,涉及到的关键步骤如IoAllocateMdl、MmBuildMdlForNonPagedPool、MmProbeAndLockPages以及MmMapLockedPagesSpecifyCache等。
摘要由CSDN通过智能技术生成

首先查阅CSDN,在其中有这样的定义:
内存描述符列表 (MDL) 是一个系统定义的结构,通过一系列物理地址描述缓冲区。执行直接 I/O 的驱动程序从 I/O 管理器接收一个 MDL 的指针,并通过 MDL 读写数据。一些驱动程序在执行直接 I/O 来满足设备 I/O 控制请求时也使用 MDL。

MDL分为两部分:固定长部分和变长部分,固定长部分结构如下:
在这里插入图片描述

    Next:MDL可以连接成一个单链表,因此可以将分散的虚拟机地址串接起来
    Size:整个MDL列表的长度,MDL只是整个列表的头部,后面跟着一块内存,整个MDL列表则是对于一个缓冲区页面的描述。
    MdlFlags:很重要的字段,用于描述和操控虚拟地址的各种属性,指明Mdl的映射方式。
    Process:如果虚拟地址是某一进程的用户地址空间,那么MDL代表的这块虚拟地址必须是从属于某一个进程,这个成员指向从属进程的结构
    MappedSystemVa:该MDL结构对应的物理页面可能被映射到内核地址空间,这个成员代表这个内核地址空间下的虚拟地址。对MmBuildMdlForNonPagedPool的逆向表明,MappedSystemVa = StartVa +ByteOffset。这是因为这个函数的输入MDL,其StartVa是由ExAllocatePoolWithTag决定的,所以已经从内核空间到物理页面建立了映射,MappedSystemVa自然就可以这样算。 可以猜测,如果是调用MmProbeAndLockPages 返回,则MappedSystemVa不会与StartVa有这样的对应关系,因为此时对应的物理页面还没有被映射到内核空间。(此处未定,MmProbeAndLockPages 是否会到PDE与PTE中建立映射,未知。)
    StartVa:虚拟地址空间的首地址,当这块虚拟地址描述的是一个用户进程地址空间的一块时,这个地址从属于某一个进程。(页对齐)
    ByteCount:虚拟地址块的大小,字节数
    ByteOffset:业内的偏移StartVa+ByteCount等于缓冲区的开始地址

经过整理学习,我简单地理解为MDL是用来建立一块虚拟地址空间与物理页面之间的映射,当Driver要存取某段内存位置时,确保MDL所描述的内存位置不会引起缺页错误。

虚拟地址在mdl中可以通过一个宏获得,物理地址的页帧存放在紧接着mdl的内存当中(MDL是一个变长结构,在MDL头后的一个数组才是真正存放着物理地址的地方,这个可以通过(PPFN_NUMBER) (Mdl + 1)得到物理页帧)。
需要特别注意的:MDL只能在内核态使用,但它指定的虚拟内存即可以是内核态地址也可以是用户态地址。

它可以被用来解决一些问题,最常见的是:
《内核情景分析》一书中给出了具体的问题说明和原因,总结如下:
在这里插入图片描述
解决方案:
比较常用的做法是通过MDL进行内存的重映射。简单地说就是将同一块物理内存同时映射到用户态空间和内核态空间:
示意图如下:
在这里插入图片描述
临时为用户空间增添一个系统空间映射,通过以物理页面就有了俩个虚拟地址区间,其一就是原来的用户空间虚拟地址区间,其二则是系统空间的虚拟地址区间。通过系统空间的虚拟地址访问用户空间缓冲区,完成操作后撤销系统空间的映射。
注意:直接方法对于很小的缓冲区是不划算的,因为临时映射的建立和撤销需要一定的开销,对于大一点的缓冲区才合适。
因为有俩个虚拟地址空间,所以也就有了俩种情况。

1.内核态分配空间,用户态进程去映射。
2.用户态进程分配空间,内核态去映射

一、内核态分配空间,用户态进程去映射

(1)、非分页内存

	WCHAR* v1 = L"HelloWorld";
	WCHAR* BufferData = ExAllocatePool(NonPagedPool, sizeof(WCHAR)*BufferLength);
	memcpy(BufferData, v1, 20);

先申请一块内存,这里我们先以“非分页”为例。长度为20,拷贝数据“HelloWorld”,如下图,我们可以看到我们申请内存在内核空间和里面的数据。
在这里插入图片描述

/*申请mdl*/
		Mdl = IoAllocateMdl(BufferData, BufferLength, FALSE,
  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值