1. 原因

  • 这里只考虑有 MMU 的芯片,Linux 为了实现进程虚拟地址空间,在启用 MMU 后,在内核中操作的都是虚拟地址,内核访问不到物理地址。

  • 如果在驱动里直接访问物理地址,等于访问了一个非法地址,会导致内核崩溃,下面会有一个相关的小实验。

  • 通过 ioremap 将物理地址映射为虚拟地址后,内核就能通过 ioremap() 返回的虚拟地址,以 虚拟地址->mmu页表映射-> 物理地址 的形式正确地访问到物理地址了。

  • ARM Linux 引入设备树特性后,一些支持设备树的设备驱动不再使用直接 ioremap(),改用 drivers/of/address.c/of_iomap(),of_iomap() 的内部仍然会调用 ioremap(),例如:

clk-rk3288.c (drivers\clk\rockchip)
static void rk3288_clk_init(struct device_node *np) {rk3288_cru_base = of_iomap(np, 0);[...]
}

2. ioremap() 实验

实验环境:

  • Linux-4.14 + Allwinner/H3。

实验代码:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <asm/io.h>#define USE_IOREMAP#define H3_GPIO_BASE (0x01C20800)static volatile unsigned long *gpio_regs = NULL;static int __init ioremap_mod_init(void)
{int i = 0;printk(KERN_INFO "ioremap_mod init\n");#ifdef USE_IOREMAPgpio_regs = (volatile unsigned long *)ioremap(H3_GPIO_BASE, 1024);
#elsegpio_regs = (volatile unsigned long *)H3_GPIO_BASE;
#endiffor (i=0; i<3; i++)printk(KERN_INFO "reg[%d] = %lx\n", i, gpio_regs[i]);return 0;
}
module_init(ioremap_mod_init);static void __exit ioremap_mod_exit(void)
{printk(KERN_INFO "ioremap_mod exit\n ");#ifdef USE_IOREMAPiounmap(gpio_regs);
#endif
}module_exit(ioremap_mod_exit);MODULE_AUTHOR("es-hacker");
MODULE_LICENSE("GPL v2");

实验结果:

使用了 ioremap()

$ insmod ioremap
ioremap_mod init
reg[0] = 71227722
reg[1] = 33322177
reg[2] = 773373

未使用 ioremap():

