[内存管理] Linux Reserved Memory 预留内存

本文详细介绍了如何在Linux系统中为设备驱动预留内存,包括通过DMA API、CMA(Contiguous Memory Allocator)以及直接在设备树中配置内存节点。内容涵盖了64位和32位系统的实例,展示了如何在驱动程序中分配和映射预留内存,以及如何使用DMA API进行内存管理。此外,还讨论了如何为CMA预留内存,以创建固定的内存池。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

前言

预留内存给设备驱动

通过DMA API预留内存

给CMA预留内存


原文地址:
Linux Reserved Memory

前言

基于Xilinx Zynq SoC / MPSoC的系统的常见要求之一是为特殊用途预留内存。预留的内存区域需要从linux内核的使用区域中分离出来,仅给特定的驱动程序使用。
reserved-memory 架构包含了预留内存的功能。预留内存的功能又与内核中的 DMA-API 和 CMA 框架密切相关。

本文旨在展示和解释一些可用的用例,并且已经使用Petalinux构建工具进行了测试。由于本文中的修改仅涉及DTS文件定制和设备驱动程序中分配内存位置的改动,还是可以将其导出到Yocto或OSL工作流程中的。

预留内存给设备驱动

为了从系统地址空间预留内存,设备树须配置预留内存的节点。每个节点定义一个特定的内存空间,并且可以根据内核文档中关于可用于预留内存节点的说明配置不同的参数。然后就可以通过memory-region参数将预留的内存空间分配给特定的设备驱动程序使用。

用于64位Cortex-A53 MPSoC的system-top.dts文件中的设备树节点:

 reserved-memory {
      #address-cells = <2>;
      #size-cells = <2>;
      ranges;
 
      reserved: buffer@0 {
         no-map;
         reg = <0x0 0x70000000 0x0 0x10000000>;
      };
   };
 
   reserved-driver@0 {
      compatible = "xlnx,reserved-memory";
      memory-region = <&reserved>;
   };

或32位Cortex-A9 Zynq上,最新的基于 Yocto的Petalinux 的自定义的类似的设备树节点:

/include/ "system-conf.dtsi"
/ {
   reserved-memory {
      #address-cells = <1>;
      #size-cells = <1>;
      ranges;
  
      reserved: buffer@0x38000000 {
         no-map;
         reg = <0x38000000 0x08000000>;
      };
   };
  
   reserved-driver@0 {
      compatible = "xlnx,reserved-memory";
      memory-region = <&reserved>;
   };
};

在设备驱动程序中,可以通过解析设备树节点来处理内存区域的属性,并且一旦知道了物理地址和大小,就可以使用 memremap / ioremap 调用来映射内存区域。

下面的代码使用了预留的内存分配:

/* Get reserved memory region from Device-tree */
np = of_parse_phandle(dev->of_node, "memory-region", 0);
if (!np) {
  dev_err(dev, "No %s specified\n", "memory-region");
  goto error1;
}
  
rc = of_address_to_resource(np, 0, &r);
if (rc) {
  dev_err(dev, "No memory address assigned to the region\n");
  goto error1;
}
  
lp->paddr = r.start;
lp->vaddr = memremap(r.start, resource_size(&r), MEMREMAP_WB);
dev_info(dev, "Allocated reserved memory, vaddr: 0x%0llX, paddr: 0x%0llX\n", (u64)lp->vaddr, lp->paddr);

由于保留的内存区域已被内核排除,并标记为no-map,因此 iomem 信息(/ proc / iomem)显示系统RAM小于主板中的内存量。

root@plnx_aarch64:~# cat /proc/iomem
00000000-6fffffff : System RAM
  00080000-00b37fff : Kernel code
  011c9000-012b8fff : Kernel data

加载设备后,可以确认内存分配:

[  126.191774] reserved-memory reserved-driver@0: Device Tree Probing
[  126.198595] reserved-memory reserved-driver@0: Allocated reserved memory, vaddr: 0xFFFFFF8020000000, paddr: 0x70000000

通过DMA API预留内存

有的时候设备驱动程序需要采用DMA的方式使用预留的内存,对于这种场景,可以将 dts 中的节点属性设置为 shared-dma-pool,从而生成为特定设备驱动程序预留的 DMA 内存池。

reserved-memory {
      #address-cells = <2>;
      #size-cells = <2>;
      ranges;
 
      reserved: buffer@0 {
         compatible = "shared-dma-pool";
         no-map;
         reg = <0x0 0x70000000 0x0 0x10000000>;
      };
   };
 
   reserved-driver@0 {
      compatible = "xlnx,reserved-memory";
      memory-region = <&reserved>;
   };

这样,设备驱动程序仅需要以常规方式使用 DMA API,但无需使用默认的 CMA 内存池,它将使用该特定设备的预留内存区域。(独占这一块内存,仍然使用DMA的接口)

/* Initialize reserved memory resources */
  rc = of_reserved_mem_device_init(dev);
  if(rc) {
    dev_err(dev, "Could not get reserved memory\n");
    goto error1;
  }
  
  /* Allocate memory */
  dma_set_coherent_mask(dev, 0xFFFFFFFF);
  lp->vaddr = dma_alloc_coherent(dev, ALLOC_SIZE, &lp->paddr, GFP_KERNEL);
  dev_info(dev, "Allocated coherent memory, vaddr: 0x%0llX, paddr: 0x%0llX\n", (u64)lp->vaddr, lp->paddr);

