在运行 Linux 的基于 ARM 的系统上,我有一个内存映射到物理地址的设备。从所有地址都是虚拟的用户空间程序中,我如何从该地址读取内容?
最佳答案
busybox devmem
busybox devmem
是一个用于映射 /dev/mem
的小型 CLI 实用程序。
你可以在 Ubuntu 中使用:sudo apt-get install busybox
用法:从物理地址0x12345678
中读取4个字节:
sudo busybox devmem 0x12345678
将 0x9abcdef0
写入该地址:
sudo busybox devmem 0x12345678 w 0x9abcdef0
来源:https://github.com/mirror/busybox/blob/1_27_2/miscutils/devmem.c#L85
mmap MAP_SHARED
在映射 /dev/mem
时,您可能希望使用:
open("/dev/mem", O_RDWR | O_SYNC);
mmap(..., PROT_READ | PROT_WRITE, MAP_SHARED, ...)
MAP_SHARED
使写入立即进入物理内存,这样更容易观察,对硬件寄存器写入更有意义。
CONFIG_STRICT_DEVMEM
和 nopat
要使用/dev/mem
查看和修改内核v4.9上的常规RAM,您必须拳头:
- 禁用
CONFIG_STRICT_DEVMEM
(在 Ubuntu 17.04 上默认设置) - 为 x86 传递
nopat
内核命令行选项
没有这些,IO 端口仍然可以工作。
参见:mmap of /dev/mem fails with invalid argument for virt_to_phys address, but address is page aligned
缓存刷新
如果您尝试写入 RAM 而不是寄存器,则内存可能会被 CPU 缓存:How to flush the CPU cache for a region of address space in Linux? 并且我没有看到一种非常便携/简单的方法来刷新它或将该区域标记为不可缓存:
- How to write kernel space memory (physical address) to a file using O_DIRECT?
- How to flush the CPU cache for a region of address space in Linux?
- Is it possible to allocate, in user space, a non cacheable block of memory on Linux?
那么可能无法可靠地使用 /dev/mem
将内存缓冲区传递给设备?
很遗憾,这在 QEMU 中无法观察到,因为 QEMU 不模拟缓存。
如何测试它
现在是有趣的部分。以下是一些很酷的设置:
- Userland memory
- 在用户态进程上分配
volatile
变量 - 使用
/proc/<pid>/maps
+/proc/<pid>/pagemap
获取物理地址 - 用
devmem
修改物理地址的值,观察用户态进程的 react
- 在用户态进程上分配
- Kernelland memory
- 使用
kmalloc
分配内核内存 - 使用
virt_to_phys
获取物理地址并将其传回用户区 - 用
devmem
修改物理地址 - 从内核模块查询值
- 使用
- IO mem and QEMU virtual platform device
- 创建具有已知物理寄存器地址的平台设备
- 使用
devmem
写入寄存器 - 观看
printf
响应从虚拟设备中出来
奖励:确定虚拟地址的物理地址
Is there any API for determining the physical address from virtual address in Linux?
关于linux - 如何从 Linux 中的用户空间访问物理地址?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12040303/