鸿蒙高级——内存专用之linux-reserve-memory 方案简介
引言最近因为工作需求涉及到一些AI端侧推理加速的需求于是新学习了一个新的知识点。一、linux-reserve-memory 方案linux-reserve-memory 是 Linux 内核中用于预留内存机制。预留内存Reserved Memory 是一种机制用于预留特定物理内存区域使其不被内核的常规内存管理分配使用。这种内存通常用于专用硬件如GPU、DMA控制器或需要连续物理内存的关键任务。在某些场景下系统需要预先保留一部分内存以供特定的设备、驱动程序或者内核功能使用避免这部分内存被常规的内存分配器如 kmalloc、vmalloc 等分配出去linux-reserve-memory 机制就是为了满足这种需求而设计的。1、 使用场景设备特定需求一些硬件设备如摄像头、硬件加速器可能需要固定的、连续的物理内存区域来进行 DMA直接内存访问操作。例如图形处理单元GPU、高速网络接口卡等它们在工作时需要直接访问内存如果内存不连续或者被其他程序占用可能会导致性能下降或者出现错误。内核功能需求某些内核功能可能需要预先分配一块内存来存储关键数据或者执行特定的操作。例如内核日志缓冲区、内核调试信息存储区等。避免内存碎片为需要大块连续内存的设备如DMA预留区域。安全/实时性需求确保关键数据不被换出或覆盖如实时系统或安全模块。启动阶段保留在系统初始化时通过内核参数或设备树静态保留内存。2、配置linux-reserve-memory在 Linux 内核中预留内存通常通过设备树Device Tree或者内核命令行参数来配置。2.1、设备树方式设备树是一种描述硬件设备信息的数据结构在设备树中可以定义预留内存节点在设备树.dts 或 .dtsi 文件中定义 reserved-memory 节点。/reserved-memory { #address-cells 1; #size-cells 1; ranges; my-reserved-memory: my-memory10000000 { reg 0x10000000 0x1000000; /* 起始地址为 0x10000000大小为 16MB */ no-map; }; };启动后查看 /proc/iomem保留区域会标记为 reservedno-map内核不会将此区域映射到虚拟内存需驱动手动处理。reusable内存可被系统临时使用但需要时能释放如CMA。以上定义了一个名为 my-reserved-memory 的预留内存节点起始地址为 0x10000000大小为 0x1000000即 16MB。no-map 属性表示这部分内存不会被内核映射到虚拟地址空间除非有特定的驱动程序进行映射。除了上面这种方式还可以结合CMA连续内存分配器CMA, Contiguous Memory AllocatorCMA是一种动态保留机制内存平时可被普通进程使用但需要时能回收供设备使用。reserved-memory { linux,cma { compatible shared-dma-pool; reusable; size 0x4000000; // 64MB alignment 0x2000; linux,cma-default; // 设为默认CMA区域 }; };使用CMA驱动通过 dma_alloc_coherent() 或 dmam_alloc_coherent() 分配内存。2.2、内核命令行参数方式内核启动参数Boot Parameters除了设备树还可以通过内核命令行参数来预留内存语法memmap size start_address 。例如在 /boot/grub/grub.cfg 中添加以下参数mem1G memmap16M$1G这个参数表示系统总内存为 1GB从 1GB 地址处开始预留 16MB 的内存。3、内核代码中的使用预留内存步骤在 Linux 内核代码中可以通过以下步骤来使用预留内存保留内存需要驱动程序访问3.1、查找预留内存区域使用 of_reserved_mem_device_init 函数来初始化设备的预留内存区域。例如#includelinux/of_reserved_mem.hstaticintmy_driver_probe(structplatform_device*pdev){structreserved_mem*rmem;intret;retof_reserved_mem_device_init(pdev-dev);if(ret)returnret;rmemof_reserved_mem_lookup(pdev-dev);if(!rmem){dev_err(pdev-dev,No reserved memory found\n);return-ENODEV;}// 使用 rmem 进行后续操作// ...return0;}3.2、物理地址直接映射使用 ioremap() 或 memremap() 将物理地址映射到内核虚拟地址。如果需要将预留的物理内存映射到虚拟地址空间可以使用 ioremap 函数。#includelinux/io.hvoid*virt_addr;phys_addr_tphys_addrrmem-base;size_tsizermem-size;virt_addrioremap(phys_addr,size);if(!virt_addr){dev_err(pdev-dev,Failed to map reserved memory\n);return-ENOMEM;}3.3、DMA API通过 dma_alloc_coherent() 从CMA区域分配内存。4、验证保留内存查看 cat /proc/iomem 文件保留区域会显示为 reserved 或指定名称。10000000-101fffff : my-reserved-memory内核日志dmesg 会输出内存保留信息。CMA状态查看 cat /proc/meminfo 中的 CmaTotal 和 CmaFree。5、注意事项内存管理预留内存不会被内核的常规内存分配器管理因此需要驱动程序自己负责这部分内存的分配和释放。兼容性不同的硬件平台和内核版本可能对预留内存的配置和使用方式有所不同需要根据具体情况进行调整。错误处理在使用预留内存时需要进行充分的错误处理避免因内存分配失败或者映射失败导致系统崩溃。地址冲突确保保留区域不与现有内存或硬件地址重叠。大小对齐物理地址需按页对齐通常 4KB某些硬件可能需要更大对齐如2MB。性能影响过度保留内存可能减少系统可用内存影响性能。动态预留CMA适合需要灵活分配的场景而静态保留适合硬件强制要求固定地址的情况。7、普通进程访问保留内存的方法在Linux系统中普通应用程序用户空间进程不能直接访问保留内存因为保留内存通常由内核或专用硬件管理且用户空间与内核空间存在隔离。但通过以下方法可以间接或受限地访问保留内存7.1、内核空间访问推荐场景驱动/内核模块有以下几种方式7.1.1、映射物理内存到内核虚拟地址如果预留内存通过设备树标记为 no-map即内核不自动映射需通过 ioremap 或 memremap 手动映射。// 内核模块示例#includelinux/io.h#includelinux/module.hstaticvoid__iomem*reserved_mem;staticint__initmy_module_init(void){phys_addr_tphys_addr0x80000000;// 预留内存的物理地址size_tsize0x10000000;// 预留内存大小256MB// 映射物理内存到内核虚拟地址reserved_memioremap(phys_addr,size);if(!reserved_mem){pr_err(Failed to ioremap reserved memory\n);return-ENOMEM;}// 写入/读取示例writel(0x12345678,reserved_mem);// 写入32位数据pr_info(Read value: 0x%x\n,readl(reserved_mem));return0;}staticvoid__exitmy_module_exit(void){iounmap(reserved_mem);}module_init(my_module_init);module_exit(my_module_exit);7.1.2、直接物理地址访问DMA场景如果内存用于 DMA 操作如硬件加速卡可直接将物理地址传递给设备// 在设备驱动中设置 DMA 地址 dma_addr_t dma_handle phys_to_dma(dev, 0x80000000); dma_engine_start_transfer(dev, dma_handle, buffer_size);高度依赖需要加速卡驱动程序配合7.1.3、使用 CMAContiguous Memory Allocator如果预留内存标记为 shared-dma-pool动态分配连续内存// 从 CMA 区域分配内存structpage*cma_pages;cma_pagesdma_alloc_from_contiguous(dev,size,order);// 转换为虚拟地址void*virt_addrpage_to_virt(cma_pages);若保留内存是 CMA 区域可通过 DMA 接口分配内存并共享到用户空间步骤内核驱动分配 CMA 内存dma_addr_tdma_handle;void*cpu_addrdma_alloc_coherent(dev,size,dma_handle,GFP_KERNEL);用户空间映射通过 mmap 或 ioctl 将 DMA 缓冲区暴露给应用。7.2、 用户空间访问需谨慎控制权限有两种7.2.1、使用 /dev/mem 直接访问物理内存Linux 提供了 /dev/mem 设备文件允许有权限的进程直接读写物理内存但是有风险。首先启用 /dev/mem内核配置确保 CONFIG_STRICT_DEVMEM 未启用或通过 CAP_SYS_RAWIO 权限绕过限制。内核需启用 CONFIG_DEVMEM 和 CONFIG_STRICT_DEVMEM默认启用但可能限制访问。需要 root 权限或 CAP_SYS_RAWIO 能力。权限控制限制 /dev/mem 的访问权限chmod 600 /dev/mem。直接访问物理内存可能引发缓存一致性问题需使用 O_SYNC 标志。再映射物理地址int fd open(/dev/mem, O_RDWR | O_SYNC); void *addr mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, phys_addr);# 查看物理内存布局确认保留地址 sudo cat /proc/iomem # 使用 dd 读取物理内存示例地址 0x10000000 sudo dd if/dev/mem bs1 count4 skip$((0x10000000)) 2/dev/null | hexdump -C一个简单的例子#includesys/mman.h#includefcntl.h#defineRESERVED_PHYS_ADDR0x80000000#defineRESERVED_SIZE0x10000000intmain(){intfdopen(/dev/mem,O_RDWR|O_SYNC);if(fd-1){perror(open /dev/mem failed);return-1;}// 映射物理内存到用户空间void*memmmap(NULL,RESERVED_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,fd,RESERVED_PHYS_ADDR);if(memMAP_FAILED){perror(mmap failed);close(fd);return-1;}// 读写操作*((volatileuint32_t*)mem)0xdeadbeef;printf(Read value: 0x%x\n,*((volatileuint32_t*)mem));munmap(mem,RESERVED_SIZE);close(fd);return0;}也存在一些风险隐患系统稳定性误操作可能导致内核崩溃。安全漏洞恶意程序可能通过 /dev/mem 窃取敏感数据。内核配置限制CONFIG_STRICT_DEVMEM 默认阻止访问关键内存区域。7.2.2、通过 UIOUserspace I/O框架Linux UIOUserspace I/O框架 是一种允许在用户空间Userspace中实现设备驱动程序的机制。它通过将部分设备驱动逻辑如内存映射和中断处理从内核空间Kernelspace转移到用户空间简化了硬件访问流程同时减少了对内核模块开发的依赖。UIO 特别适合需要快速原型开发、实时性要求高或需要隔离用户空间与内核空间的场景更安全的用户空间访问方案需内核驱动支持UIO 框架将设备驱动分为两部分内核模块仅负责硬件的基本初始化、中断处理和物理内存映射。用户空间程序实现设备控制逻辑如读写寄存器、数据处理等。这种分离使得开发者无需编写复杂的内核代码即可操作硬件典型场景7.2.2.1、UIO 的主要功能内存映射将设备的物理内存映射到用户空间虚拟地址用户程序可直接访问硬件寄存器或内存区域。内核通过 uio_map 接口暴露内存地址用户程序通过 mmap 映射。中断处理内核侧捕获硬件中断并通知用户空间。用户侧通过 read 或 poll 监听中断事件如读取 /dev/uioX 设备文件。设备发现通过 sysfs 文件系统/sys/class/uio/uioX提供设备信息如内存区域、中断号等7.2.2.2、UIO 的使用步骤内核配置启用 UIO 支持CONFIG_UIOy # 基础 UIO 框架 CONFIG_UIO_PDRV_GENIRQy # 通用 UIO 平台驱动适用于设备树配置设备树配置通过设备树定义 UIO 设备以 FPGA 为例 / { reserved-memory { #address-cells 1; #size-cells 1; fpga_region: fpga80000000 { compatible shared-dma-pool; reg 0x80000000 0x1000000; // 16MB 保留内存 no-map; }; }; uio_fpga { compatible generic-uio; memory-region fpga_region; // 绑定到预留内存 interrupts 0 123 4; // 中断号示例 }; };加载 UIO 驱动加载通用 UIO 驱动或自定义内核模块# 加载通用 UIO 平台驱动 sudo modprobe uio_pdrv_genirq用户空间通过UIO访问7.2.3、通过内核驱动程序映射这是最安全和标准的方法需编写内核模块将保留内存暴露给用户空间7.2.3.1、编写内核驱动1.在驱动中申请保留内存如通过设备树预留的内存区域。2.创建字符设备并实现 mmap 操作将保留内存映射到用户空间。// 设备树中定义的保留内存区域staticstructresource*reserved_mem;staticvoid__iomem*mem_base;staticintmydev_mmap(structfile*filp,structvm_area_struct*vma){// 将物理内存映射到用户空间returnremap_pfn_range(vma,vma-vm_start,PFN_DOWN(reserved_mem-start),vma-vm_end-vma-vm_start,vma-vm_page_prot);}staticstructfile_operationsfops{.mmapmydev_mmap,};// 初始化模块时获取保留内存资源staticint__initmydev_init(void){reserved_memrequest_mem_region(0x10000000,0x200000,my_reserved_mem);mem_baseioremap(reserved_mem-start,resource_size(reserved_mem));// 注册字符设备...return0;}7.2.3.2、用户空间访问1.应用程序通过 open() 打开设备文件。2.使用 mmap() 系统调用将设备内存映射到进程的虚拟地址空间。#include fcntl.h #include sys/mman.h int main() { int fd open(/dev/mydevice, O_RDWR); void *addr mmap(NULL, 0x200000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); // 通过 addr 访问保留内存 munmap(addr, 0x200000); close(fd); return 0; }小结生产环境使用内核驱动程序通过 mmap 安全地暴露保留内存。临时调试谨慎使用 /dev/mem需关闭 CONFIG_STRICT_DEVMEM。硬件开发结合 UIO 框架实现用户空间驱动。

相关新闻

毕业论文初稿提纲极速搭建指南|拒当炮灰!社科生用智一刻4步搭建硬核逻辑框架

毕业论文初稿提纲极速搭建指南|拒当炮灰!社科生用智一刻4步搭建硬核逻辑框架

人文社科类同学在写毕业论文时,常常陷入这样一种极其尴尬的困境: 开题好不容易糊弄过去了,一到动笔写正文初稿,直接两眼一黑! 通宵折腾了几天,好不容易憋出了一个三级提纲目录发给导师,结果被…

2026/10/10 1:26:38 阅读更多 →
重读哈利波特:姓名、预言与魔法物件里的隐藏密码

重读哈利波特:姓名、预言与魔法物件里的隐藏密码

我第一次把这七本书连在一起重读时,感受和单本阅读完全不同。你明明已经知道结局,却会被第一本里的某句话、某样物件、某个名字击中心事。那不是传统意义的“悬念”,更准确的词是“秘密”——所有答案早就摊在读者面前了,只是第一…

2026/10/10 1:26:38 阅读更多 →
Ouroboros verify-gate 的 Windows 可移植性与 fat-harness 过度拒绝治理实战

Ouroboros verify-gate 的 Windows 可移植性与 fat-harness 过度拒绝治理实战

AI Agent人工智能代码智能体Agent 编排AI 评测CLI开发工具 【免费下载链接】ouroboros Agent OS: the agent gets smarter on its own. We just hold the line: Interview-gated, staged evaluation, budgeted evolution loop. MCP server, 14 runtimes: Claude Code, Codex CL…

2026/10/10 1:25:38 阅读更多 →

最新新闻

回溯算法综合练兵:组合总和、优美排列与状态机详解

回溯算法综合练兵:组合总和、优美排列与状态机详解

很多人学完递归就卡在回溯,原因只有一个:递归只需要一路向前,回溯还要学会高明的“后悔”。本次专题(五)正好到了综合练兵的中段,我用三个经典的搜索问题——组合总和、优美排列、状态机——把回溯的剪枝、…

2026/10/10 5:58:45 阅读更多 →
Python Flask实现车辆交易系统:从数据库设计到并发控制

Python Flask实现车辆交易系统:从数据库设计到并发控制

做车辆交易系统这个项目之前,我以为它跟一般的信息展示站差不多:后台录入车辆数据,前台列表展示,用户留下联系方式,完事了。真把需求和流程理完才发现,车辆交易的核心不止是“展示”,还牵涉车源…

2026/10/10 5:58:45 阅读更多 →
eNSP基础网络实验:从零搭建拓扑、排查AR1失败40与ping不通

eNSP基础网络实验:从零搭建拓扑、排查AR1失败40与ping不通

简介:基于华为eNSP仿真平台的基础网络搭建实验文档,面向计算机网络初学者及需要快速上手eNSP模拟器的学员。文档以“搭建基础网络”为线索,逐步覆盖启动eNSP、添加PC与S3700交换机、建立物理连接、完成主机名和静态IP配置,再到启动…

2026/10/10 5:58:45 阅读更多 →
一句指令搞定 TTS、编辑、分离:语音模型的“统一接口“叙事,会复制 LLM 的成功路径吗?

一句指令搞定 TTS、编辑、分离:语音模型的“统一接口“叙事,会复制 LLM 的成功路径吗?

一句指令搞定 TTS、编辑、分离:语音模型的"统一接口"叙事,会复制 LLM 的成功路径吗? 【免费下载链接】AuK 项目地址: https://ai.gitcode.com/tencent_hunyuan/AuK 当大语言模型用一句自然语言指令统一了翻译、摘要、代码生…

2026/10/10 5:58:45 阅读更多 →
一周狂涨2485星、51.1k星杀进周榜21:这本开源Agent书刚刚爆了

一周狂涨2485星、51.1k星杀进周榜21:这本开源Agent书刚刚爆了

一周狂涨2485星、51.1k星杀进周榜21:这本开源Agent书刚刚爆了 【免费下载链接】ai-agent-book 《深入理解 AI Agent:设计原理与工程实践》(李博杰 著)开源主仓库:全书正文、编译版 PDF 与按章配套代码 项目地址: htt…

2026/10/10 5:58:45 阅读更多 →
mergerfs 性能调优完全指南:从 IO 性能模型到缓存、线程与 passthrough.io 的实战配置

mergerfs 性能调优完全指南:从 IO 性能模型到缓存、线程与 passthrough.io 的实战配置

存储 【免费下载链接】mergerfs a featureful union filesystem 项目地址: https://gitcode.com/gh_mirrors/me/mergerfs 点击查看 免费下载 mergerfs 本质上是一个文件系统代理(proxy),它的理论性能上限就是底层分支设备的性能&…

2026/10/10 5:57:45 阅读更多 →

日新闻

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

1. 从“卫星轨道分类”这个标题说起:为什么值得花时间搞懂第一次接触“卫星轨道分类”这个概念,很多人会觉得它离自己很远——不就是天上的星星怎么转吗?但如果你正在做航天任务规划、遥感数据接收、星座设计,甚至只是准备一场航天…

2026/10/10 0:00:39 阅读更多 →
Spring AOP 核心原理与实战:从概念到日志切面落地

Spring AOP 核心原理与实战:从概念到日志切面落地

1. 从一个真实痛点说起:为什么你的代码里到处都是重复逻辑刚入行那会儿,我写过一个用户管理模块,注册、登录、改密码、注销四个接口。每个接口里都塞了几乎一样的日志打印、参数校验、事务开启和提交。当时觉得没什么,能跑就行。直…

2026/10/10 0:00:40 阅读更多 →
Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

简介:这是一套面向计算机相关专业学生与项目实战学习者的Python数据采集与分析可视化完整项目,以Boss直聘岗位数据为对象,适合用作毕业设计、课程设计或期末大作业。资源包共38个文件,约246KB,以13个py源码文件为核心&…

2026/10/10 0:00:40 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 1:36:08 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 10:11:06 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 5:23:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 6:17:20 阅读更多 →