devmem源码很短,网上可以下载到,有devmem和devmem2两个版本
devmem源码地址:https://www.cnblogs.com/sky-heaven/p/13597581.html
devmem2源码地址:http://sources.buildroot.net/devmem2.c

busybox中的devmem

busybox是Linux一个调试工具箱,里面包含了devmem及其他工具,可以以命令行的方式调用工具
下载及使用方法如链接及下文https://www.icode9.com/content-3-744746.html

wget https://busybox.net/downloads/binaries/1.31.0-defconfig-multiarch-musl/busybox-x86_64
cp busybox-x86_64 /usr/local/bin/busybox
chmod +x /usr/local/bin/busybox
busybox

devmem原理:这个工具的原理也比较简单,就是应用程序通过mmap函数实现对/dev/mem驱动中mmap方法的使用,映射了设备的内存到用户空间,实现对这些物理地址的读写操作。

[root@delete mem]# busybox devmem
BusyBox v1.31.0 (2019-06-10 15:54:54 CEST) multi-call binary.

Usage: devmem ADDRESS [WIDTH [VALUE]]

Read/write from physical address

	ADDRESS	Address to act upon
	WIDTH	Width (8/16/...)
	VALUE	Data to be written

使用

[root@delete mem]# busybox devmem 123456 64
0x0000000000000000
[root@delete mem]# busybox devmem 123456 64 1
[root@delete mem]# busybox devmem 123456 64
0x0000000000000001
[root@delete mem]# busybox devmem 1 64
0xC3F000FF53F000FF
[root@delete mem]# busybox devmem 1 64 1
[root@delete mem]# busybox devmem 1 64
0x0000000000000001

[root@delete mem]# busybox devmem read 0xfa0000 20
devmem: invalid number '0xfa0000'
[root@delete mem]# busybox devmem read fa0000 20
devmem: invalid number 'fa0000'
[root@delete mem]# busybox devmem 0x97000000 64 
devmem: mmap: Operation not permitted

[用法]
Usage: devmem ADDRESS [WIDTH [VALUE]]
读取:在地址0x97000000读取32bit值(WIDTH默认等于32, 可选值为[8, 16, 32, 64])
/dev # devmem 0x97000000 
0x11111111
读取:在地址0x97000000读取16bit值
/dev # devmem 0x97000000 16
0x1111

写入:在地址0x97000000写入32bit值0x7777ABCD
/dev # devmem 0x97000000 32 0x7777ABCD
/dev # devmem 0x97000000              
0x7777ABCD

注意:如果/dev下没有mem这个node,会出现错误:
/dev # devmem 0x97000000 
devmem: can't open '/dev/mem': No such file or directory

这时可以在Host系统中手动创建一个(例如在NFS root filesystem模式):
host@host-laptop:~/embedded/tftpboot/nfsroot/dev$ sudo mknod mem -m666 c 1 1
注意这里的权限是666,允许任何人任意读写,可以很好的配合程序debug。

/dev # devmem 0x97000000
0x7777ABCD

devmem源码编译成工具

https://blog.csdn.net/leon_zeng0/article/details/83099809?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-1.no_search_link&spm=1001.2101.3001.4242.2

[root@delete mem]# ./devmem_o 0xff w 0
/dev/mem opened.
Memory mapped at address 0x7f001978d000.
Value at address 0xFF (0x7f001978d0ff): 0x4A2FAAF0
Written 0x0; readback 0x0
[root@delete mem]# ./devmem_o 0xff w 
/dev/mem opened.
Memory mapped at address 0x7fcc48c0e000.
Value at address 0xFF (0x7fcc48c0e0ff): 0x0

[root@delete mem]# ./devmem_o 0x123456 16
/dev/mem opened.
Error at line 85, file devmem_o.c (1) [Operation not permitted]

在上面busybox中的devmem命令中的WIDTH的几种取值和这里的whb是一致的
第3个参数控制读写的宽度只能是 w(32位), h(16位), b(8位)。

衍生工具

链接里作者自己写的代码,用devmem的原理实现了物理内存读写工具
https://www.cnblogs.com/sky-heaven/p/13597581.html
对源码编译 gcc -o devmem_tool devmem.c

* 读取内存数据: ./devmem_tool read 0xfa0000 20
* 读取内存物理地址 0xfa0000作为起始地址,一共读取20个4字节,共计 20 * 4 = 80 字节。
* 写入内存数据: ./devmem_tool write 0xfa0000 20
* 写入内存物理地址 0xfa0000作为起始地址,一共写入20个4字节,共计 20 * 4 = 80 字节。

但是同示例的地址在我虚拟机报错了
[root@delete mem]# ./devmem_tool read 0xfa0000 20
read data
Error at line 142, file devmem.c (1) [Operation not permitted]
address = 0x00fa0000, data = 0x00000000
address = 0x00fa0004, data = 0x00000000
address = 0x00fa0008, data = 0x00000000
address = 0x00fa000c, data = 0x00000000
address = 0x00fa0010, data = 0x00000000
address = 0x00fa0014, data = 0x00000000
address = 0x00fa0018, data = 0x00000000
address = 0x00fa001c, data = 0x00000000
address = 0x00fa0020, data = 0x00000000
address = 0x00fa0024, data = 0x00000000
address = 0x00fa0028, data = 0x00000000
address = 0x00fa002c, data = 0x00000000
address = 0x00fa0030, data = 0x00000000
address = 0x00fa0034, data = 0x00000000
address = 0x00fa0038, data = 0x00000000
address = 0x00fa003c, data = 0x00000000
address = 0x00fa0040, data = 0x00000000
address = 0x00fa0044, data = 0x00000000
address = 0x00fa0048, data = 0x00000000
address = 0x00fa004c, data = 0x00000000

