0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

为什么Linux操作寄存器要ioremap

麦辣鸡腿堡 来源:老吴嵌入式 作者:吴伟东Jack 2023-07-20 10:23 次阅读

1. 原因

  • 这里只考虑有 MMU 的芯片Linux 为了实现进程虚拟地址空间,在启用 MMU 后,在内核中操作的都是虚拟地址,内核访问不到物理地址。
  • 如果在驱动里直接访问物理地址,等于访问了一个非法地址,会导致内核崩溃,下面会有一个相关的小实验。
  • 通过 ioremap 将物理地址映射为虚拟地址后,内核就能通过 ioremap() 返回的虚拟地址,以 虚拟地址->mmu页表映射-> 物理地址 的形式正确地访问到物理地址了。
  • ARM Linux 引入设备树特性后,一些支持设备树的设备驱动不再使用直接 ioremap(),改用 drivers/of/address.c/of_iomap(),of_iomap() 的内部仍然会调用 ioremap(),例如:
clk-rk3288.c (driversclkrockchip)
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 initn");

#ifdef USE_IOREMAP
    gpio_regs = (volatile unsigned long *)ioremap(H3_GPIO_BASE, 1024);
#else
    gpio_regs = (volatile unsigned long *)H3_GPIO_BASE;
#endif

    for (i=0; i< 3; i++)
        printk(KERN_INFO "reg[%d] = %lxn", i, gpio_regs[i]);

    return 0;
}
module_init(ioremap_mod_init);

