Linux操作寄存器前为什么要ioremap

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/467100.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Loading页的实现代码

用了几种Loading页的代码&#xff0c;还是算这个好用了。真的佩服牛人们的思想。有的说用DIV来实现遮盖后面的东西&#xff0c;当FORM加载完后&#xff0c;执行CLOSE()d的JS函数。我试验了几次&#xff0c;效果不是那么好。也主要是由于我吧东西都放在我本地&#xff0c;感觉不…

Fibonacci数列

问题描述Fibonacci数列的递推公式为&#xff1a;FnFn-1Fn-2&#xff0c;其中F1F21。 当n比较大时&#xff0c;Fn也非常大&#xff0c;现在我们想知道&#xff0c;Fn除以10007的余数是多少。 输入格式输入包含一个整数n。输出格式输出一行&#xff0c;包含一个整数&#xff0c;表…

C语言——关键字

C语言——关键字 宗旨&#xff1a;技术的学习是有限的&#xff0c;分享的精神是无限的。 【谨记&#xff1a;尽量不要用printf函数&#xff0c;要去看变量的值&#xff0c;内存的值。】 auto&#xff0c;int&#xff0c;double&#xff0c;long&#xff0c;char&#xff0c;fl…

调色板栅格数据使用GDAL时注意

这几天用GDAL处理DRG数据时发现&#xff0c;有数据被处理成了黑板&#xff0c;什么都没有&#xff0c;发现是因为DRG图像颜色比较简单&#xff0c;使用了调色板的缘故。 使用SetColorTable将调色板写入后&#xff0c;一部分基本正常&#xff0c;但还有些图像还是有黑板的现象。…

jQuery实现表格行上移下移和置顶

<!DOCTYPE HTML> <html> <head> <meta charset"utf-8"> <meta name"viewport" content"widthdevice-width, initial-scale1, maximum-scale1"> <title>jQuery实现表格行上移下移和置顶</title> <m…

做算法,为什么建议你一定要学懂C++?

在工业界&#xff0c;有这样一个规律&#xff1a;“ 但凡能用其他语言的都不会用C&#xff0c;只能用C的必然用C。”但是&#xff0c;C的学习和项目开发都比较困难。一个有经验的老手也经常搞出野指针&#xff0c;内存泄露等bug&#xff0c;包括我自己在学C的时候也非常痛苦。所…

顺序查找法

#include<stdio.h> #define KeyType int #define OtherType int #define List_size 100 typedef struct{KeyType key;OtherType other; }RecordType; typedef struct{RecordType r[List_size];int length; }Recordlist; int SeqSearch(Recordlist l,int k)//没有设置监视…

IT行业专业术语

IT行业专业术语 宗旨&#xff1a;技术的学习是有限的&#xff0c;分享的精神是无限的。 目前比较流行的开发语言有哪些&#xff1f; Java、C#(C Sharp)、C、C、JavaScript、PHP、Ruby、Python等 WEB端有哪些开发技术&#xff1f; Javascript、CSS、HTML、Ajax、Flex等 比较…

AI一键注释代码、阅读整个项目、转换编程语言。已开源!

获取github源码地址和国内url、key方式&#xff1a;在文章底部 大家好今天给大家介绍一款开源项目&#xff0c;这个项目是由渡码维护的&#xff0c;这个项目支持自己的大模型和使用openai两种方式&#xff0c;本文章介绍使用openai的方式&#xff01; 使用过程中发现两个问题…

为什么别人赚钱比自己容易?

之前的文章提到自己的一个同事&#xff0c;在一家公司干了10年&#xff0c;最近跳槽找了份5万薪水的工作&#xff0c;大家都很想听他的故事。为了方便记录&#xff0c;我叫他文哥文哥比我们一般的毕业生厉害&#xff0c;他比我大将近9岁&#xff0c;我在初中的时候他已经是一个…

Linux下遍历目录下的文件

方法1&#xff1a;http://tag.csdn.net/Article/ef431d9b-68b3-419f-9f85-1fb9279f904a.html//ListFile.cpp#include <stdio.h>#include <dirent.h>#include <sys/types.h>intmain(intargc, char*argv[]){ if (2 ! argc){ printf("Usage:ListFileSource…

折半查找

折半查找又为二分查找&#xff0c;对待查找的列表有两个要求&#xff1a;1.必须采用顺序存储结构。 2.必须按关键字大小顺序排列。 #include<stdio.h> #define Max 100 typedef struct {int key;int other; }RecordType; typedef struct {RecordType r[Max];int lenght; …

15张图来了解【树】,面试再也不怕被刷了

我之前的文章C语言实现树&#xff0c;你一定看得懂树的概念什么是树&#xff1f;树属于非线性数据结构的一种&#xff0c;概念也极多&#xff0c;是由结点或顶点和边组成的且不存在着任何环的一种数据结构。没有结点的树称为空树。一棵非空的树包括一个根结点&#xff0c;还很可…

String源码图

String StringBuffer StringBuilder 均为对字符数组的操作。 实现了不同的接口&#xff0c;导致不同的覆写。 实现了同样的接口&#xff0c;适应不同的场景。 转载于:https://www.cnblogs.com/zhengwenqiang/p/8076495.html

C语言——位操作

C语言——位操作 宗旨&#xff1a;技术的学习是有限的&#xff0c;分享的精神是无限的。 一、基本位操作 | 或 & 与 ~ 取反 ^ 异或 << 左移 >> 右移 二、位操作的常见用法 1.获取某位的值 #define BitGet(Number,pos) ((Number)| 1<<(…

架构设计中的方法学(七)

十三、代码验证   要保证架构的稳定和成功&#xff0c;利用代码对架构进行验证是一种实用的手段。代码验证的核心是测试&#xff0c;特别是单元测试。而测试的基本操作思路是测试优先&#xff0c;它是敏捷方法中非常重要的一项实践&#xff0c;是重构和稳定核模式的重要保障。…

十进制转二进制,八进制,十六进制

十进制转二进制&#xff1a; #include<stdio.h> int main() {int a[20],x;int rem,i0;scanf("%d",&x);do{remx%2;xx/2;a[i]rem;i;}while(x!0);while(i>0)printf("%d",a[--i]);printf("\n");return 0; }十进制转八进制&#xff1a; …

呵,你会51单片机的精确延时吗?

文章整理自网络序对于某些对时间精度要求较高的程序&#xff0c;用 c 写延时显得有些力不从心&#xff0c;故需用到汇编程序。本人通过测试&#xff0c;总结了 51 的精确延时函数(在 c 语言中嵌入汇编)分享给大家。至于如何在 c 中嵌入汇编大家可以去网上查查&#xff0c;这方面…

SignalR

原址: http://www.cnblogs.com/shanyou/archive/2012/07/28/2613693.html SignalR是什么&#xff1f; SignalR是一个继承的客户端与服务器库&#xff0c;基于浏览器的客户端和基于ASP.NET的服务器组件可以借助它来进行双向多步对话&#xff0c;换句话说&#xff0c;该对话可不…

C语言——数组、函数、指针

C语言——数组、函数、指针 宗旨&#xff1a;技术的学习是有限的&#xff0c;分享的精神是无限的。 1、有什么作用&#xff1f;为什么要使用它们&#xff1f; &#xff08;1&#xff09;数组&#xff1a;提供一段连续的存储空间&#xff0c;存数据和字符串很方便&#xff1b; …