# 配置和管理記憶體

Qualcomm^®^ Linux 核心基準支援所有記憶體管理功能和分配器。以下資訊概述如何自訂記憶體映射和執行堆管理。

欲深入瞭解 Linux 核心記憶體管理，請參閱 [Memory management](https://www.kernel.org/doc/html/next/core-api/index.html#memory-management)。

**記憶體映射**

記憶體映射描述在核心啟動過程中為子系統 (例如數據機、攝影機、aDSP 和 cDSP) 保留的區域。

記憶體映射為 DTSI 中的劃分區域設定 `no-map`，使內核無法存取它們。

在 `arch/arm64/boot/dts/qcom/qcs6490.dtsi` 檔案中的 `reserved-memory` 節點下定義可配置的劃分區域。

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

備註

針對 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

在 `reserved-memory` 節點下定義自訂 CMA 區域，與 `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-3TC/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

備註

為了支援頁面遷移，讓 CMA 區域與 4 MB 位址基數和大小一致。遷移在頁面區塊層級的 2 個 ^pageblock\_order^ 頁面進行。Qualcomm Linux 核心中的頁面區塊順序為 10。

### 支援的堆

下表列出 Qualcomm Linux 發行版預設支援的堆：

表：預設支援的堆

| 堆名稱 | 開發節點 | 說明 | 用途 |
| --- | --- | --- | --- |
| 系統 | /dev/dma_heap/system<br>    Copy to clipboard | 核心建立預設的 DMA-BUF 堆。 | 所有通用使用案例都必須遵循使用底層通用 Linux 記憶體管理夥伴分配器的系統堆。 |
| 保留 | /dev/dma_heap/reserved<br>    Copy to clipboard | 在系統中建立的預設 CMA 類型堆使用預設的 *reserved* 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 堆。

以下是範例程式，示範如何在 `/dev/dma_heap/system` 中使用 Qualcomm Linux 核心建立的 DMA-BUF 系統堆：

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 作為模組。

在 Yocto 建置的 `recipes-extended/zram/zram/zram-swap-init-update` 檔案中配置 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 檔案中調整記憶體區域的位址和大小。

根據以下資訊延伸劃分區域：

使用以下語法在 `arch/arm64/boot/dts/qcom/<SoC>-<board>-<variant>.dts` 檔案的 **reserved-memory** 節點中新增劃分區域：

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 | 表示此區域是劃分區域，核心應從可定址範圍中移除映射。 |

備註

- 區域不應重疊。如果必須增加區域大小，請移動所有其他後續區域，並在裝置樹中進行配置以避免重疊。
- 核心預期所有為核心使用定義的記憶體區域邊界為 1 MB。
- 現有的劃分區域受可信任韌體保護，防止核心存取。縮減大小或刪除區域可能導致外部中止，引發核心崩潰。

**新增 CMA 區域**

若要在 `arch/arm64/boot/dts/qcom/<SoC>-<board>-<variant>.dts` 檔案的 **reserved-memory** 節點下新增 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: Jan 01, 2026

[Previous Topic
配置遠端處理器 (remoteproc) 子系統](https://docs.qualcomm.com/bundle/publicresource/80-70020-3TC/topics/remoteproc-overview.md) [Next Topic
配置排程器](https://docs.qualcomm.com/bundle/publicresource/80-70020-3TC/topics/scheduler.md)