当前位置: 首页 > article >正文

嵌入式Linux驱动开发(8)——内存映射 I/O - 别拿物理地址当指针用

嵌入式Linux驱动开发8——内存映射 I/O - 别拿物理地址当指针用仓库已经开源所有教程主线内核移植跑新版本imx-linux/uboot都在这里欢迎各位大佬观摩喜欢的话点个⭐仓库地址https://github.com/Awesome-Embedded-Learning-Studio/imx-forge静态网页https://awesome-embedded-learning-studio.github.io/imx-forge/上一章我们介绍了硬件的基本原理知道了要控制 LED 需要读写哪些寄存器。如果你之前写过单片机程序比如 STM32可能会习惯性地写出这样的代码#defineGPIO1_DR(*(volatileu32*)0x0209C000)*GPIO1_DR0;// 点亮 LED说实话在裸机环境下这确实没问题。因为在裸机程序里物理地址和虚拟地址是一一对应的或者说根本没有虚拟地址的概念。但在 Linux 这样的操作系统环境下这行代码会让你收获一个非常漂亮的内核 panic。我们得搞清楚为什么。首先Linux 运行在虚拟地址空间里CPU 访问内存前需要通过 MMU 把虚拟地址转换成物理地址。我们直接写一个物理地址 0x0209C000在内核看来这可能指向任何地方——可能是某个内核数据结构可能是用户空间内存甚至可能是一个未映射的地址。其次即使地址能对应上我们也没有考虑缓存一致性问题。所以我们需要一种机制安全地把物理地址映射到内核虚拟地址空间然后通过虚拟地址来访问寄存器。这个机制就是ioremap()。先别急着看代码我们先搞清楚两个概念MMIOMemory-Mapped I/O和 PMIOPort-Mapped I/O。这两种是 CPU 与外设交互的不同方式。PMIO 方式下外设寄存器有独立的地址空间称为 I/O 端口需要用专门的指令如 x86 的 in/out来访问。而 MMIO 方式下外设寄存器被映射到内存地址空间可以像访问内存一样用普通的 load/store 指令访问。ARM 架构只支持 MMIO没有独立的 I/O 端口空间所以我们所有的寄存器访问都是通过内存映射来实现的。现在我们来拆解ioremap()做了什么。它的功能可以概括为一句话建立物理地址到虚拟地址的映射。但这个简单的功能背后内核做了一系列复杂的工作。在 ARM 架构下ioremap()的调用链大致是这样的ioremap() - arch_ioremap_caller() - __ioremap() - get_vm_area() 分配虚拟地址空间 - ioremap_page_range() 建立页表映射 - ioremap_pte_range() 填充页表项。内核首先需要在内核地址空间中找到一块连续的虚拟地址区域这是通过get_vm_area()实现的它会在 vmalloc 区域里找到合适的空间。找到虚拟地址空间后内核需要建立页表项把这块虚拟地址映射到我们指定的物理地址。这一步的核心工作是设置页表项的属性。对于设备寄存器映射页表项会被设置为MT_DEVICE类型这个类型有几个重要属性非缓存、不可合并、强有序。非缓存意味着数据不会被 CPU 缓存为什么因为缓存可能延迟写回而我们写寄存器时希望立即生效。更严重的是如果 CPU 缓存了寄存器的读结果下次再读时可能拿到的是旧值。不可合并意味着 CPU 不会把多次访问合并成一次这对设备访问很重要因为有些设备寄存器的读操作有副作用。强有序意味着访问严格按照程序顺序执行不会被乱序执行优化打乱。页表修改完成后需要刷新 TLBTranslation Lookaside Buffer页表缓存确保 CPU 使用新的映射关系。iounmap()是ioremap()的逆向操作它负责清理映射关系。主要做的事情包括查找对应的 vm_area 结构、清除页表映射、释放虚拟地址空间、刷新 TLB。这里有个常见的错误点很多人知道要ioremap()但忘了在模块卸载时调用iounmap()。长期积累下来会造成内核地址空间泄漏。虽然每次泄漏的空间不大只有几页但这是不合格的驱动代码应该避免的问题。你可能会问既然已经映射好了为什么不直接用指针读写为什么非要用writel()和readl()这就涉及到内存屏障的问题了。现代 CPU 和编译器都会进行各种优化包括指令重排、缓存优化等。对于普通内存访问这些优化是安全的因为有缓存一致性协议保证。但对于设备寄存器访问这些优化可能导致严重问题。我们来看一个具体的场景*addr1value1;// 写寄存器1启动 DMA*addr2value2;// 写寄存器2设置 DMA 地址编译器或 CPU 可能会交换这两条指令的顺序。如果寄存器 2 的值必须在 DMA 启动前设置好重排就会导致错误。编译器还可能会优化掉一些它认为没必要的访问。比如对于设备寄存器有些写操作是有副作用的不能被优化掉。writel()和readl()就是用来解决这些问题的。让我们看看writel()的实现简化版staticinlinevoidwritel(u32 value,volatilevoid__iomem*addr){__io_bw();// 写前屏障__raw_writel(value,addr);__io_aw();// 写后屏障}__io_bw()和__io_aw()就是内存屏障它们做了两件事阻止编译器优化告诉编译器这条指令前后的内存访问不能乱序阻止 CPU 乱序在汇编层面插入屏障指令确保 CPU 按顺序执行。在 ARM64 的实现中这会插入dmbData Memory Barrier指令。writel()和readl()还会处理端序转换大多数外设使用小端序而 ARM 架构可能是大端或小端所以内部会调用cpu_to_le32()把 CPU 端序转换为小端序。你可能注意到了writel()内部调用了__raw_writel()。这个 “raw” 版本是什么__raw_writel()是不做任何屏障的原始写操作它的 ARM 实现非常简洁staticinlinevoid__raw_writel(u32 val,volatilevoid__iomem*addr){asmvolatile(str %1, %0::Qo(*(volatileu32 __force*)addr),r(val));}就是一条str指令把值写到内存地址。这里的 “Qo” 约束确保地址是正确对齐的并且不使用写回寻址模式。一般我们不直接使用__raw_writel()除非我们清楚自己在做什么并且有自己管理内存屏障的方案。现在我们结合实际的 LED 驱动代码看看怎么用的staticvoid__iomem*IMX6U_CCM_CCGR1NULL;staticvoid__iomem*GPIO1_DRNULL;// 映射寄存器IMX6U_CCM_CCGR1ioremap(kCCM_CCGR1_BASE,sizeof(u32));GPIO1_DRioremap(kGPIO1_DR_BASE,sizeof(u32));// 访问寄存器u32 valreadl(IMX6U_CCM_CCGR1);// 读writel(val|0b1126,IMX6U_CCM_CCGR1);// 写// 清理映射iounmap(IMX6U_CCM_CCGR1);iounmap(GPIO1_DR);这里有几个需要注意的点。实际工程中一定要检查ioremap()的返回值如果映射失败比如物理地址无效它会返回 NULL直接使用 NULL 指针会导致内核崩溃。ioremap()的第二个参数是映射大小建议按实际需要映射虽然多映射一点不会造成功能问题但会浪费内核虚拟地址空间。对于单个 32 位寄存器映射sizeof(u32)或 4 字节就足够了。Linux 内核提供了多种寄存器访问函数有 8 位的 readb/writeb、16 位的 readw/writew、32 位的 readl/writel、64 位的 readq/writeq。根据寄存器位宽选择对应函数我们的 LED 寄存器都是 32 位的所以用readl()和writel()。到这里我们已经理解了内存映射 I/O 的完整机制。知道了为什么不能直接用指针访问物理地址知道了ioremap()如何建立映射知道了writel()/readl()如何保证访问顺序和正确性。下一章我们会把这些知识应用到实际代码中看看硬件抽象层是如何设计并实现的。相关阅读深入理解Linux模块——第1章 Hello World内核模块内核编程的第一步 - 相似度 80%入门 · 环境搭建 · 00 · Qt6 安装踩坑指南 - 相似度 80%现代Qt开发——0.1——如何在IDE中配置Qt环境 - 相似度 80%

