1. 原因
- 这里只考虑有 MMU 的芯片,Linux 为了实现进程虚拟地址空间,在启用 MMU 后,在内核中操作的都是虚拟地址,内核访问不到物理地址。
- 如果在驱动里直接访问物理地址,等于访问了一个非法地址,会导致内核崩溃,下面会有一个相关的小实验。
- 通过 ioremap() 将物理地址映射为虚拟地址后,内核就能通过 ioremap() 返回的虚拟地址,以 虚拟地址->mmu页表映射-> 物理地址 的形式正确地访问到物理地址了。
- ARM Linux 引入设备树特性后,一些支持设备树的设备驱动不再使用直接 ioremap(),改用 drivers/of/address.c/of_iomap(),of_iomap() 的内部仍然会调用 ioremap(),例如:
clk
2. ioremap() 实验
实验环境:
- Linux-4.14 + Allwinner/H3。
实验代码:
#include
实验结果:
使用了 ioremap()
$
未使用 ioremap():
pgd
3. ioremap() 的实现内幕
ioremap() 的实现内幕会涉及到比较多的内存管理的知识,这里我们抛开代码细节简单了解一下原理就好。
- ioremap() 将 vmalloc 区的某段虚拟内存块映射到 io memory,其实现原理与vmalloc() 类似,都是通过在 vmalloc 区分配虚拟地址块,然后修改内核页表的方式将其映射到设备的 I/O 地址空间。
- 与 vmalloc() 不同的是,ioremap() 并不需要通过伙伴系统去分配物理页,因为ioremap() 要映射的目标地址是 io memory,不是物理内存 (RAM)。
函数调用流程:
总结一下:
- 相关检查;
- 分配一个 vm_struct 结构体,内核在管理虚拟内存中的 vmalloc 区时,内核必须跟踪哪些子区域被使用、哪些是空闲的,对应的数据结构就是 vm_strcut。
- 初始化 vm_struct;
- 建立页表;
4. 相关参考
- 深入理解 Linux 内核 / 8.3.2
- 深入 Linux 内核架构 / 3.5.7
- 深入理解Linux设备驱动程序内核机制 / 3.5.3
- https://blog.csdn.net/njuitjf/article/details/40745227
5. 参与讨论
关于嵌入式软件软件(应用/驱动)开发,大家都遇到过哪些经典的面试题呢?快抛出来一起讨论吧~
你和我各有一个苹果,如果我们交换苹果的话,我们还是只有一个苹果。但当你和我各有一个想法,我们交换想法的话,我们就都有两个想法了。
对 嵌入式系统 (Linux、RTOS、OpenWrt、Android) 和 开源软件 感兴趣,关注公众号:嵌入式Hacker。
觉得文章对你有价值,不妨点个 在看和赞。