看起来应该
root@testbox:~# dd if=/dev/mem bs=1 count=4 skip=2149646336 | hd
几乎等于
root@testbox:~# devmem 2149646336 32
但是,虽然devmem
效果很好,但该dd
调用给我带来了段错误。对于许多其他 bs,skip 组合(在我尝试解决这个问题时偶然发现的) dd 成功返回,但数据与我期望的完全不同。所有这些都表明,当我使用 dd 时,我实际上并没有解决我认为我正在解决的问题。也许是一些内存映射问题?我是一个硬件专家,所以我只考虑物理地址。
一些血淋淋的细节:
我正在构建一个嵌入式系统,其中 Linux 运行在带有片上 ARM A53 内核的 Xilinx FPGA 上。我经常使用 devmem 来读取或写入 FPGA 逻辑中的内存映射寄存器。我想使用 dd 而不是 devmem 通过一个命令读取一长串地址,并将数据保存到文件或通过管道将其传输到另一个进程。
我的 FPGA 设计有一个内部 RAM 块,可读写,映射到字节地址0x80210000
。
我写了一个shell脚本,如下所示:
devmem 0x80210000 32 0x5AB000CD
devmem 0x80210004 32 0x5AB001CD
devmem 0x80210008 32 0x5AB002CD
devmem 0x8021000C 32 0x5AB003CD
... etc etc <250 more lines> ...
devmem 0x802103F8 32 0x5AB0FECD
devmem 0x802103FC 32 0x5AB0FFCD
它只是用一些可识别的乱码填充了我的块 RAM 的第一个 KB。执行该 shell 脚本后,我可以使用 devmem 从该内存中读取单词。
root@testbox:~# devmem 2149646336 32
0x5AB000CD
root@testbox:~# devmem 2149646340 32
0x5AB001CD
root@testbox:~# devmem 2149646344 32
0x5AB002CD
root@testbox:~# devmem 2149646348 32
0x5AB003CD
到目前为止,一切都很好。
请注意:
0x80210000 = 2149646336 十进制
和
0x80210000 / 16 = 134352896 十进制
接下来我尝试使用以下命令读取相同的 4 个单词的内存dd
:
root@testbox:~# dd if=/dev/mem of=/tmp/junk1 bs=1 count=16 skip=2149646336
或
root@testbox:~# dd if=/dev/mem of=/tmp/junk1 bs=16 count=1 skip=134352896
诸如此类。
这些行中的任何一行都会给我带来段错误。我尝试过许多其他的 bs、skip 等组合,试图找到我的内存块。
dd
其他“成功”的调用。例如:
root@testbox:~# dd if=/dev/mem bs=16 count=1 skip=2149646336 | hd
1+0 records in
1+0 records out
16 bytes copied, 0.00032236 s, 49.6 kB/s
00000000 ff ff fd ba 85 ff 4c ce ff ff bd df e4 d5 9d ed |......L.........|
00000010
但我不认识这个数据。我想我只是从我的 DRAM 中的谁知道的地方读取。
for 的寻址dd if=/dev/mem
与 for 的寻址不同吗devmem
?
答案1
部分答案:
如果你devmem
来自 busybox,它使用/dev/mem读取和写入值,所以你应该得到相同的结果。
也就是说,请注意,单位skip
是块(bs
字节),因此bs=16 count=1 skip=2149646336
不会在 0x80210000 处读取,而是在 0x802100000 处读取,这可能会包装到 0x02100000。
由于跳过的 MSB 是 1,因此如果源代码和/或编译器中的某处存在有符号/无符号混淆,也可能会搞砸。
所以我要做的第一件事是使用类似于bs=16 skip=134352896
.如果仍然失败,我要做的第二件事是编写一个小型 C 程序,直接读取/dev/mem
并验证是否那作品。
答案2
这确实是一个符号错误(对于busybox版本):
if (skip) {
if (lseek(ifd, skip * ibs, SEEK_CUR) < 0) {
do {
ssize_t n = safe_read(ifd, ibuf, ibs);
if (n < 0)
goto die_infile;
if (n == 0)
break;
} while (--skip != 0);
}
}
lseek()
返回文件偏移量(2149646336),该偏移量被转换为int32
负数(-2145320960),因此dd
认为这是一个错误代码。然后,它从文件中读取所有字节,直到给定偏移量,以尝试实现基本查找。这意味着读取总线上从 0 到您的地址的所有字节,这只会导致麻烦。
您可以尝试dd
通过检查返回值是否是有效的错误代码(-1 到 -4095 之间的任何值)来修复,但是编写自己的 C 程序可能比再次编译 busybox 更快。
顺便说一句,devmem
用于mmap()
阅读/dev/mem
略有不同。