static void __exit ioremap_mod_exit(void)
{
    printk(KERN_INFO "ioremap_mod exitn ");

#ifdef USE_IOREMAP
    iounmap(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.ko

Unable 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)

[

3. ioremap() 的实现内幕

ioremap() 的实现内幕会涉及到比较多的内存管理的知识,这里我们抛开代码细节简单了解一下原理就好。

  • ioremap() 将 vmalloc 区的某段虚拟内存块映射到 io memory,其实现原理与vmalloc() 类似,都是通过在 vmalloc 区分配虚拟地址块,然后修改内核页表的方式将其映射到设备的 I/O 地址空间。
  • 与 vmalloc() 不同的是,ioremap 并不需要通过伙伴系统去分配物理页,因为ioremap 要映射的目标地址是 io memory,不是物理内存 (RAM)。

函数调用流程:

图片

总结一下:

  • 相关检查;
  • 分配一个 vm_struct 结构体,内核在管理虚拟内存中的 vmalloc 区时,内核必须跟踪哪些子区域被使用、哪些是空闲的,对应的数据结构就是 vm_strcut。
  • 初始化 vm_struct;
  • 建立页表;
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 芯片
    +关注

    关注

    455

    文章

    50818

    浏览量

    423719
  • 寄存器
    +关注

    关注

    31

    文章

    5343

    浏览量

    120385
  • Linux
    +关注

    关注

    87

    文章

    11304

    浏览量

    209537
收藏 人收藏

    评论

    相关推荐

    linux系统中内存分配基本原理分析

    访问外设的寄存器(一般包括数据寄存器、控制寄存器与状态寄存器),需要在驱动初始化中将外设所处的物理地址映射为虚拟地址,linux为应对该问题
    发表于 03-28 09:16 791次阅读

    寄存器是什么?怎么操作寄存器点亮LED灯?

    寄存器,是集成电路中非常重要的一种存储单元,通常由触发组成。在集成电路设计中,寄存器可分为电路内部使用的寄存器和充当内外部接口的寄存器这两
    的头像 发表于 07-21 16:59 4044次阅读
    <b class='flag-5'>寄存器</b>是什么?怎么<b class='flag-5'>操作</b><b class='flag-5'>寄存器</b>点亮LED灯?

    iTOP-4412开发板ioremap控制GPIO寄存器

    GPIO的读和写以及其它任意功能。 需要的基础知识虚拟地址和物理地址内存管理单元概念linux 驱动模块的加载 主要内容GPIO 的寄存器文档详细介绍和说明函数 ioremap的用法
    发表于 05-16 15:13

    寄存器操作方法的经验和其总结

    接触了一阵子的STM32函数库,使用起来挺方便的,但是很少有处理会有函数库,大部分情况下还是自己来对寄存器进行操作,所以还是不要生疏了对寄存器
    的头像 发表于 12-19 09:30 8760次阅读
    对<b class='flag-5'>寄存器</b><b class='flag-5'>操作</b>方法的经验和其总结

    寄存器操作方法_对寄存器操作的通用方法总结

    本文主要详解寄存器操作方法以及对寄存器操作的通用方法总结,具体的跟随小编来了解一下。
    的头像 发表于 05-22 15:53 2.3w次阅读

    寄存器变量

    C语言中使用关键字register来声明局部变量为寄存器变量。寄存器变量的值会被存放在CPU的寄存器中,每当需要使用它们时,CPU就可以直接使用,而无须再通过控制从内存中获取。由于
    发表于 06-03 10:13 2383次阅读

    C语言:寄存器操作

    C语言:寄存器操作
    发表于 01-13 12:56 6次下载
    C语言:<b class='flag-5'>寄存器</b><b class='flag-5'>操作</b>

    STM32的寄存器操作

    STM32的寄存器操作在使用STM32单片机编程时一般都用ST给的库函数编程,库函数编程的底层就是对单片机寄存器操作,库函数就是一系列寄存器
    发表于 01-13 15:43 19次下载
    STM32的<b class='flag-5'>寄存器</b><b class='flag-5'>操作</b>

    简述RAL寄存器模型基础

    RAL(Register Abstract Layer,寄存器抽象层),通常也叫寄存器模型,顾名思义就是对寄存器这个部件的建模。本文介绍的内容,包括对UVM
    的头像 发表于 02-14 16:55 2728次阅读
    简述RAL<b class='flag-5'>寄存器</b>模型基础

    RAL寄存器模型操作图鉴

    寄存器模型操作,指的是通过寄存器模型对RTL中寄存器进行读写访问,或者同步寄存器模型与RTL中寄存器
    的头像 发表于 05-17 09:01 942次阅读
    RAL<b class='flag-5'>寄存器</b>模型<b class='flag-5'>操作</b>图鉴

    RAL寄存器模型操作指南

    寄存器模型操作,指的是通过寄存器模型对RTL中寄存器进行读写访问,或者同步寄存器模型与RTL中寄存器
    的头像 发表于 07-12 09:37 1091次阅读
    RAL<b class='flag-5'>寄存器</b>模型<b class='flag-5'>操作</b>指南

    Linux驱动操作寄存器

    ,第四个参数是映射的大小。 驱动中操作: #define OFFSET  0x60 //某个寄存器的偏移地址 static int my_probe(struct platform_device
    的头像 发表于 09-26 16:34 832次阅读

    Linux应用层操作寄存器

    应用层操作寄存器 驱动中操作寄存器,需要先进行映射将物理地址转为虚拟地址。 但如果想在应用层中操作寄存器
    的头像 发表于 09-26 16:37 968次阅读

    如何在shell中操作寄存器

    shell 中操作寄存器可以使用 devmem 命令. devmem 命令其实就是上述应用层操作寄存器生成的可执行文件,只不过busybox已经帮我们实现了。 devmem 命令格式:
    的头像 发表于 09-26 16:39 1060次阅读

    Linux应用层操作寄存器

    --- > [*] /dev/mem virtual device support Linux应用层操作寄存器 除了直接使用devmem,我们也可以在Linux应用层自己实现一个de
    的头像 发表于 10-08 15:16 1226次阅读
    <b class='flag-5'>Linux</b>应用层<b class='flag-5'>操作</b><b class='flag-5'>寄存器</b>