说明:

  1. Kernel版本:4.14
  2. ARM64处理器,Contex-A53,双核
  3. 使用工具:Source Insight 3.5, Visio

1. 概述

Contiguous Memory Allocator, CMA,连续内存分配器,用于分配连续的大块内存。CMA分配器,会Reserve一片物理内存区域:

  1. 设备驱动不用时,内存管理系统将该区域用于分配和管理可移动类型页面;
  2. 设备驱动使用时,用于连续内存分配,此时已经分配的页面需要进行迁移;

此外,CMA分配器还可以与DMA子系统集成在一起,使用DMA的设备驱动程序无需使用单独的CMA API。

2. 数据结构

内核定义了struct cma结构,用于管理一个CMA区域,此外还定义了全局的cma数组,如下:

struct cma {unsigned long   base_pfn;unsigned long   count;unsigned long   *bitmap;unsigned int order_per_bit; /* Order of pages represented by one bit */struct mutex    lock;
#ifdef CONFIG_CMA_DEBUGFSstruct hlist_head mem_head;spinlock_t mem_head_lock;
#endifconst char *name;
};extern struct cma cma_areas[MAX_CMA_AREAS];
extern unsigned cma_area_count;
  • base_pfn:CMA区域物理地址的起始页帧号;
  • count:CMA区域总体的页数;
  • *bitmap:位图,用于描述页的分配情况;
  • order_per_bit:位图中每个bit描述的物理页面的order值,其中页面数为2^order值;

来一张图就会清晰明了:

资料直通车:Linux内核源码技术学习路线+视频教程内核源码

学习直通车:Linux内核源码内存调优文件系统进程管理设备驱动/网络协议栈

3. 流程分析

3.1 CMA区域创建

3.1.1 方式一 根据dts来配置

之前的文章也都分析过,物理内存的描述放置在dts中,最终会在系统启动过程中,对dtb文件进行解析,从而完成内存信息注册。

CMA的内存在dts中的描述示例如下图:

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