修改地址可用
[root@delete mem]# ./devmem_tool read 0x0000ff 20
read data
address = 0x000000ff, data = 0x4a2faaf0
address = 0x00000103, data = 0x000d56ea
address = 0x00000107, data = 0x00f065f0
address = 0x0000010b, data = 0x002667f0
address = 0x0000010f, data = 0x000d56c0
address = 0x00000113, data = 0x000d56f0
address = 0x00000117, data = 0x000d56f0
address = 0x0000011b, data = 0x000d56f0
address = 0x0000011f, data = 0x000d56f0
address = 0x00000123, data = 0x000d56f0
address = 0x00000127, data = 0x000d56f0
address = 0x0000012b, data = 0x000d56f0
address = 0x0000012f, data = 0x000d56f0
address = 0x00000133, data = 0x000d56f0
address = 0x00000137, data = 0x000d56f0
address = 0x0000013b, data = 0x000d56f0
address = 0x0000013f, data = 0x000d56f0
address = 0x00000143, data = 0x000d56f0
address = 0x00000147, data = 0x000d56f0
address = 0x0000014b, data = 0x000d56f0

还有个更好的
http://www.wowotech.net/soft/186.html

使用难点

  1. 确保地址格式,地址范围是合法的
  2. 目前看都是对一个地址单独操作,怎么批量操作或者按段连续地读写

局限性

有些地址能访问,有些地址Operation not permitted
[root@delete ~]# busybox devmem 0xffff11 64
devmem: mmap: Operation not permitted
原因是Linux有些限制,只能读取一定范围地址空间的数据,大了就不行。

网上搜了些解决此问题的方法

要修改内核源码,重新编译
https://stackoverflow.com/questions/8213671/mmap-operation-not-permitted
https://blog.csdn.net/qq_30025621/article/details/108362715
http://xilinx.eetrend.com/content/2020/100059177.html
https://www.it1352.com/1560850.html
https://blog.csdn.net/prike/article/details/73691183
It sounds like the kernel has been compiled with CONFIG_STRICT_DEVMEM enabled. This is a security feature to prevent user space access to (possibly sensitive) physical memory above 1MB (IIRC). You might be able to disable this with sysctl dev.mem.restricted.

使用devmem 操作System RAM时,出现devmem: mmap: Operation not permitted的错误,原因为 内核的 mem.c文件中,限制了,所以在 mem.c文件中 将 #ifdef CONFIG_STRICT_DEVMEM 改为 #if 0 即可

在driver中通过alloc_pages申请得到的page,将page的物理地址export到userspace,但是user space拿到这个
物理地址后并不能mmap成功。通过perror(“mmap”),发现总是返回错误"Operation notpermitted!",后来发现是
由于kernel对userspace访问/dev/mem是有限制的,通过编译选项:CONFIG_STRICT_DEVMEM来限制user space
对物理内存的访问,这个选项的说明在arch/x86/Kconfig.debug中有说明:
config STRICT_DEVMEM
bool “Filteraccess to /dev/mem”
—help—
If this option is disabled, you allow userspace (root) access toall
of memory, including kernel and userspace memory. Accidental
access to this is obviously disastrous, but specific accesscan
be used by people debugging the kernel. Note that with PATsupport
enabled, even in this case there are restrictions on /dev/mem
use due to the cache aliasing requirements.
If this option is switched on, the /dev/mem file only allows
userspace access to PCI space and the BIOS code and dataregions.
This is sufficient for dosemu and X and all common users of
/dev/mem.
If in doubt, say Y.
只有在.config文件中设置CONFIG_STRICT_DEVMEM=n才能获得对整个memory的访问权限,在默认情况下,
CONFIG_STRICT_DEVMEM=y,这也就是之前mmap总是报错:“Operation notpermitted”的原因。
设置这个选项后,编译kernel,然后运行tool,mmap还是返回错误:“Invalidargument”。后来查到还需要设置
编译选项CONFIG_X86_PAT=n,这个选项也是默认开启的,但是要关闭这个选项还需要开启CONFIG_EXPERT,
否则CONFIG_X86_PAT总是关不掉。

设置好这三个编译选项后,重新编译kernel,然后运行tool,发现kernel已经解除了对mmap的访问限制,可以
正确读取对应物理地址的内容了。
最后还可以通过修改内核源代码来实现,具体的源文件时在/drivers/char/目录下的mem.c文件
static inlineint range_is_allowed(unsignedlong pfn, unsigned long size);

相关链接

https://blog.csdn.net/gatieme/article/details/50964903
https://blog.csdn.net/xy010902100449/article/details/47028497?locationNum=10&utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_title~default-0.no_search_link&spm=1001.2101.3001.4242.1
https://www.cnblogs.com/tinylaker/p/9823517.html

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