mmap for I/O access

Do you have a question? Post it now! No Registration Necessary

Translate This Thread From English to

Threaded View
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

Re: mmap for I/O access
Quoted text here. Click to load it

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
On Mon, 07 Jan 2008 22:33:07 +0000, "Geronimo W. Christ Esq"

Quoted text here. Click to load it

Thanks.  It worked like a charm.  Yes, my getpagesize() did return 4K.  Now I'm
happily turning LEDs on and off.


Robert Scott
Ypsilanti, Michigan

Re: mmap for I/O access
Quoted text here. Click to load it

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

Quoted text here. Click to load it

   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.

Quoted text here. Click to load it


--
--
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

Quoted text here. Click to load it

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))


Quoted text here. Click to load it

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

Quoted text here. Click to load it

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

Quoted text here. Click to load it
the
Quoted text here. Click to load it
it
Quoted text here. Click to load it

In your situation, I like to use a struct with the __packed__ attribute
(as supported by GCC and other compilers). This lets you see registers
of different sizes directly by accessing members of a struct. But the
outcome is much the same.


Re: mmap for I/O access
Quoted text here. Click to load it

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