浅浅讲解下Linux内存管理之CMA
说明:
Kernel版本:4.14
ARM64处理器,Contex-A53,双核
使用工具:Source Insight 3.5, Visio
1. 概述
Contiguous Memory Allocator, CMA
,连续内存分配器,用于分配连续的大块内存。CMA分配器
,会Reserve一片物理内存区域:
设备驱动不用时,内存管理系统将该区域用于分配和管理可移动类型页面;
设备驱动使用时,用于连续内存分配,此时已经分配的页面需要进行迁移;
此外,CMA分配器
还可以与DMA子系统
集成在一起,使用DMA的设备驱动程序无需使用单独的CMA API
。
2. 数据结构
内核定义了struct cma
结构,用于管理一个CMA区域
,此外还定义了全局的cma数组
,如下:
base_pfn
:CMA区域物理地址的起始页帧号;count
:CMA区域总体的页数;*bitmap
:位图,用于描述页的分配情况;order_per_bit
:位图中每个bit
描述的物理页面的order
值,其中页面数为2^order
值;
来一张图就会清晰明了:

【文章福利】小编推荐自己的Linux内核技术交流群:【749907784】整理了一些个人觉得比较好的学习书籍、视频资料共享在群文件里面,有需要的可以自行添加哦!!!(含视频教程、电子书、实战项目及代码)


3. 流程分析
3.1 CMA区域创建
3.1.1 方式一 根据dts来配置
之前的文章也都分析过,物理内存的描述放置在dts
中,最终会在系统启动过程中,对dtb
文件进行解析,从而完成内存信息注册。
CMA
的内存在dts
中的描述示例如下图:

在dtb
解析过程中,会调用到rmem_cma_setup
函数:

3.1.2 方式二 根据参数或宏配置
可以通过内核参数或配置宏,来进行CMA区域的创建,最终会调用到cma_declare_contiguous
函数,如下图:

3.2 CMA添加到Buddy System
在创建完CMA区域
后,该内存区域成了保留区域,如果单纯给驱动使用,显然会造成内存的浪费,因此内存管理模块会将CMA区域
添加到Buddy System
中,用于可移动页面的分配和管理。CMA区域
是通过cma_init_reserved_areas
接口来添加到Buddy System
中的。
core_initcall(cma_init_reserved_areas);
core_initcall
宏将cma_init_reserved_areas
函数放置到特定的段中,在系统启动的时候会调用到该函数。

3.3 CMA分配/释放
CMA分配,入口函数为
cma_alloc
:

CMA释放,入口函数为
cma_release
:函数比较简单,直接贴上代码
3.4 DMA使用
代码参考driver/base/dma-contiguous.c
,主要包括的接口有:
在上述的接口中,实际调用的就是cma_alloc/cma_release
接口来实现的。
整体来看,CMA分配器还是比较简单易懂,也不再深入分析。
原文作者:LoyenWang
