linux内核中CMA内存分配

CMA的必要性

Continuous Memory Allocator

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

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

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

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

CMA的使用方法

配置宏CONFIG_CMA,启动连续内存分配器;

配置宏CONFIG_CMA_AREAS,指定CMA区域的最大数量,默认值为7;

配置宏CONFIG_DMA_CMA运行设备驱动分配内存的连续内存分配器;

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

配置CMA区域有3种方法

1)通过内核参数cma配置全局cma区域大小:

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

2)通过配置宏配置全局CMA区域的大小

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

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

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

设备树源码解析

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区域:

1)节点名称linux,cma 大小64MB

2)帧缓冲设备专用CMA framebuffer,大小8M

3)多媒体专用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位图中把物理页状态标记为空闲;
     学习链接:

    kernel学习链接

     参考

    https://course.0voice.com/v1/course/intro?courseId=2&agentId=0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值