Accessing raw memory in Embedded Linux

Modern operating systems almost always feature memory protection. This stops a faulty program from crashing the entire system, or malware from accessing resources or tampering where it shouldn't.

The Linux Kernel also contains similar provisions. A userspace program can't easily access raw physical memory. However in an embedded application there are several reasons for wanting to do so.

You might want to flip a bit in a register somewhere. Perhaps you want to play with the timing parameters in the LCD driver for your SoC, but you don't want to have to re-build and re-load the kernel each time during the testing phase.

Or perhaps you have a heterogenous multiprocessor chip which uses shared memory as a communications protocol, but for simplicity's sake you would like to control this from userspace rather than build a kernel driver.

Kernel configuration

To enable access to raw physical memory access enable CONFIG_DEVMEM in your kernel configuration file. Also make sure CONFIG_STRICT_DEVMEM is disabled which will only allow access to PCI space and BIOS code and data regions (which probably won't be relevant to your ARM/MIPS/RISC-V based Embedded Linux platform).

Once you have enabled it the /dev/mem device will appear in userspace. This is a simple character device. You can then use mmap to map raw physical memory to a process's virtual memory space.

A handy tool: devmem2

That's very useful! But for debug you want a tool that allows you to poke and prod registers quickly, and luckily there is a tool available for that already. It's called devmem2 and it has a handy yocto recipe in meta-oe.

To read one 32 word from raw physical memory 0x80008044 you would run

devmem2 0x80008044

To write a value of 0xdeadbeef back into that memory location you would run

devmem2 0x80008044 w 0xdeadbeef

Simples! In addition the source code to devmem2 provides a really handy reference for accessing /dev/mem from your C application.

My own creation: devmem3

Years ago I thought it would be handy to be able to easily read/write buffers from userspace. That's when I came up with the idea of devmem3 (source on github). It utilises the stdin/stdout IO streams to pipe raw binary data between applications and the shell. This allows handy integration with other command line utilities such as hexdump or piping directly to a file.

To read 4096 bytes from address 0x40002000 and place in file /tmp/raw.bin

devmem3 0x40002000 r 4096 > /tmp/raw.bin

To write that same buffer into address location 0x40008000

cat /tmp/raw.bin | devmem3 0x40008000 w 0xdeadbeef

I think the underlying idea here is quite powerful and useful in certain situations. I hope someone finds it useful!

A note on security

As you might have guessed the use of /dev/mem can be considered a security risk. It's use in production systems should be carefully considered, and where it is not needed it should be disabled in the kernel configuration. However if an attacker already has root access, then many other things must have gone wrong from a security perspective, and you've got far graver concerns to worry about.

Copyright © 2020