如何使用 dd if=/dev/mem 代替 devmem ?

如何使用 dd if=/dev/mem 代替 devmem ?

看起来应该
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略有不同。

相关内容