DMA区域会极大的浪费内存的使用,因为即使DMA没有人使用,DMA区域也会空在这里,因此引入CMA解决这种问题。为了解决既不浪费内存,又能申请到连续的物理内存空间,在嵌入式中引入了CMA的概念。
CMA:contiguous memry allocator。CMA区域和DMA功能一样,专门用于DMA或者其他功能。如果该模块未被使用,他不会空着,他会通过free_pages释放到伙伴系统中,上层可以通过alloc_page这些接口申请。如果中间突然需要使用CMA的大块内存,此时需要将CMA这个区域被用于伙伴系统的这部分内存进行迁移。只有当dma或者其他模块需要连续大块内存的时候,它才会分配出一个CMA区域。
- 如何申请一个大块连续的物理内存?
- CMA初始化:内核配置,设备树dts文件管理
1.CMA结构体描述
cma结构体的具体介绍:专门用来描述预留的内存区域。注意 ,这里是可以设置多个cma区域的。在Linux内核中定义了两个全局变量:他们记录了系统有多少个CMA区域。
extern struct cma cma_areas[MAX_CMA_AREAS];
extern unsigned cma_area_count;
struct cma{
unsigned long base pfn; //cma区域的起始地址
unsigned long count; //cma区域的页面数,物理页数
unsigned long *bitmap; //cma区域物理页的内存情况,使用位图来描述cma区域物理页的使用情况。每个bit值表示对应的物理页是否空闲。并且和order_per_bit结合使用,当bit为0时,bitmap每个位表示的指向的是1个页面,是1就是2个页面,类似伙伴系统中的order。
unsigned int order_per_bit;//1
char name[cma max name];
};
extern struct cma cma areas(max cma areas);
这里的bitmap好像不好直接理解:因为struct cma_area[MAX_CMA_AREAS]区域通过一个数组来记录,因此这里每个cma_area区域的记录的页面大小都是一样的(order_per_bit只能是一个值)。//cma区域物理页的内存情况,使用位图来描述cma区域物理页的使用情况。每个bit值表示对应的物理页是否空闲。并且和order_per_bit结合使用,当bit为0时,bitmap每个位表示的指向的是1个页面,是1就是2个页面,类似伙伴系统中的order。
遗留问题:是否意味着bit_map最多描述的long类型个页面(假设order是0)。
CMA和DMA类似,也是预留出来的。专门用于DMA或者其他多媒体模块的连续大块的物理内存使用。但是,如果这个区域没有被使用的话,会通过free_page函数接口释放到伙伴系统中??没理解。只有当DMA需要连续大块内存的使用,才会分配(再从原来的伙伴系统中拿出来,如果有些cma区域的内存已经被伙伴系统分出去了,此时需要对CMA分配出去的页面做出迁移操作,搬到其他区域出去)。
现在一般是通过设备树来指定cma区域的信息,并且初始化。例如下面是某个开发板设备树中的信息。
注意:cma区域的内存在伙伴系统中是单独用一个链表表示的,并且会把页面也类型标识为MIGRATE_CMA。
我们可以看到,pagetype中是有cma类型的区域的。
2.cma接口:cma_alloc cma_release
用户一般不会通过cma的接口使用,一般是通过dma接口调用。这部分代码显示申请和释放都依赖于伙伴系统。