相关文章:

嵌入式Linux驱动开发(8)——内存映射 I/O - 别拿物理地址当指针用

嵌入式Linux驱动开发(8)——内存映射 I/O - 别拿物理地址当指针用 仓库已经开源!所有教程,主线内核移植,跑新版本imx-linux/uboot都在这里!欢迎各位大佬观摩!喜欢的话点个⭐! 仓库地…...

观察 Taotoken 在不同时段与模型下的服务稳定性与可用性

观察 Taotoken 在不同时段与模型下的服务稳定性与可用性 1. 长期使用体验概述 作为长期使用 Taotoken 的开发者,我们在过去六个月中持续通过 API 调用各类主流模型,覆盖了工作日白天、晚间以及周末等不同时段。整体而言,平台提供的统一接入…...

SoC测试太头疼?试试SSN:一个让DFT工程师告别布线噩梦和测试时间浪费的“解耦”神器

SoC测试效率革命:SSN如何重构DFT工程师的工作流 在28nm以下工艺节点,单个SoC集成超过200亿晶体管已成为常态。某头部芯片厂商的DFT团队曾向我展示过一组数据:他们的5nm移动SoC中,仅扫描链布线就占用了12%的全局布线资源&#xff…...

python reStructuredText

# Python Docutils 的那些事 它到底是什么 在Python生态里有这么一个库,它诞生得比很多框架都要早,但做文档相关的人基本绕不开它。这个库就是Docutils。说得通俗点,它就是一套能把纯文本转换成各种格式文档的工具。 你可能会想到Markdown…...

