1. 为什么需要预留内存
在Linux内核驱动开发中,我们经常会遇到一些特殊场景需要独占使用特定物理内存区域。比如某些高性能设备(如图形处理器、硬件编解码器)需要大块连续物理内存来保证DMA操作的效率;安全敏感模块需要隔离内存防止被篡改;嵌入式系统中某些外设寄存器区域需要固定映射地址。
传统的内存分配方式(如kmalloc、vmalloc)存在几个局限性:
- 无法保证物理地址连续性(特别是大块内存)
- 分配区域可能被其他模块占用或回收
- 无法精确控制内存的物理地址范围
提示:在嵌入式视频处理系统中,摄像头采集的4K视频帧往往需要60MB以上的连续物理内存,普通分配方式在系统运行一段时间后几乎无法满足需求。
2. 内核中的预留内存实现机制
2.1 设备树配置方法
现代Linux内核主要通过设备树(Device Tree)来声明预留内存区域。典型配置如下:
dts复制/reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
ranges;
custom_reserved: buffer@0x30000000 {
compatible = "shared-dma-pool";
reg = <0x0 0x30000000 0x0 0x10000000>;
no-map;
};
};
关键参数解析:
reg属性:前两个数字表示起始地址(0x30000000),后两个表示大小(0x10000000=256MB)no-map:内核不会将该区域映射到虚拟地址空间shared-dma-pool:允许多个设备共享该内存池
2.2 内核启动参数方式
对于早期内核或x86平台,可以通过bootloader传递参数:
text复制memmap=256M$0x30000000
这表示从0x30000000开始保留256MB内存。注意这种方式需要与物理内存布局配合使用,避免与其他区域冲突。
3. 驱动中访问预留内存
3.1 获取预留内存区域
在驱动代码中,可以通过以下方式获取设备树中声明的内存区域:
c复制s
