odd mmap behavior

B

Brett

I'm trying to read and write from /dev/mem on a linux system using the
mmap module. When I run this minimal example:
-------------------------------
import os, mmap

MAP_MASK = mmap.PAGESIZE - 1

addr = 0x48088024

f = os.open("/dev/mem", os.O_RDWR | os.O_SYNC)
m = mmap.mmap(f, mmap.PAGESIZE, mmap.MAP_SHARED, mmap.PROT_WRITE |
mmap.PROT_READ, offset=addr & ~MAP_MASK)
m.seek(addr & MAP_MASK)
c = m.read_byte()
print c
m.close()
os.close(f)
-------------------------------

I get the following error:
Unhandled fault: external abort on non-linefetch (0x1018) at
0x40020024
Bus error

and python crashes. What is odd is that if I try to read the same
memory address using the devmem2 program (i'll attach the source at
the end), everything works fine. Here are the truncated straces for
each program:

----- devmem2 0x48088024 -----
open("/dev/mem", O_RDWR|O_SYNC) = 3
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1,
0) = 0x4001f000
write(1, "/dev/mem opened.\n", 17) = 17
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, 3, 0x48088) =
0x40020000
write(1, "Memory mapped at address 0x40020"..., 37) = 37
write(1, "Value at address 0x48088024 (0x4"..., 46) = 46
munmap(0x40020000, 4096) = 0
close(3) = 0
io_submit(0, 0, 0xfbad2088 <unfinished ... exit status 0>
Process 1635 detached

------ the above minimal python example -----
open("/dev/mem", O_RDWR|O_SYNC|O_LARGEFILE) = 3
fstat64(3, {st_mode=S_IFCHR|0640, st_rdev=makedev(1, 1), ...}) = 0
dup(3) = 4
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, 3, 0x48088) =
0x40020000
--- SIGBUS (Bus error) @ 0 (0) ---
+++ killed by SIGBUS +++
Process 1633 detached

Am I using mmap incorrectly?
 
C

Carl Banks

I'm trying to read and write from /dev/mem on a linux system using the
mmap module. When I run this minimal example:
-------------------------------
import os, mmap

MAP_MASK = mmap.PAGESIZE - 1

addr = 0x48088024

f = os.open("/dev/mem", os.O_RDWR | os.O_SYNC)
m = mmap.mmap(f, mmap.PAGESIZE, mmap.MAP_SHARED, mmap.PROT_WRITE |
mmap.PROT_READ, offset=addr & ~MAP_MASK)
m.seek(addr & MAP_MASK)
c = m.read_byte()
print c
m.close()
os.close(f)
-------------------------------

I get the following error:
Unhandled fault: external abort on non-linefetch (0x1018) at
0x40020024
Bus error

and python crashes. What is odd is that if I try to read the same
memory address using the devmem2 program (i'll attach the source at
the end), everything works fine. Here are the truncated straces for
each program:

----- devmem2 0x48088024 -----
open("/dev/mem", O_RDWR|O_SYNC)         = 3
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1,
0) = 0x4001f000
write(1, "/dev/mem opened.\n", 17)      = 17
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, 3, 0x48088) =
0x40020000
write(1, "Memory mapped at address 0x40020"..., 37) = 37
write(1, "Value at address 0x48088024 (0x4"..., 46) = 46
munmap(0x40020000, 4096)                = 0
close(3)                                = 0
io_submit(0, 0, 0xfbad2088 <unfinished ... exit status 0>
Process 1635 detached

------ the above minimal python example -----
open("/dev/mem", O_RDWR|O_SYNC|O_LARGEFILE) = 3
fstat64(3, {st_mode=S_IFCHR|0640, st_rdev=makedev(1, 1), ...}) = 0
dup(3)                                  = 4
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, 3, 0x48088) =
0x40020000
--- SIGBUS (Bus error) @ 0 (0) ---
+++ killed by SIGBUS +++
Process 1633 detached

Am I using mmap incorrectly?

Looks like you're using it ok to me.

One thing to keep in mind is that the offset parameter was added to
mmap recently, only in Python 2.6 I think, so it might not have been
so battle-tested as the rest of Python. Also, I would guess the file-
like methods (seek, read, etc.) are not commonly used. Perhaps those
methods don't play nice with the offset method? It's possible the
mmap object doesn't recon the seek pointer relative to the offset,
meaning you'd have to use m.seek(addr) instead of m.seek(addr &
MAP_MASK)

Another possibility is that the mmap object is accessing the memory
with bad alignment (when I see bus error the first thing I think of is
that a word was read from a non-word-aligned address). You don't
happen to be running this on a Power PC? What happens when you try
accessing the mmap data like an regular array?

All speculation, but my gut feeling is bug in mmap module.


Carl Banks
 
B

Brett

Looks like you're using it ok to me.

One thing to keep in mind is that the offset parameter was added to
mmap recently, only in Python 2.6 I think, so it might not have been
so battle-tested as the rest of Python.  Also, I would guess the file-
like methods (seek, read, etc.) are not commonly used.  Perhaps those
methods don't play nice with the offset method?  It's possible the
mmap object doesn't recon the seek pointer relative to the offset,
meaning you'd have to use m.seek(addr) instead of m.seek(addr &
MAP_MASK)

Another possibility is that the mmap object is accessing the memory
with bad alignment (when I see bus error the first thing I think of is
that a word was read from a non-word-aligned address).  You don't
happen to be running this on a Power PC?  What happens when you try
accessing the mmap data like an regular array?

All speculation, but my gut feeling is bug in mmap module.

Carl Banks

I also posted this question to the linux-omap list and received some
helpful (and timely) assistance. I'm running this on an ARM (omap
3530, gumstix). Here is the take-home message (from the omap technical
reference and reported to me here http://www.spinics.net/lists/linux-omap/msg19347.html):
"CAUTION
The GP timer registers are limited to 32-bit and 16-bit data accesses;
8-bit access is not allowed and can corrupt the register content."

So... instead of calling mmap.read_byte() i'm calling mmap.read(4).
The thing I'm still wondering, is if python 'under-the-hood' is still
making 8-bit accesses. I thought it was fixed, but just got another
'Unhandled fault'. Any hints?

Also, thanks for the suggestion about accessing it as an array. I will
try to find out if one method of access (array-like or reading as a
string) results in more errors.
 
C

Carl Banks

I also posted this question to the linux-omap list and received some
helpful (and timely) assistance. I'm running this on an ARM (omap
3530, gumstix). Here is the take-home message (from the omap technical
reference and reported to me herehttp://www.spinics.net/lists/linux-omap/msg19347.html):
"CAUTION
The GP timer registers are limited to 32-bit and 16-bit data accesses;
8-bit access is not allowed and can corrupt the register content."

So... instead of calling mmap.read_byte() i'm calling mmap.read(4).
The thing I'm still wondering, is if python 'under-the-hood' is still
making 8-bit accesses. I thought it was fixed, but just got another
'Unhandled fault'. Any hints?

Yes, read() operates by copying the value as a string, which means
byte-by-byte access. (It's probably using a function such as
PyString_FromStringAndLen under the convers.)

I'm not sure you can even access the the memory through the mmap
object except byte-by-byte.

One way to get word access would be to use buffer protocol, which mmap
supports, and create a numpy ndarray that references the mmap data.


Carl Banks
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,149
Members
46,695
Latest member
StanleyDri

Latest Threads

Top