Do you have a question? Post it now! No Registration Necessary
Subject
- Posted on
mmap for I/O access
- 01-07-2008
- Robert Scott
January 7, 2008, 8:24 pm

My call to mmap is causing a Segmentation fault. Is this the right way to do
it?
I have some general-purpose I/O on this Embest ARM-based board. According to
the manual for the board, the control register and the data register are at
absolute physical addresses
0x56000010 and
0x56000014 respectively.
So here is how I tried to test my access to these registers:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
main() {
int fm = open("/dev/mem",O_RDWR);
printf("handle to /dev/mem = %08x\r\n",fm);
char *mptr = (char*)mmap(
(void*)0,
16, //..16 bytes
PROT_READ | PROT_WRITE,
MAP_SHARED,
fm,
0x56000010); //..starting with Port B CON reg
printf("mptr = %08x", mptr);
printf("GPBCON = %08x\r\n", *((int*)(mptr+0)));
printf("GPBDAT = %08x\r\n", *((int*)(mptr+4)));
}
When I run this program, the open() returns 4, and then the Segmentation Fault
occurs during the execution of mmap, because there was no printf telling what
mptr is. Here is the output:
handle to /dec/mem = 00000004
: [<000086b4>] lr : [<00000000>] Tainted: P
sp : bffffdd8 ip : bffff7d8 fp : bffffea4
r10: 40139280 r9 : 000084a0 r8 : 00000001
r7 : 4000ee5c r6 : 0000830c r5 : bffffec4 r4 : 40020c34
r3 : ffffffff r2 : 0000000f r1 : 00008823 r0 : 0000883c
Flags: NzCv IRQs on FIQs on Mode USER_32 Segment user
Control: C000317F Table: 33E90000 DAC: 00000015
Segmentation fault
- - - - - - - - - - - - - - - - - - - - - - - - - - -
I am running as root, so I should be able to do this, right?
Robert Scott
Ypsilanti, Michigan
it?
I have some general-purpose I/O on this Embest ARM-based board. According to
the manual for the board, the control register and the data register are at
absolute physical addresses
0x56000010 and
0x56000014 respectively.
So here is how I tried to test my access to these registers:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
main() {
int fm = open("/dev/mem",O_RDWR);
printf("handle to /dev/mem = %08x\r\n",fm);
char *mptr = (char*)mmap(
(void*)0,
16, //..16 bytes
PROT_READ | PROT_WRITE,
MAP_SHARED,
fm,
0x56000010); //..starting with Port B CON reg
printf("mptr = %08x", mptr);
printf("GPBCON = %08x\r\n", *((int*)(mptr+0)));
printf("GPBDAT = %08x\r\n", *((int*)(mptr+4)));
}
When I run this program, the open() returns 4, and then the Segmentation Fault
occurs during the execution of mmap, because there was no printf telling what
mptr is. Here is the output:
handle to /dec/mem = 00000004
: [<000086b4>] lr : [<00000000>] Tainted: P
sp : bffffdd8 ip : bffff7d8 fp : bffffea4
r10: 40139280 r9 : 000084a0 r8 : 00000001
r7 : 4000ee5c r6 : 0000830c r5 : bffffec4 r4 : 40020c34
r3 : ffffffff r2 : 0000000f r1 : 00008823 r0 : 0000883c
Flags: NzCv IRQs on FIQs on Mode USER_32 Segment user
Control: C000317F Table: 33E90000 DAC: 00000015
Segmentation fault
- - - - - - - - - - - - - - - - - - - - - - - - - - -
I am running as root, so I should be able to do this, right?
Robert Scott
Ypsilanti, Michigan

Re: mmap for I/O access

It should work more or less as you have guessed, but there are a few
things to fix :
- you need to map to an offset which is a multiple of the page size,
usually 4K. Get the page size with a call to getpagesize(2).
- The size you're mapping to also needs to be a multiple of the page size.
I usually write a little wrapper function which allows the user to map
arbitrary addresses, computing the offset and alignment for you behind
the scenes.
- check that you're mapping to the physical address as actually
presented on the CPU's bus, and not the mapped or translated address
supported by the CPU. I don't know what way this is set up on ARM. Ask
your hardware engineer or check the hardware guide for the board.
- I would strongly recommend that you ass the O_SYNC flag to the open(2)
call. This will tell the OS to use an uncached mapping. Not using O_SYNC
may cause weird effects.

Re: mmap for I/O access

More reasonable: (you want mptr to point to an int right?)
int *mptr = mmap(

And then:
printf("GPBCON = %08x\r\n", mptr[0] );
printf("GPBCON = %08x\r\n", mptr[1] );
For some one who tries to be so political correct to cast the
(void *) that mmap returns, it is strange to see here a 4,
instead of sizeof(int) .
Maybe you managed to confuse the compiler. It is certainly
worthwhile to leave the second line out, see what happens.

--
--
Albert van der Horst, UTRECHT,THE NETHERLANDS
Economic growth -- like all pyramid schemes -- ultimately falters.
Albert van der Horst, UTRECHT,THE NETHERLANDS
Economic growth -- like all pyramid schemes -- ultimately falters.
We've slightly trimmed the long signature. Click to see the full one.

Re: mmap for I/O access

Not necessarily. The I/O defined at 0x56000000 includes some 32-bit and some
16-bit registers, and even some 8-bit ones. And the documentation gives all the
addresses in terms of byte addresses. So if I want to make my code look like it
corresponds exactly with the documentation, then I want address arithmetic to
work on bytes. The variable mptr is never used directly in my application. I
use it in macros, like:
#define gpb_DAT (*(short int*)(mptr+0x14))

Right. This was only a test. In the real application I use the macros like the
one shown above.

No need. The problem of the segmentation fault was solved by the posting of
Geronimo on 1/7/2008. The problem was that I was not using a page boundary and
a size equal to a multiple of the page size (4K) in my call to mmap.
Robert Scott
Ypsilanti, Michigan

Re: mmap for I/O access

Using structures yes, but don't use the __packed__ attribute. This could
change the way the compiler generates code to access the members in it (for
example bytewise access on larger members that are not aligned for this
type of architecture).
Best way for maintenance would be to create a few inline functions with the
access width in their name like in8, out8, in16, out16 aso. that are
working with simple address offsets. Its also more portable, because some
architectures do some kind of access optimization (reordering) in
background so the volatile attribute does not help this case.
JB
Site Timeline
- » Professional Seminar - Linux Kernel Debugging
- — Next thread in » Embedded Linux
-
- » Requesting Help on XIP on ARM 7TDMI
- — Previous thread in » Embedded Linux
-
- » Crosscompiling for ARM: reloc type R_ARM_ABS32 is not supported for PIC - ...
- — Newest thread in » Embedded Linux
-
- » Broadband filter matching design
- — The site's Newest Thread. Posted in » Electronics Design
-
- » Alimentazione piano magnetico
- — The site's Last Updated Thread. Posted in » Electronics Hobby (Italian)
-