R语言自动化报告革命:用`tidyreport`+`gt::tab_source_note()`实现“写一次,导出N格式”(附GitHub私藏模板库)

更多请点击: https://intelliparadigm.com 第一章:R语言自动化报告革命的范式跃迁 传统报表生成依赖人工导出、复制粘贴与格式调整,不仅耗时易错,更难以应对高频迭代的数据需求。R语言凭借其原生的统计计算能力与丰富的报告生态&…...

Koin 开发者炸了!7 条规则根治运行时错误,自动扫描太香了

编译零警告,测试全绿,上线直接炸。 用过 Koin 的人或多或少都经历过这种场景——NoBeanDefFoundException 在某个不起眼的页面突然蹦出来,而你根本不知道是哪个依赖没注册。 这不是 Bug,是 Koin 的"特性"。它的运行时解…...

医疗DevSecOps终极防线(Docker 27合规认证黄金三角模型):eBPF运行时鉴权 + OCI Artifact签名 + 医疗专用CVE-2024补丁基线

更多请点击: https://intelliparadigm.com 第一章:医疗DevSecOps终极防线与Docker 27合规认证黄金三角模型概览 在医疗信息化高速演进的当下,DevSecOps不再仅是效率工具,而是贯穿等保2.0、GDPR、HIPAA及中国《医疗器械软件注册审…...

3步部署方案:开源内存注入技术实现英雄联盟皮肤自定义

3步部署方案:开源内存注入技术实现英雄联盟皮肤自定义 【免费下载链接】R3nzSkin-For-China-Server Skin changer for League of Legends (LOL) 项目地址: https://gitcode.com/gh_mirrors/r3/R3nzSkin-For-China-Server R3nzSkin是一款专为英雄联盟国服设计…...

BetterNCM安装器:3分钟解锁网易云音乐插件生态的终极方案

BetterNCM安装器:3分钟解锁网易云音乐插件生态的终极方案 【免费下载链接】BetterNCM-Installer 一键安装 Better 系软件 项目地址: https://gitcode.com/gh_mirrors/be/BetterNCM-Installer 你是否厌倦了网易云音乐PC版一成不变的界面和有限的功能&#xff…...

COMTool终极指南:5个步骤快速掌握跨平台串口调试工具

