我能在不同空间下操作寄存器,快学起来!

简介: 我能在不同空间下操作寄存器,快学起来!

大家好,我是Vincent。

大家都知道在linux中操作寄存器,都是驱动去做的。

但其实,驱动层、应用层和shell中都是可以操作寄存器的。

Linux驱动操作寄存器

首先在设备树里定义一个节点,例如:

uart0: serial@10010000 {
   compatible = "sifive,uart0";
   reg = <0x0 0x10010000 0x0 0x1000>;
   status = "okay";
}

@符号后面是寄存器的基地址,然后填写compatiblereg属性,status属性设置为okay

reg属性中,第二参数为寄存器基址,与@符号后面的地址对应,第四个参数是映射的大小。

驱动中操作:

#define OFFSET  0x60 //某个寄存器的偏移地址
static int my_probe(struct platform_device *pdev)
{
    struct resource *res;
    void __iomem *base;
    u32 regval;
    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    base = devm_ioremap_resource(&pdev->dev, res);
    //寄存器读写
    regval = readl(base + OFFSET);//读寄存器
    regval |= (1 << 0);//赋值
    writel(regval, base + OFFSET);//写寄存器
    return 0;
}

先调用platform_get_resource获取IORESOURCE_MEM资源,就是获取了设备树中的reg属性,返回的resource结构体中包含了起始地址和结束地址。然后调用devm_ioremap_resource映射这个资源,就能得到一个虚拟地址。后续对该虚拟地址的操作,就等同于对寄存器物理地址的操作。

读写寄存器,可以调用readlwritel函数。先读取寄存器的值放到临时变量中,赋值后,再一次性写入。

应用层操作寄存器

驱动中操作寄存器,需要先进行映射将物理地址转为虚拟地址。

但如果想在应用层中操作寄存器,也是可以实现的。

应用层中只需打开/dev/mem设备节点,然后用mmap映射寄存器地址就可以访问了。

例如,应用层读取物理地址为0x40000000的值:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#define MAP_SIZE 0x80000
#define base 0x40000000
int main(int argc, char **argv)
{
  int fd = open("/dev/mem",O_RDWR|O_NDELAY);
    if (fd < 0)
    {
        printf("open /dev/mem error!\n");
        return -1;
  }
    void *map_base = mmap(NULL,MAP_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,fd,base);
    if (map_base == MAP_FAILED)
    return -1;
    printf("%x \n",*(volatile unsigned int*)(map_base));
    close(fd);
    munmap(map_base,MAP_SIZE);
  return 0;
}

注意,内核必须将CONFIG_STRICT_DEVMEM=y配置选项打开才有/dev/mem节点

shell中操作寄存器

shell中操作寄存器可以使用devmem命令.

devmem命令其实就是上述应用层操作寄存器生成的可执行文件,只不过busybox已经帮我们实现了。

devmem命令格式:

Usage: devmem ADDRESS [WIDTH [VALUE]]
Read/write from physical address
 ADDRESS Address to act upon
 WIDTH Width (8/16/...)
 VALUE Data to be written

ADDRESS:物理地址

WIDTH:位宽,32位、64位等等

VALUE:要写入的值

例如,读取32位寄存器0x40200000的值:

devmem 0x40200000 32

向32位寄存器0x40200000写入0x12345678

devmem 0x40200000 32 0x12345678

end

关注我,回复【加群】,进入嵌入式技术交流群,一起交流学习~

猜你喜欢

机遇:我是如何走向Linux驱动的...

入职Linux驱动工程师后,我才知道的真相......

一个Linux驱动工程师必知的内核模块知识

Linux内核中常用的数据结构和算法

Linux内核中常用的C语言技巧

Linux内核基础篇——常用调试技巧汇总

Linux内核基础篇——动态输出调试

Linux内核基础篇——printk调试

Linux内核基础篇——initcall

嵌入式Linux充电站

作者Vincent,分享一些嵌入式Linux、内核、RISC-V等知识。学习、沉淀、分享,才能有所获。

74篇原创内容

公众号

收录于合集 #Linux驱动

30

上一篇当我用几道题考了一遍做Linux驱动的同事......下一篇嵌入式BSP工程师到底是干嘛的?

喜欢此内容的人还喜欢

那些只有芯片原厂才能做的驱动开发工作

 

嵌入式Linux充电站

相关文章
|
存储 编译器 C语言
C语言,数据在内存中的存储。——保姆级教学
C语言,数据在内存中的存储。——保姆级教学
|
6月前
|
存储 缓存 Linux
内存系列学习(三):ARM处理器地址变换过程
内存系列学习(三):ARM处理器地址变换过程
200 0
|
编译器 C语言
【C语言航路】第十三站:动态内存管理(上)
【C语言航路】第十三站:动态内存管理
75 0
|
C语言 C++ 容器
C语言指针练“级”题(相信我,让你的头发掉得值)
C语言指针练“级”题(相信我,让你的头发掉得值)
数据在内存中的存储(超级无敌究极详细!)
数据在内存中的存储(超级无敌究极详细!)
|
存储 C语言
【C语言进阶】纳尼?这样学数据在内存中的存储竟然如此简单(2)?
【C语言进阶】纳尼?这样学数据在内存中的存储竟然如此简单(2)?
242 0
|
存储 C语言
【C语言进阶】纳尼?这样学数据在内存中的存储竟然如此简单(1)?
【C语言进阶】纳尼?这样学数据在内存中的存储竟然如此简单(1)?
116 0
|
存储 安全 数据安全/隐私保护
骚操作:隐藏代码到数据区,函数指针【滴水逆向三期37笔记】
骚操作:隐藏代码到数据区,函数指针【滴水逆向三期37笔记】
|
C语言 C++
初始C语言——梦启程的地方
选择语句 if语句 if 单分支 if 多分支 循环语句 while 循环 函数 数组 操作符 关键字 typedef static #define定义常量和宏 结构体 总结
70 0
初始C语言——梦启程的地方
|
存储 小程序 编译器
【C/C++】庖丁解牛 深究数据在内存中如何存储
【C/C++】庖丁解牛 深究数据在内存中如何存储
169 0