4

I cannot figure how to get the virtual address of the standard mmap objects in Python (from the mmap module). The documented methods only seem to access the memory as array of bytes or as character strings.

But I need to access the mmap'ped memory by precisely 2 or 4 bytes at once - because this memory in my application is mapped to hardware registers (think /dev/mem or GPIO or such). Accessing memory in this way is possible with ctypes module - but for this I need the pointer - or virtual address - of the mapping.

Currently I overcome this by using the native open() and mmap() functions from libc (thanks to the same ctypes) but would rather not.

Why the mmap module won't provide easy way to get the memory address? Hope I'm missing something obvious...

-- dd

ddbug
  • 1,392
  • 1
  • 11
  • 25

2 Answers2

5

mmap objects support the writable buffer interface, so you can use the from_buffer class method that ctypes classes have with the mmap object as an argument to get a ctypes object that shares the memory of the mmap file.

buf = mmap.mmap(fd, mmap.PAGESIZE, mmap.MAP_SHARED, mmap.PROT_WRITE)
int_pointer = ctypes.c_int.from_buffer(buf)
Tim Wakeham
  • 1,029
  • 1
  • 8
  • 12
  • Great! Thank you a lot. – ddbug Sep 03 '15 at 00:49
  • I made a quick test yesterday and wanted already mark your answer. but then I cannot make a "real" code work with Python 2.7 on Linux. The exact code as you posted, fails with access denied. I do not understand why. When I change MAP_SHARED to MAP_PRIVATE, mmap succeeds. When I change PROT_WRITE to PROT_READ, mmap succeeds. But I need it shared (visible globally) and writable. Could you give another hint, please? – ddbug Sep 03 '15 at 19:08
1

Here is a more complete code that I need get working, with Python 2.7, on Linux:

import os, io
from mmap import *
from ctypes import *

winsize= 0
devmemfd= -1
curr_va=0
curr_base=0
devf = None
mm = None
ptr4 = None

def mm_init( path = 'test.dat' ) :
  global curr_va,winsize,devmemfd,mm,devf,ptr4
  devf = open( path, "rwb")
  devmemfd = devf.fileno()
  mm = mmap(devmemfd, PAGESIZE, MAP_SHARED, PROT_WRITE) # this FAILS if MAP_SHARED
  ptr4 = POINTER(c_uint32)( c_uint32.from_buffer(mm) ) # this FAILS is I make mapping readonly
  curr_va = cast(ptr4, c_void_p).value 
  winsize=PAGESIZE
  print("OK")

Again, I should be missing something obvious as I'm new to Python

-- dd

Traceback:

>>> mm_init()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "mm-test.py", line 17, in mm_init
    mm = mmap(devmemfd, PAGESIZE, MAP_SHARED, PROT_WRITE) 
mmap.error: [Errno 13] Permission denied
ddbug
  • 1,392
  • 1
  • 11
  • 25
  • How does it fail? Exceptions? Post traceback. – Tim Wakeham Sep 03 '15 at 22:02
  • Traceback added above. By the way I run this as root. so what means "permission denied" exactly? Does this work for you without errors? -- dd – ddbug Sep 04 '15 at 00:34
  • Ok, found the error. The open() mode must be "r+", not "rw". Exactly like in C. Python3 detects this and gives error message, 2.7 silently does something weird. Thank you a lot again. -- dd – ddbug Sep 04 '15 at 00:53