今天分享一个内核调试实用工具——devmem。
相信很多做底层驱动的人都会经常用到。
什么是devmem?
在Linux系统,如果我们想要访问某个寄存器,就需要写一个驱动程序,在驱动中映射寄存器地址,转为虚拟地址后就可以访问。
但有时候,我们只是单纯想知道某个寄存器的值,不想这么麻烦,怎么办呢?
Linux早就想到这一点了,于是提供了一个工具devmem,通过devmem就可以直接读写寄存器,
devmem是一个命令,在shell中输入devmem命令就可以非常方便的读写寄存器。
如何使用devmem?
devmem命令格式:
Usage: devmem ADDRESS [WIDTH [VALUE]]Read/write from physical addressADDRESS Address to act uponWIDTH 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
可以看到,devmem的使用非常简单,有了devmem就可以轻松访问寄存器。
内核配置devmem
devmem命令依赖于/dev/mem设备节点,需要在Linux内核中打开/dev/mem的配置:
Device Drivers --->Character devices --->[*] /dev/mem virtual device support
Linux应用层操作寄存器
除了直接使用devmem,我们也可以在Linux应用层自己实现一个devmem。
devmem的实现原理,就是打开/dev/mem,然后通过mmap映射物理地址,从而实现读写寄存器。因此,我们只要实现这些操作,就可以自己实现类似devmem的功能。
例如,在Linux应用层读取物理地址为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 0x40000000int 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;
}
总结
devmem是一个很常用的工具,主要给驱动开发人员在Linux应用层调试使用。devmem不仅仅是访问寄存器,只要有权限访问某个物理地址,就可以使用devmem,方便我们调试。