COMTool终极指南:5个步骤快速掌握跨平台串口调试工具 【免费下载链接】COMTool Cross platform communicate assistant(Serial/network/terminal tool)( 跨平台 串口调试助手 网络调试助手 终端工具 linux windows mac Raspberry Pi )支持插件…...

在多轮对话应用中观察通过聚合路由后的API稳定性表现

在多轮对话应用中观察通过聚合路由后的API稳定性表现 1. 多轮对话场景的技术挑战 开发需要连续调用大模型进行多轮对话的应用时,稳定性是核心考量因素之一。这类应用通常需要维持较长的会话周期,期间可能涉及数十次甚至上百次的API调用。在实际工程实践…...

Dolphin模型:深度学习在多说话人语音分离中的突破

1. 多说话人语音分离的技术挑战语音分离技术是音频信号处理领域的重要研究方向,特别是在多人同时说话的嘈杂环境中,如何准确分离出每个说话人的独立语音流一直是个棘手问题。传统方法主要基于以下两种技术路线:基于麦克风阵列的波束形成技术基…...

终极指南:如何使用ROFL-Player轻松管理英雄联盟回放文件

终极指南:如何使用ROFL-Player轻松管理英雄联盟回放文件 【免费下载链接】ROFL-Player (No longer supported) One stop shop utility for viewing League of Legends replays! 项目地址: https://gitcode.com/gh_mirrors/ro/ROFL-Player 英雄联盟回放分析工…...

突破平台壁垒的革命性方案:跨平台模组下载终极指南

突破平台壁垒的革命性方案:跨平台模组下载终极指南 【免费下载链接】WorkshopDL WorkshopDL - The Best Steam Workshop Downloader 项目地址: https://gitcode.com/gh_mirrors/wo/WorkshopDL 你是否曾在Epic Games Store或GOG平台购买了心仪的游戏&#xff…...

终极游戏串流指南:如何用Sunshine打造你的个人云游戏服务器

终极游戏串流指南:如何用Sunshine打造你的个人云游戏服务器 【免费下载链接】Sunshine Self-hosted game stream host for Moonlight. 项目地址: https://gitcode.com/GitHub_Trending/su/Sunshine 还在为高性能游戏设备的高昂成本而烦恼吗?想要在…...

OpenProject:为什么这个开源项目管理软件能提升团队协作效率65%?

OpenProject:为什么这个开源项目管理软件能提升团队协作效率65%? 【免费下载链接】openproject OpenProject is the leading open source project management software. 项目地址: https://gitcode.com/GitHub_Trending/op/openproject 在数字化转…...

别再只盯着ESP了!聊聊让底盘变‘聪明’的幕后功臣:高度与加速度传感器

底盘智能化的神经末梢:高度与加速度传感器如何重塑驾乘体验 当一辆豪华轿车以60公里时速驶过减速带时,后排乘客的咖啡几乎纹丝不动——这种被称为"魔毯悬挂"的体验背后,是数十个微型传感器以每秒上千次的频率在监测车身动态。与普遍…...

3分钟掌握particles.js:为你的网站注入动态粒子魔法

3分钟掌握particles.js:为你的网站注入动态粒子魔法 【免费下载链接】particles.js A lightweight JavaScript library for creating particles 项目地址: https://gitcode.com/gh_mirrors/pa/particles.js 还在为网站背景单调乏味而烦恼吗?parti…...

低代码集成进入深水区:Dify自定义Connector开发规范V2.3(含OpenAPI 3.1 Schema校验工具链)

更多请点击: https://intelliparadigm.com 第一章:低代码集成进入深水区:Dify自定义Connector开发规范V2.3(含OpenAPI 3.1 Schema校验工具链) 随着企业级AI工作流对异构系统集成能力的要求持续升级,Dify平…...

2026年4月30日

🔬 科技1. 谷歌豪掷400亿美元追投Anthropic,AI"御三家"格局重塑谷歌宣布向Anthropic投入最高400亿美元,100亿美元立即到账,估值按3800亿美元计算——这比一年前翻了好几倍。有意思的是,谷歌一边押注"竞…...