内核启动的log:

[    0.000000] Reserved memory: created DMA memory pool at 0x0000000070000000, size 256 MiB
[    0.000000] Reserved memory: initialized node buffer@0, compatible id shared-dma-pool
[    0.000000] cma: Reserved 128 MiB at 0x0000000068000000

驱动加载的log:

root@plnx_aarch64:~# insmod /lib/modules/4.6.0-xilinx/extra/reserved-memory.ko
[   80.745166] reserved-memory reserved-driver@0: Device Tree Probing
[   80.750183] reserved-memory reserved-driver@0: assigned reserved memory node buffer@0
[   81.220878] reserved-memory reserved-driver@0: Allocated coherent memory, vaddr: 0xFFFFFF8020000000, paddr: 0x70000000
 

给CMA预留内存

有时,不需要将预留的内存分配给特定的设备驱动程序,而只打算给 CMA 内存池分配一块固定的内存区域。 对于这种场景,可以使用一个额外的属性来指向内核,以将预留的内存区域用作默认的 CMA 内存池。
属性:
reusable;
linux,cma-default

reserved-memory {
      #address-cells = <2>;
      #size-cells = <2>;
      ranges;
 
      reserved: buffer@0 {
         compatible = "shared-dma-pool";
         reusable;
         reg = <0x0 0x70000000 0x0 0x10000000>;
         linux,cma-default;
      };
   };

内核启动关于CMA分配的log:

[    0.000000] Reserved memory: created CMA memory pool at 0x0000000070000000, size 256 MiB
[    0.000000] Reserved memory: initialized node buffer@0, compatible id shared-dma-pool

 

 

### NHLOS预留内存概述 NHLOS(Non-Hardware-Limited Operating System)是一种操作系统架构设计模式,通常用于嵌入式设备或特定场景下的资源管理优化。对于NHLOS中的预留内存配置和使用说明,可以从以下几个方面展开: #### 1. **预留内存的作用** 预留内存是指在系统启动阶段预先分配的一段物理内存区域,主要用于满足某些特殊用途的需求。例如,在Linux内核中,CMA(Contiguous Memory Allocator)就是一种典型的预留内存机制[^1]。它通过提前规划一段连续的物理地址空间来支持需要大块连续内存的应用程序。 在NHLOS环境中,预留内存可能被用来实现以下功能: - 提供专用缓冲区给硬件驱动程序。 - 支持实时性较高的任务调度需求。 - 确保关键服务运行期间不会因内存不足而中断。 #### 2. **NHLOS预留内存的配置方法** NHLOS系统的具体实现方式会有所不同,但一般可以通过修改引导参数或者编辑相关配置文件完成设置。以下是常见的两种途径及其操作指南: ##### (1)**通过命令行传递参数** 如果采用的是基于U-boot或其他类似的Bootloader加载方案,则可以在kernel command line里增加指定选项定义保留范围大小以及位置等属性值。比如下面这个例子展示了如何为某款SoC平台设定固定数量字节长度作为专门用途所使用的RAM区间: ```bash memmap=reserve:<size>@<start> ``` 其中`<size>`表示要保护起来不被普通进程占用的空间尺寸(单位可以是K,M,G),而`<start>`则是该片段起始处对应的绝对偏移量地址[^2]。 注意:实际应用过程中需参照目标板卡手册确认兼容性和语法细节。 ##### (2)**利用DTB(Device Tree Blob)节点描述** 现代ARM Cortex-A系列处理器普遍依赖device tree技术表达硬件特性信息。因此也可以借助这种方式声明哪些部分应该划归到受控范畴之内而不参与常规动态分配流程之中去处理。如下所示即是一个简单的示范片断: ```dts reserved-memory { #address-cells = <1>; #size-cells = <1>; my_reserved_region@80000000 { reg = <0x80000000 0x1000000>; /* Reserve 16MB at physical address 0x80000000 */ no-map; }; }; ``` 上述代码片段创建了一个名为 `my_reserved_region` 的保留区域,位于物理地址 `0x80000000` 处,并占据 16 MB 的空间[^3]。 #### 3. **注意事项与最佳实践建议** 当涉及到调整此类高级别的底层资源配置时,请务必遵循以下原则以减少潜在风险并提高稳定性表现水平: - 明确评估当前项目所需的确切规格后再做决定; - 尽量保持最小化影响正常业务逻辑运转的前提下实施改动; - 测试验证新策略生效后的整体性能指标变化情况; 最后提醒一点,由于不同版本之间可能存在差异性较大甚至完全重构的情况发生,所以在查阅官方文档资料的同时也要密切关注社区最新进展动态获取最权威指导依据[^4]。 ```python # 示例 Python 脚本展示如何解析 /proc/iomem 文件查找已知标签对应的实际基址范围 with open('/proc/iomem', 'r') as f: lines = f.readlines() for line in lines: if 'CMA' in line or 'reserved' in line: print(line.strip()) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值