linux内核中CMA内存分配

目录

一、CAM的必要性

二、当应用层申请大的内存时的解决方法

三、CAM使用方法

        1、内核配置:

        2、 配置CMA区域有3种方法

3、设备树源码解析

四、技术原理

1、创建CMA区域

2、把CAM区域释放给页分配器

3、从CMA区域借用页

4、从CMA区域分配内存

5、释放CMA区域的内存


一、CAM的必要性

系统长时间运行后,可能碎片化,很难找到连续物理页。连续内存分配器CAM使得这种情况下分配大的连续内存块成为可能。


二、当应用层申请大的内存时的解决方法


1、一种解决方案是为设备保留一块大的内存区域:缺点 当设备驱动不使用的实时,内核其他模块也不能使用这块内存;


2、连续内存分配试图解决这个问题,保留一块大的内存区域。当设备驱动不使用的时候,内核其他模块可以使用,要求:只有申请可移动类型的页时可以借用;当设备驱动需要使用的时候,把已经分配的页迁移到其他地方,形成物理连续的大内存块。


三、CAM使用方法


1、内核配置:

  • 配置宏CONFIG_CMA,启动连续内存分配器
  • 配置宏CONFIG_CMA_AREAS,指定CMA区域的最大数量,默认值是7
  • 配置宏CONFIG_DMA_CMA运行设备驱动分配内存的连续内存分配器


    CMA区域分为全局CMA区域设备私有CMA区域。全局CMA区域是由所有设备共享的,设备私有CMA区域由指定的一个或多个设备驱动使用。


 2、 配置CMA区域有3种方法

  • 通过内核参数cma配置全局cma区域大小;

        使用内核参数cma=nn[MG]@[start[MG]][-end[MG]]设置全局CMA区域的大小和物理地址范围

  • 通过配置宏配置全局CMA区域的大小;

        CONFIG_CMA_SIZE_SEL_MBYTES表示兆字节;0表示禁用
        CONFIG_CMA_SIZE_SEL_PERCENTAGE 表示指定物理内存容量的百分比,默认使用指定兆字节数的方式;0表示禁用
        以上两种方式都可以使用内存传递参数启用CMA

  • 通过设备树源文件/reserved-memory配置CMA区域

        如果子节点的属性“compatible”的值是shared-dma-pool 表示全局CMA区域,否则表示设备私有CMA区域

3、设备树源码解析

reserved-memory {
	#address-cells= <1>;
	#size-cells= <1>;
	ranges ;
		linux , cma {
		    compatible= " shared-dma-pool" ;
		    reusable;
		    size= <Ox4000000>;
		    alignment= <Ox2000>;
		    linux , cma-defaul 七;
		} ;
		display_reserved: framebuffer@78000000 {
		    reg= <Ox78000000 Ox800000>;
		) ;
		multimedia reserved : multimedia@77000000
		    compatible= "acme, multimedia-memory" ;
		    reg= <Ox77000000 Ox4000000>;
		} ;
) ; 

分配三个cma区域,

  • 节点名称linux,cma 大小64MB,
  • 帧缓冲设备专用CMA framebuffer 大小8M
  • 多媒体专用CMA区域,节点multimedia-memory 大小64M 

四、技术原理


连续内存分配器是DMA映射框架的辅助框架,设备驱动程序不能直接使用连续分配器;

  • 连续内存分配器是在页分配器的基础上实现的,提供接口cma_alloc用来从CMA区域分配页,cma_release用来释放CMA区域分配的页
  • 在连续内存分配器的基础上实现了DMA映射框架专用的连续内存分配器,简称DMA专用连续内存分配器。

            dma_alloc_from_contiguous 用来从CMA分配
            dma_release_from_contiguous 释放

  • dma映射框架从DMA专用连续内存分配器分配或释放,为设备驱动程序提供的接口

            dma_alloc_coherent  ,dma_alloc_noncoherent 用来分配内存
            dma_free_conerent ,dma_free_nocoherent用来释放内存

  • 设备驱动程序调用DMA映射框架提供的函数来分配或释放。 

 可配置多个CMA区域,内核定义一个数组来管理CMA区域

struct cma cma_areas[MAX_CMA_AREAS];
unsigned cma_area_count;

页分配器为CMA区域的物理页定义了迁移类型MIGRATE_CMA

1、创建CMA区域


内存管理子系统初始化,解析设备树二进制文件得到物理内存布局,使用memblock保存布局信息。
        memblock的memory保存物理块的物理地址范围,
        reserved类型保存预留内存块的物理地址范围
        CMA区域属于保留内存块

通过设备树配置CMA区域,解析如下:
setup_arch->arm64_memblock_init
            early_init_fdt_scan_reaseved_mem     


2、把CAM区域释放给页分配器


memblock是内核初始化的时候使用的内存分配器,内核初始化完成后使用伙伴分配器管理物理页。内核初始化后,把空闲的内存释放给伙伴分配器,不会把保留的内存释放给伙伴分配器。CMA是保留内存。但需要把CMA区域的物理页交给伙伴分配器管理

3、从CMA区域借用页


当设备驱动程序不使用CMA区域的时候,内核的其他模块可以借用CMA区域的物理页,页分配器只允许可移动类型从CMA类型
借用物理页。
1)从迁移类型分配页
2)如果分配失败,从备用类型借用物理页
    如果指定迁移类型是可移动类型,首先从CMA类型借用物理页
    从备用类型列表中的每个迁移类型借用物理页

4、从CMA区域分配内存

当设备驱动程序需要使用CMA区域的时候,如果CMA区域的物理页已经被页分配器分配出去,需要把物理页迁移到其他地方。

  • 1)在CMA区域的位图中查找一个足够大的空闲页块
  • 2)在位图中把物理页的分配状态设置为已分配
  • 3)调用函数alloc_contig_range把页分配出去的物理页迁移到其他地方;
  • 4)如果迁移失败,回到1),找下一个足够大的空闲页块尝试分配,知道分配成功或者尝试完所有的空闲页块;

5、释放CMA区域的内存

  • 1)  检测物理页是否是CMA区域;
  • 2)把物理页释放给页分配器;
  • 3)在CMA位图中把物理页状态标记为空闲;

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

为了维护世界和平_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值