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.

Comments

  1. 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?

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

    ReplyDelete
  3. 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()

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

    ReplyDelete
  5. 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"

    ReplyDelete
  6. How much memory(I mean the max memory size) can be accessed by this method?

    ReplyDelete
  7. Sorry, I don't know for sure also because I think not all total memory can be accessed. Some memory block can be reserved and locked by the system.

    ReplyDelete

Post a Comment

Popular posts from this blog

Access GPIO from Linux user space

Launch an app from Android shell terminal

Qt 5 and " Failed to load platform plugin 'windows' " error