• 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、设备树源码解析

    1. reserved-memory {
    2. #address-cells= <1>;
    3. #size-cells= <1>;
    4. ranges ;
    5. linux , cma {
    6. compatible= " shared-dma-pool" ;
    7. reusable;
    8. size= <Ox4000000>;
    9. alignment= <Ox2000>;
    10. linux , cma-defaul 七;
    11. } ;
    12. display_reserved: framebuffer@78000000 {
    13. reg= <Ox78000000 Ox800000>;
    14. ) ;
    15. multimedia reserved : multimedia@77000000
    16. compatible= "acme, multimedia-memory" ;
    17. reg= <Ox77000000 Ox4000000>;
    18. } ;
    19. ) ;

    分配三个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区域

    1. struct cma cma_areas[MAX_CMA_AREAS];
    2. 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

     

  • 相关阅读:
    【Ansible】02
    python+vue_django编程语言在线学习平台
    《定时执行专家》官方版介绍 —— 毫秒级精度、多线程、专业级的定时任务执行软件
    JAVA对象大小的获取
    图解域名解析成IP的全过程(你浏览器摁下一个网址后发生了啥?)
    计算机专业毕业设计项目推荐12-志愿者管理系统(Spring+Js+Mysql)
    多跳推理真的可解释吗?10.24
    Linux 线程控制 —— 线程取消 pthread_cancel
    Android C++系列:Linux进程间关系
    3.8 PCIe控制器——运行机制——错误处理
  • 原文地址:https://blog.csdn.net/WANGYONGZIXUE/article/details/133375244