Access physical memory in Linux


If you want to find a way for access physical memory in Linux there are only two solutions. The first is to develop a module running in kernel space with the correct privileges to access physical memory and the second is to use a special devices called "/dev/mem". If your purpose is only to read or write some small parts of physical memory from user space this device is the right solution for you. Basically you can manage it as a file with additional use of some special functions required for get a pointer to the memory address your are interested to work in.

The first operation is to get handle of this special device, Please, note that in Linux system the access of this device is usually guarantee only to root user. If you want to get handle from a different user you need to change device access permission. Anyway the command for get the handle is the following:

int mem_dev = open("/dev/mem", O_RDWR | O_SYNC);

if(mem_dev == -1)
{
   // Error
}

and once finished obviously:

close(mem_dev);

Now the most important part. On Linux the physical memory pointer you want must be page aligned. This mean we need to change, in case, the original memory address you need to something the system can accept. The operation is quite simple and all you need are the following lines of code:

const uint32_t mem_address = 0x10001234
const uint32_t mem_size = 0x100;

uint32_t alloc_mem_size, page_mask, page_size;
void *mem_pointer, *virt_addr;

page_size = sysconf(_SC_PAGESIZE);
alloc_mem_size = (((mem_size / page_size) + 1) * page_size);
page_mask = (page_size - 1);

mem_pointer = mmap(NULL,
                   alloc_mem_size,
                   PROT_READ | PROT_WRITE,
                   MAP_SHARED,
                   mem_dev,
                   (mem_address & ~page_mask)
                   );

if(mem_pointer == MAP_FAILED)
{  
      // Error
}

virt_addr = (mem_pointer + (mem_address & page_mask)); 

At the end of this code, if no errors occurred, you have a pointer virt_addr to the physical memory space from address 0x10001234 to 0x10001334. You can use this pointer in read/write mode but be very carefully since an incorrect modify to some critical memory section will crash the system. Once finished to use the pointer you must free it as follow:

munmap(mem_pointer, alloc_mem_size);

Finish! Very short code and quite easy.

6 Comments:

Just what I was looking for!

September 19, 2014 at 1:05 AM comment-delete

first of all, excellent work!

would classifying the memory address for a 64bit system change the variable type of the memory address to a uint64_t?

March 13, 2016 at 1:20 AM comment-delete

or maybe even simply use the size_t type which changes according to architecture?

March 13, 2016 at 1:24 AM comment-delete

Hi

This example is for 32 bit system. In case you need to work on 64 bit system you have to change the variable type as you wrote but also use the correct mmap() call that in case of 64 bit is mmap64()

March 13, 2016 at 3:37 AM comment-delete

That's all fine and dandy, but try doing it within a device driver that you don't have access to an "open()" function.

March 21, 2016 at 11:34 AM comment-delete

It's exactly why I wrote on top of the post the following warning:

"Please, note that in Linux system the access of this device is usually guarantee only to root user. If you want to get handle from a different user you need to change device access permission"

March 21, 2016 at 11:48 AM comment-delete

Post a Comment