RESERVEDMEM_OF_DECLARE(cma, "shared-dma-pool", 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:函数比较简单,直接贴上代码
/*** cma_release() - release allocated pages* @cma:   Contiguous memory region for which the allocation is performed.* @pages: Allocated pages.* @count: Number of allocated pages.** This function releases memory allocated by alloc_cma().* It returns false when provided pages do not belong to contiguous area and* true otherwise.*/
bool cma_release(struct cma *cma, const struct page *pages, unsigned int count)
{unsigned long pfn;if (!cma || !pages)return false;pr_debug("%s(page %p)\n", __func__, (void *)pages);pfn = page_to_pfn(pages);if (pfn < cma->base_pfn || pfn >= cma->base_pfn + cma->count)return false;VM_BUG_ON(pfn + count > cma->base_pfn + cma->count);free_contig_range(pfn, count);cma_clear_bitmap(cma, pfn, count);trace_cma_release(pfn, pages, count);return true;
}

3.4 DMA使用

代码参考driver/base/dma-contiguous.c,主要包括的接口有:

/*** dma_alloc_from_contiguous() - allocate pages from contiguous area* @dev:   Pointer to device for which the allocation is performed.* @count: Requested number of pages.* @align: Requested alignment of pages (in PAGE_SIZE order).* @gfp_mask: GFP flags to use for this allocation.** This function allocates memory buffer for specified device. It uses* device specific contiguous memory area if available or the default* global one. Requires architecture specific dev_get_cma_area() helper* function.*/
struct page *dma_alloc_from_contiguous(struct device *dev, size_t count,unsigned int align, gfp_t gfp_mask);/*** dma_release_from_contiguous() - release allocated pages* @dev:   Pointer to device for which the pages were allocated.* @pages: Allocated pages.* @count: Number of allocated pages.** This function releases memory allocated by dma_alloc_from_contiguous().* It returns false when provided pages do not belong to contiguous area and* true otherwise.*/
bool dma_release_from_contiguous(struct device *dev, struct page *pages,int count);

在上述的接口中,实际调用的就是cma_alloc/cma_release接口来实现的。

整体来看,CMA分配器还是比较简单易懂,也不再深入分析。

浅浅讲解下Linux内存管理之CMA相关推荐

  1. Linux内存管理:CMA(连续内存分配)(DMA)

    目录 什么是CMA 数据结构 CMA区域 cma_areas 的创建 dts方式 command line方式 将CMA区域添加到Buddy System CMA分配 <Linux内存管理:什么 ...

  2. linux cma内存,【原创】(十六)Linux内存管理之CMA,

    [原创](十六)Linux内存管理之CMA, 背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. ...

  3. Linux内存管理之CMA简介

    1.概述 在linux驱动开发过程中经常需要使用到连续大块物理内存,尤其是DMA设备.而实际在系统经过长时间的允许之后,物理内存会出现比较严重的碎片化现象,虽然通过内存规整,内存回收等手动可以清理出一 ...

  4. linux 内存 cma,【原创】(十六)Linux内存管理之CMA

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  5. 万字整理,肝翻Linux内存管理所有知识点【Linux内核开发人员必学】都是精髓

    Linux的内存管理可谓是学好Linux的必经之路,也是Linux的关键知识点,有人说打通了内存管理的知识,也就打通了Linux的任督二脉,这一点不夸张.有人问网上有很多Linux内存管理的内容,为什 ...

  6. 万字整理,图解Linux内存管理所有知识点

    Linux的内存管理可谓是学好Linux的必经之路,也是Linux的关键知识点,有人说打通了内存管理的知识,也就打通了Linux的任督二脉,这一点不夸张.有人问网上有很多Linux内存管理的内容,为什 ...

  7. Linux内存管理:知识点总结(ARM64)

    https://mp.weixin.qq.com/s/7zFrBuJUK9JMQP4TmymGjA 目录 Linux内存管理之CPU访问内存的过程 虚拟地址转换为物理地址的本质 Linux内存初始化 ...

  8. 万字整理,肝翻Linux内存管理所有知识点

    Linux的内存管理可谓是学好Linux的必经之路,也是Linux的关键知识点,有人说打通了内存管理的知识,也就打通了Linux的任督二脉,这一点不夸张.有人问网上有很多Linux内存管理的内容,为什 ...

  9. 浅谈Linux内存管理那些事儿

    linux相关视频解析: 5个方面分析linux内核架构,让你对内核不再陌生 手把手带你实现一个Linux内核文件系统 1 前言 内存管理是Linux内核中非常重要的部分,今天和大家一起学习一下. 当 ...

最新文章

  1. QT 32位程序Debug模式发布问题
  2. js 获取 select的option的 id值
  3. 计算机主机中网卡的作用,计算机硬件组成及作用
  4. php怎么改标题,PHP – 如何更改包含header.php的页面标题?
  5. jQuery.Event的一些用法
  6. 现在最流行哪款有linux系统,哪一个Linux发行版最流行?
  7. 创建一个简单的MFC程序
  8. ibm x3850装oracle,Oracle数据库服务器:x3850 X5
  9. 【Python】利用tkinter开发AI对战井字棋游戏
  10. WPS如何在同一篇文档针对不同章节设置不同的页眉页脚
  11. 还想打马赛克掩盖身份?人工智能让你告别打码时代
  12. android自动调节背光,android自动调节背光
  13. 我为JNCIE狂——Juniper认证成长之路
  14. 泰坦尼克号乘客获救预测
  15. 在C中将二进制转换为十进制
  16. redis中的increment()方法遇到的问题记录
  17. Django站内消息通知
  18. 前端网页生成二维码方法
  19. matlab如何解麦克斯韦方程,麦克斯韦方程组-Read.PPT
  20. 爬虫:爬取某个商品的历史价格并绘制折线图

热门文章

  1. 何为固定IP和动态IP?快解析搞定固定IP端口映射!
  2. 【C++·C11】C++ 时间与时间戳
  3. springboot罗亚方舟考研资料库网站设计与实现毕业设计源码302302
  4. 分享136个PHP源码,总有一款适合您
  5. Matlab中属性 get 方法的使用
  6. amazeui学习笔记--css(常用组件6)--图标Icon
  7. 第二章:真分数理论(信度系数的估计)(三)
  8. checkra1n越狱错误79_新的unc0ver漏洞可让运行iOS / iPadOS 12至13.5的苹果iPhone和iPad越狱...
  9. 直流电机的原理及驱动
  10. 小米java后端实习一面面经