Illustrator脚本终极指南:20个免费工具快速提升设计效率

Illustrator脚本终极指南:20个免费工具快速提升设计效率 【免费下载链接】illustrator-scripts Adobe Illustrator scripts 项目地址: https://gitcode.com/gh_mirrors/il/illustrator-scripts 在当今快节奏的设计行业中,Adobe Illustrator设计师…...

【2026企业级缓存治理黄金标准】:基于17家头部客户压测报告的Dify缓存调优清单

更多请点击: https://intelliparadigm.com 第一章:Dify 2026缓存治理的演进逻辑与黄金标准定义 随着 LLM 应用规模化部署,Dify 平台在 2026 版本中重构了缓存治理体系——从“响应级静态快照”跃迁至“语义感知动态分层缓存”,核…...

神池:高原沃土生胡麻,胡油醇香飘古今

在晋西北黄土高原的腹地,神池县静卧于北纬38黄金油料种植带,平均海拔超1500米,山高气寒、光照充沛、昼夜温差悬殊。这片土地孕育的神池胡麻油,从东汉至今近两千年种植史,五百余年压榨传承,是国家地理标志保…...

企业如何利用Taotoken的多模型聚合能力优化内部知识问答系统

企业如何利用Taotoken的多模型聚合能力优化内部知识问答系统 1. 多模型聚合的核心价值 企业内部知识问答系统通常需要处理多样化的查询场景,从技术文档检索到人力资源政策解读,不同任务对模型能力的需求存在显著差异。单一模型往往难以在所有场景下保持…...

SolidWorks草图绘制避坑指南:几何关系、剪裁与等距实体,新手最易犯的5个错误

SolidWorks草图绘制避坑指南:几何关系、剪裁与等距实体,新手最易犯的5个错误 刚接触SolidWorks的工程师们,是否经常遇到这样的场景:明明按照教程一步步操作,草图却频繁报错?约束冲突的红标不断闪现&#xf…...

OpenCV车牌识别避坑指南:为什么你的字符总分割错?聊聊铆钉、汉字与verifyCharSize

OpenCV车牌识别实战:从字符分割到参数调优的深度解析 车牌识别系统在实际部署时,开发者常会遇到字符分割不准确、汉字识别率低等问题。本文将聚焦三个关键环节:铆钉干扰消除的阈值设定、字符尺寸验证的参数优化以及汉字轮廓的特殊处理&#x…...

别再手动复制了!飞书文档跨账号迁移的3个高效技巧与1个隐藏功能

飞书文档跨账号迁移的高阶操作手册:从基础到深度优化 引言:为什么需要更高效的文档迁移方案? 在团队协作频繁变动的现代办公环境中,文档账号迁移已成为许多飞书用户的刚需场景。无论是个人账号切换、部门重组还是外包交接&#xf…...

独立开发者如何通过透明计费与多模型选择优化个人AI项目预算

独立开发者如何通过透明计费与多模型选择优化个人AI项目预算 1. 个人AI开发中的预算挑战 对于独立开发者或学生群体而言,个人AI项目的预算管理往往面临两个核心痛点。首先是模型选择单一化问题,当开发者仅能接入单一供应商的API时,既无法横…...

Windows 7环境下iperf3网络测试工具完整兼容性解决方案:从崩溃问题到实战应用

Windows 7环境下iperf3网络测试工具完整兼容性解决方案:从崩溃问题到实战应用 【免费下载链接】iperf3-win-builds iperf3 binaries for Windows. Benchmark your network limits. 项目地址: https://gitcode.com/gh_mirrors/ip/iperf3-win-builds 网络性能测…...

3步让你的Windows桌面拥有macOS般优雅体验:鼠标指针美化实战指南

3步让你的Windows桌面拥有macOS般优雅体验:鼠标指针美化实战指南 【免费下载链接】macOS-cursors-for-Windows Tested in Windows 10 & 11, 4K (125%, 150%, 200%). With 2 versions, 2 types and 3 different sizes! 项目地址: https://gitcode.com/gh_mirro…...