Email: BuddyZhang1 buddy.zhang@aliyun.com
目录
CMA 多块区域原理
CMA 分配器使用 cma_areas[] 数组维护所有可用的 CMA 区域。CMA 分配器可以 指定驱动使用特定的 CMA 区域。因此本文重点讨论如何在内核中支持 CMA 多 区域以及驱动如何使用特定的 CMA 区域。
CMA 多区域支持原理
内核可以采用多种方案配置一块新的 CMA 区域,这包括了下面三种方法:
每种方案各有利弊,其中 DTS 的方案可以支持多块 CMA 区域的建立,因此可以 采用 DTS 的方案来支持多块 CMA 区域。
驱动使用 CMA 原理
在内核中,每个驱动都是通过设备进行描述,每个设备使用 struct device 数据结构进行描述,其中包含了 cma_area 成员,默认情况下,该成员用于 指向一个 CMA 区域。分配连续物理内存的时候,CMA 分配器就会根据设备 的 cma_area 成员提供的信息找到指定的 CMA 区域,然后从中分配和释放 连续物理内存资源。因此要让驱动使用指定的 CMA 区域,只要设置设备 struct device 的 cma_area 成员即可
实践部署
实践基础部署
本文支持在 BiscuitOS 上实践 CMA 碎片问题,如果还没有搭建 BiscuitOS 开发环境,可以下列文章:
实践用例部署
如果已经搭建好 BiscuitOS 开发环境,本文实践部署如下:
选择 “Package” 并进入二级菜单.
选择 “CMA: Contiguous Memory Allocator —>” 并进入二级菜单.
选择 “CMA on special Area Application —>” 和 “CMA on special Area Device Driver Module —>” 并保存退出。接着 使用如下命令:
实践编译部署
这里准备了对应的驱动程序和应用程序,开发者参考下面步骤进行编译安装:
驱动程序
驱动程序用于为用户空间应用程序提供 CMA 申请的接口,其使用如下:
执行完上面的命令之后,BiscuitOS 会下载指定的文件,如下图:
获得上面的文件之后,开发者首先根据 “00001-CMA-special-areas.patch” 补丁 中的内容,对内核进行手动补丁或自动补丁,其修改内容如下:
从补丁的内容可以看出,首先将 “dma_alloc_from_contiguous” 和 “dma_release_from_contiguous” 两个函数使用 “EXPORT_SYMBOL()” 宏 进行导出,以便供外部模块使用。接着在 “mm/cma.c” 文件中添加了 一个函数 “find_cma_by_name()” 其作用是通过名字直到指定的 cma 区块对应的结构体. 接着是 “default.dts” 文件,该文件用户描述 该驱动的 DTS 节点以及 CMA 区块的配置信息,如下:
开发者参考上面的内容添加到内核的 DTS 文件中,例如本例子中 使用的 DTS 位于:
开发者参考上面的 DTS 之后,在项目的 DTS 文件中找到 reserved-memory 节点, 然后向该节点中分别添加 “linux,cma” 和 “BiscuitOS_cma” 两个节点,其节点 属性与图中的配置一致。最后打完补丁和添加完 patch 之后,开发者需要重新 编译内核,可以参考如下命令:
接着编译驱动和安装模块到 BiscuitOS,使用如下命令:
执行完上面的命令之后,驱动已经成功安装到 BiscuitOS,接着只要在 BiscuitOS 系统运行的时候安装就行。接下来是安装驱动对应的应用程序。
应用程序
应用程序与驱动程序配合,目的是从 CMA 中获得连续物理内存。从应用程序 角度看,应用程序并不关系物理地址来自哪块 CMA 区域,只关系从 CMA 中 分配到连续物理内存即可。开发者首先按照下列步骤部署应用程序:
在获得源码之后,开发者继续执行如下命令将应用程序源码进行编译、安装 和打包到 BiscuitOS 系统里:
实践运行部署
在准备好驱动和应用程序之后,接下来就是在 BiscuitOS 上面使用即可。 开发者使用如下命令启动 BiscuitOS:
接着安装驱动:
安装完毕驱动之后,可以在 “/dev” 目录下查看当前获得 CMA_demo 节点。 运行应用程序:
由上图可以看到应用程序从 CMA 中分配的内存起始地址是 0x69300000,该地址 位于 BiscuitOS_cma 区域内。因此实践成功。
实践源码分析
源码分作驱动部分和应用程序部分,驱动源码位于:
驱动中指定 CMA 区域的核心代码如下:
应用程序源码位于:
驱动程序的主要通过应用程序 ioctl 发送命令 “CMA_MEM_ALLOCATE” 和 “CMA_MEM_RELEASE” 告诉驱动程序进行 CMA 分配和释放,驱动程序进而调用 “dma_alloc_from_contiguous()” 函数和 “dma_release_from_contiguous()” 函数 进行进行 CMA 的分配和释放动作。