How to use dd if=/dev/mem in place of devmem

dddevicesembeddedmmap

It seems like
root@testbox:~# dd if=/dev/mem bs=1 count=4 skip=2149646336 | hd
should be nearly equivalent to
root@testbox:~# devmem 2149646336 32

But, while devmem works great, that dd invocation gives me a segfault.
For many other bs,skip combinations (found by accident during my attempt to figure this out) dd successfully returns, but the data is nothing like what I'm expecting.
All of this suggests I'm not actually addressing where I think I'm addressing, when I use dd. Some memory-mapping issue perhaps? I'm a hardware guy, so I only think in physical addresses.

Some gory details:

I'm building an embedded system with linux running on a Xilinx FPGA with on-chip ARM A53 cores. I routinely use devmem to read or write memory-mapped registers in my FPGA logic. I'd like to use dd instead of devmem to read a long block of addresses with one command, and save the data to a file or pipe it to another process.

My FPGA design has an internal RAM block, read-writable, mapped to byte-address 0x80210000.

I wrote a shell script like so:

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  

It just fills the first kbyte of my block-RAM with some recognizable gibberish.
After executing that shell script, I can use devmem to read words from that memory.

root@testbox:~# devmem 2149646336 32
0x5AB000CD
root@testbox:~# devmem 2149646340 32
0x5AB001CD
root@testbox:~# devmem 2149646344 32
0x5AB002CD
root@testbox:~# devmem 2149646348 32
0x5AB003CD

So far so good.

Note that:
0x80210000 = 2149646336 decimal
and
0x80210000 / 16 = 134352896 decimal

Next I try to read the same 4 words of memory using dd:

root@testbox:~# dd if=/dev/mem of=/tmp/junk1 bs=1 count=16 skip=2149646336
or
root@testbox:~# dd if=/dev/mem of=/tmp/junk1 bs=16 count=1 skip=134352896
or suchlike.

Either of these lines gives me a segfault. I've tried many other combinations of bs, skip, etc, trying to find my block of memory.

Other invocations of dd "succeed". e.g. :

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

but I don't recognize this data. I guess I'm just reading from who-knows-where in my DRAM.

Is the addressing for dd if=/dev/mem different than for devmem ?

Best Answer

Partial answer:

If your devmem is from busybox, it uses /dev/mem to read and write values, so you should get the same results.

That said, note that the unit of skip is blocks (bs bytes), so bs=16 count=1 skip=2149646336 wouldn't read at 0x80210000, but at 0x802100000, which probably wraps to 0x02100000.

As the MSB of your skips is one, if there's a signed/unsigned confusion somewhere in the source and/or compiler, that could also screw up things.

So first thing I'd do is to test reading at 0x80210000 using something along the lines of bs=16 skip=134352896. If that still fails, second thing I'd do is to write a small C program that directly reads /dev/mem and verifies if that works.

Related Question