# 配置和管理内存

Qualcomm^®^ Linux 内核基线支持所有内存管理功能和分配器。以下信息概述了如何定制内存映射和执行堆管理。

有关 Linux 内核内存管理的详细信息，参见 [Memory management](https://www.kernel.org/doc/html/next/core-api/index.html#memory-management)。

**内存映射**

内存映射描述了内核启动过程中为子系统（如 Modem、摄像头、aDSP 和 cDSP 等）保留的区域。

内存映射为 DTSI 中的划分区域设置 `no-map`，使内核无法访问这些区域。

可配置的划分区域定义在 `reserved-memory` 节点下的 `arch/arm64/boot/dts/qcom/qcs6490.dtsi` 文件中。

reserved-memory {
                   cdsp_secure_heap_mem: cdsp-secure-heap@81800000 {
                            reg = <0x0 0x81800000 0x0 0x1e00000>;
                            no-map;
                   };
    
                   camera_mem: camera@84300000 {
                            reg = <0x0 0x84300000 0x0 0x500000>;
                            no-map;
                   };
    
                   wpss_mem: wpss@0x84800000 {
                            reg = <0x0 0x84800000 0x0 0x1900000>;
                            no-map;
                   };
    
                   adsp_mem: adsp@86100000 {
                            reg = <0x0 0x86100000 0x0 0x2800000>;
                            no-map;
                   };
    };
    Copy to clipboard

Note

对于 Qualcomm SoC ，参见 SoC 特定的 Qualcomm DTSI 文件以获取此信息。

以下早期启动日志显示了为不同子系统创建的划分区域：

[    0.000000] OF: reserved mem: 0x0000000081800000..0x00000000835fffff (30720 KiB) nomap non-reusable cdsp-secure-heap@81800000
    [    0.000000] OF: reserved mem: 0x0000000084300000..0x00000000847fffff (5120 KiB) nomap non-reusable camera@84300000
    [    0.000000] OF: reserved mem: 0x0000000084800000..0x00000000860fffff (25600 KiB) nomap non-reusable wpss@0x84800000
    [    0.000000] OF: reserved mem: 0x0000000086100000..0x00000000888fffff (40960 KiB) nomap non-reusable adsp@86100000
    Copy to clipboard

## 连续内存分配器

Qualcomm Linux 分发版支持 CMA 来分配物理上连续的大内存。CMA 在启动时会保留大块的物理上连续的内存区域，并在 CMA 分配时提供物理上连续的内存。不使用时，CMA 内存可供内核伙伴分配器进行可移动分配。

要更改默认 CMA 区域的大小，请运行内核命令行参数中的 `cma=size_in_MB`。有关如何使用内核参数的详细信息，可参见以下示例：

cma=nn[MG]@[start[MG][-end[MG]]]
                            [KNL,CMA]
                            Sets the size of kernel global memory area for
                            contiguous memory allocations and optionally the
                            placement constraint by the physical address range of
                            memory allocations. A value of 0 disables CMA
                            altogether. For more information, see
                            kernel/dma/contiguous.c
    Copy to clipboard

自定义 CMA 区域定义在 `reserved-memory` 节点，其兼容标签 `shared-dma-pool` 指示 CMA 区域：

adsp_heap_mem: adsp-heap {
                            compatible = "shared-dma-pool";
                            alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>;
                            reusable;
                            alignment = <0x0 0x400000>;
                            size = <0x0 0xc00000>;
                   };
    Copy to clipboard

以下所示为启动时保留的 aDSP CMA 内存区域的日志示例：

[    0.000000] OF: reserved mem: initialized node adsp-heap, compatible id shared-dma-pool
    [    0.000000] OF: reserved mem: 0x00000000ff000000..0x00000000ffbfffff (12288 KiB) map reusable adsp-heap
    Copy to clipboard

### 添加自定义 CMA 堆

要使用 DMA-BUF 堆创建自定义 CMA 区域，请使用 Qualcomm Linux 内核中现有的 DMA-BUF 框架。

Qualcomm Linux 内核导出自定义 DMA-BUF 堆的 `cma_heap_add()` API。

/**
    * cma_heap_add - adds a CMA heap to dmabuf heaps
    * @cma:       pointer to the CMA pool to register the heap for
    * @data:      unused
    *
    * Returns 0 on success. Else, returns errno.
    */
    
    int cma_heap_add(struct cma *cma, void *data);
    Copy to clipboard

导出到用户空间的 DMA-BUF 堆，其名称与设备树中 CMA 区域的 phandle 相同。

要添加自定义 CMA 堆，可执行以下操作：

1. 要创建定制 CMA 区域，请参见[连续内存分配器](https://docs.qualcomm.com/doc/80-70020-3SC/topic/memory.html#memory-contiguous)。
2. 在要添加自定义堆的驱动程序中：

    1. 解析新添加的 CMA 区域的设备树。
    2. 添加与驱动程序相关的 DMA-BUF 堆。

int create_my_cma_heap(struct device *dev)
            {
               int rc = 0, idx = 0;
            
               rc = of_reserved_mem_device_init_by_idx(dev, dev->of_node, 0);  // Parse the devicetree for the cma region
            
               if (rc) {
                        pr_err("No reserved DMA memory, ret=%d\n", rc);
                        rc = -EINVAL;
                        goto err;
               }
            
               rc = cma_heap_add(dev->cma_area, NULL);  // Add a dmabuf heap associated with the cma region
            
               if (rc) {
                        pr_err("cma_heap_add failed, ret=%d\n", rc);
                        rc = -EINVAL;
                        goto err;
               }
            
            err:
               return rc;
            }
            Copy to clipboard

Note

将 CMA 区域对齐到 4 MB 地址基址并设置大小，以支持页面迁移。迁移发生在 page-block 级别的 2 ^pageblock\_order^ 页。在 Qualcomm Linux 内核中，页面块阶次为 10。

### 支持的堆

下表列出了 Qualcomm Linux 分发版默认支持的堆：

表：默认支持的堆

| 堆名称 | Dev 节点 | 说明 | 用法 |
| --- | --- | --- | --- |
| 系统堆 | /dev/dma_heap/system<br>    Copy to clipboard | 内核会创建默认的 DMA-BUF 堆。 | 所有通用用例都必须遵循系统堆，系统堆在底层使用的是常见的 Linux 内存管理伙伴分配器。 |
| Reserved | /dev/dma_heap/reserved<br>    Copy to clipboard | 系统中创建的默认 CMA 类型的堆，使用默认*保留的* CMA 区域。 | 如果由于任何限制而需要使用连续内存，可使用 CMA 堆。 |
| 定制 CMA 堆 | /dev/dma_heap/my_cma_heap<br>    Copy to clipboard | 用户定义的 CMA 类型的堆。 | 为特定的定制 CMA 堆创建自己的 CMA 类型的堆时使用。 |

### 使用 DMA-BUF 堆

Qualcomm Linux 分发版支持 DMA-BUF 堆，用于分配自定义 CMA 堆。对于 DMA-BUF 堆，每个堆在 `/dev/dma_heap` 文件系统中都有一个设备文件。除了系统堆和常用的 CMA 预留堆外，用户还可以创建自己的 CMA 类型的 DMA-BUF 堆。

下面是一个示例程序，演示了如何使用 Qualcomm Linux 内核创建的 DMA-BUF 系统堆 `/dev/dma_heap/system:`

include <stdio.h>
    include <stdlib.h>
    include <fcntl.h>
    include <errno.h>
    include <unistd.h>
    include <sys/ioctl.h>
    include <linux/dma-buf.h>
    #include <linux/dma-heap.h>
    
    define DMA_HEAP_NAME "system"
    define SZ_4 0x00000004  // to allocate a 4K buffer
    
    int main()
    {
    int fd, dma_buf_fd;
    
    struct dma_heap_allocation_data dma_alloc_data = {
       .len = SZ_4,
       .fd_flags = O_RDWR | O_CLOEXEC,
    };
    
    struct dma_buf_sync sync_start = {
       .flags = DMA_BUF_SYNC_START,
    };
    struct dma_buf_sync sync_end = {
       .flags = DMA_BUF_SYNC_END,
    };
    
    fd = open("/dev/dma_heap/system", O_RDWR);
    if (fd < 0) {
       perror("open");
       return errno;
    }
    
    dma_buf_fd = ioctl(fd, DMA_HEAP_IOCTL_ALLOC, &dma_alloc_data);
    if (dma_buf_fd < 0) {
       perror("ioctl");
       return errno;
    }
    printf("Allocated DMA buffer with fd %d\n", dma_buf_fd);
    
    if (ioctl(dma_buf_fd, DMA_BUF_IOCTL_SYNC, &sync_start)) {
       perror("ioctl DMA_BUF_IOCTL_SYNC start");
       return errno;
    }
    
    //        Do something with the buffer here
    
    if (ioctl(dma_buf_fd, DMA_BUF_IOCTL_SYNC, &sync_end))
    {
       perror("ioctl DMA_BUF_IOCTL_SYNC end");
       return errno;
    }
    
    if (close(dma_buf_fd)) {
       perror("close");
       return errno;
    }
    
    if (close(fd)) {
       perror("close");
       return errno;
    }
    
    return 0;
    }
    Copy to clipboard

### 将 ZRAM 配置为交换设备

ZRAM 是一种压缩交换机制，可在 RAM 中创建虚拟块设备。ZRAM 已作为模块在内核 defconfig 中启用。

在 `recipes-extended/zram/zram/zram-swap-init-update` 文件的 Yocto 编译中配置 ZRAM。

如需启用或配置 ZRAM，可执行以下程序：

# check if zram module is loaded
      lsmod | grep zram
    
    # else load it
      modprobe zram
    
    # Configure /dev/zram0 size according to your RAM size
      echo 128M > /sys/block/zram0/disksize
    
    # activate swap
      mkswap /dev/zram0
      swapon /dev/zram0
    Copy to clipboard

要将 ZRAM 配置为交换设备，请参阅 [zram: Compressed RAM-based block devices](https://www.kernel.org/doc/html/v6.6/admin-guide/blockdev/zram.html)。

### 扩展内存映射

若要扩展内存映射，可调整 DTSI 文件中内存区域的地址和大小。

使用以下信息扩展划分区域：

使用以下语法在 **reserved-memory** 节点中的 `arch/arm64/boot/dts/qcom/<SoC>-<board>-<variant>.dts` 文件中添加划分区域：

my_carveout_mem: my_carveout_mem@address {
          reg= <0x0 0xbase_address 0x0 0xsize>;
          no-map;
    }
    Copy to clipboard

例如：

my_carveout_mem: my_carveout_mem@d0800000 {
          reg= <0x0 0xd0800000 0x0 0x100000>;
          no-map;
    }
    Copy to clipboard

表：划分区域的语法

| 变量 | 说明 |
| --- | --- |
| my_carveout_mem@d0800000<br>    Copy to clipboard | 指示设备节点的名称。按照惯例，应将内存区域的基址附加到名称中。 |
| my_carveout_mem<br>    Copy to clipboard | 指示分配给此节点的标签，该标签可供设备树中的其他节点使用 phandle 引用此节点时使用。 |
| reg<br>    Copy to clipboard | 指示属性，该属性是一个 64 位值，用于定义内存区域的基址和大小。 |
| no-map<br>    Copy to clipboard | 指示此区域已划分，内核应从其可寻址范围中删除映射。 |

Note

- 任何区域都不应重叠。如果必须增大某个区域的大小，则移动所有其他后续区域，并在设备树中进行配置以避免重叠。
- 内核要求供内核使用的所有内存区域边界都对齐到 1 MB。
- 现有划分区域受受信任固件保护，防止内核访问。减小其大小或将其删除可能会导致外部中止，造成内核崩溃。

**添加 CMA 区域**

要在**保留内存**节点下的 `arch/arm64/boot/dts/qcom/<SoC>-<board>-<variant>.dts` 文件中添加 CMA 区域，请使用以下语法：

my_cma_mem: my_cma {
       compatible = "shared-dma-pool";
       alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>;
       reusable;
       alignment = <0x0 0x400000>;
       size = <0x0 0x1400000>;
    };
    Copy to clipboard

表：添加 CMA 区域的语法

| 参数 | 说明 |
| --- | --- |
| my_cma_mem<br>    Copy to clipboard | CMA 节点的标签，可用作 phandle。标签 `my_cma` 是 CMA 区域的名称。 |
| shared-dma-pool<br>    Copy to clipboard | 指示此区域是 CMA 区域。 |
| alloc-ranges<br>    Copy to clipboard | 指示此区域是否应处于某个特定的内存限制范围内，因为某些设备无法访问超过 32 位地址限制的内存区域。 |
| reusable<br>    Copy to clipboard | 指示内核可以在该内存区域空闲时使用其中的内存。 |
| alignment<br>    Copy to clipboard | 指示此区域中的任何对齐要求。 |
| size<br>    Copy to clipboard | 指示区域的大小： |
| reg<br>    Copy to clipboard | 这是一个可选属性，指示用于内存分配的固定区域，若不设置此属性，则以随机地址动态分配内存。 |

Last Published: Jul 22, 2025

[Previous Topic
配置远程处理器 (remoteproc) 子系统](https://docs.qualcomm.com/bundle/publicresource/80-70020-3SC/topics/remoteproc-overview.md) [Next Topic
配置调度程序](https://docs.qualcomm.com/bundle/publicresource/80-70020-3SC/topics/scheduler.md)