$ insmod ioremap_mod.koUnable to handle kernel paging request at virtual address 01c20800
pgd = c9ece7c0
[01c20800] *pgd=6ddd7003, *pmd=00000000
Internal error: Oops: 206 [#1] SMP ARM
CPU: 1 PID: 1253 Comm: insmod Tainted: G           O    4.14.111 #116
Hardware name: sun8i
task: ef15d140 task.stack: edc50000
PC is at ioremap_mod_init+0x3c/0x1000 [ioremap_mod]
LR is at ioremap_mod_init+0x14/0x1000 [ioremap_mod]
pc : [<bf5d903c>]    lr : [<bf5d9014>]    psr: 600e0013
sp : edc51df8  ip : 00000007  fp : 118fa95c
r10: 00000001  r9 : ee7056c0  r8 : bf5d6048
r7 : bf5d6000  r6 : 00000000  r5 : bf5d6200  r4 : 00000000
r3 : 01c20800  r2 : 01c20800  r1 : 00000000  r0 : bf5d5048
Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment user
Control: 30c5387d  Table: 49ece7c0  DAC: b106c794
Process insmod (pid: 1253, stack limit = 0xedc50210)[<bf5d903c>] (ioremap_mod_init [ioremap_mod]) from [<c0201a70>] (do_one_initcall+0x40/0x16c)
[<c0201a70>] (do_one_initcall) from [<c02b20c8>] (do_init_module+0x60/0x1f0)
[<c02b20c8>] (do_init_module) from [<c02b1214>] (load_module+0x1b48/0x2250)
[<c02b1214>] (load_module) from [<c02b1ad8>] (SyS_finit_module+0x8c/0x9c)
[<c02b1ad8>] (SyS_finit_module) from [<c0221f80>] (ret_fast_syscall+0x0/0x4c)
Code: e5953000 e3050048 e1a01004 e34b0f5d (e7932104)
---[ end trace 928c64a33a054308 ]---
Segmentation fault

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

#推荐阅读:

专辑|Linux文章汇总

专辑|程序人生

专辑|C语言

嵌入式Linux

微信扫描二维码,关注我的公众号 

Linux操作寄存器前为什么要ioremap相关推荐

  1. 字符设备驱动高级篇5——静态映射表、动态映射结构体方式操作寄存器

    以下内容源于朱有鹏<物联网大讲堂>课程的学习整理,如有侵权,请告知删除. 一.静态映射表建立过程分析 1.建立映射表的三个关键部分 (1)映射表描述 具体物理地址和虚拟地址的值相关的宏定义 ...

  2. Linux操作系统分析 | 深入理解系统调用

    Linux操作系统分析 | 深入理解系统调用 实验要求 1.找一个系统调用,系统调用号为学号最后2位相同的系统调用 2.通过汇编指令触发该系统调用 3.通过gdb跟踪该系统调用的内核处理过程 4.重点 ...

  3. Linux操作系统管理公共基础——积累

    20170609 16:00 备注:本篇博文,借鉴新浪博客中用博文积累文学知识.英语词汇的好习惯的成功养成,这里同样是一篇知识积累型的博文,用于记录任何.各种关于Linux系统技术的新发现.这些技术多 ...

  4. Linux操作系统分析——课程总结报告

    一.Linux系统的启动过程 1.POST开机自检 linux开机加电后,系统开始开机自检,该过程主要对计算机各种硬件设备进行检测,如CPU.内存.主板.硬盘.CMOS芯片等,如果出现致命故障则停机, ...

  5. Linux操作系统分析-课程总结报告

    一.结合虚拟化技术分析Linux系统的一般执行过程 a. 一个 Linux 系统在虚拟化技术中的一般执行过程: 用户登录:当用户登录到 Linux 系统时,系统会创建一个用户会话. 系统启动:Linu ...

  6. Linux操作系统分析------期末总结、感谢老师、祝我们越来越好

    王雪 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 一.博客目录: 1.第一 ...

  7. linux优先级继承和优先级天花板,关于Linux操作系统内核原理.ppt

    <铁机>Linux操作系统内核原理 Linux内核基础 第一事业部 王 风 内容 进程管理 内存管理 虚拟文件系统 了解Linux内核核心功能的基本原理结构,引导源码阅读 Linux系统结 ...

  8. Hadoop综合大作业补交4次作业:获取全部校园新闻,网络爬虫基础练习,中文词频统计,熟悉常用的Linux操作...

    1.用Hive对爬虫大作业产生的文本文件(或者英文词频统计下载的英文长篇小说)进行词频统计. (1)开启所有的服务,并创建文件夹wwc (2)查看目录下所有文件 (3)把hdfs文件系统中文件夹里的文 ...

  9. linux操作系统分析实验—基于mykernel的时间片轮转多道程序实现与分析

    linux操作系统分析实验-基于mykernel的时间片轮转多道程序实现与分析 学号384 原创作业转载请注明出处+中国科学技术大学孟宁老师的Linux操作系统分析 https://github.co ...

最新文章

  1. springboot(十八):使用Spring Boot集成FastDFS
  2. java静态方法 问题_Java中堆、栈,静态方法和非静态方法的速度问题
  3. js 对一个字段去重_JS单行、多行文本字符去重和行去重
  4. python中pow_python – 为什么pow(x,y)的时间复杂度为O(1),而x ** y为O(n)?
  5. mysql 优化之 is null ,is not null 索引使用测试
  6. VC6.0 +WDK 开发驱动的环境配置
  7. Java数据结构的知识体系
  8. ps_基础技术提升topic基础知识调研
  9. 大数据平台数据挖掘的作用是什么
  10. electron build报错,nsis下载不下来的情况
  11. ZigBee-CC2530单片机 - 实现外部电压值的测量
  12. 制作一个美团饿了么外卖的cps小程序
  13. xsmax进入dfu模式_DFU模式是什么?苹果XR/XS Max的DFU模式进入与退出方法[多图]
  14. 电子签约存证及印章管理整体化解决方案
  15. 图像算法工程师面试考点集锦
  16. 关于阿里云aca和acp哪个好?阿里云认证证书有含金量吗?
  17. 让极客精神成为自然:DefCon China看这一篇就够了
  18. java左手画圆右手画方_左手画圆右手画方900字作文
  19. 计算机键盘时好时坏,机子的CTRL键时好时坏?
  20. 网络-4 【http状态码、accept、Content-Type】

热门文章

  1. springmvc 1
  2. mysql query cache
  3. 基于web的新闻发布系统_终极Linux系统ExTiX 19.8发布,基于深度操作系统deepin15.11...
  4. 项目宝提供的服务器,开源WebSocket服务器项目宝贝鱼CshBBrain V4.0.1 和 V2.0.2发布
  5. SQLAlchemy()分页器paginate方法
  6. Pycharm 专业版 导入系统pip安装的包
  7. grid autosport额外内容下载慢_清理大王app下载-清理大王v1.0安卓下载
  8. python静态方法,类方法,属性方法,实例方法
  9. 编写的windows程序,崩溃时产生crash dump文件的办法
  10. cocostuff10k数据集介绍_(六)COCO数据集的简单介绍