mmap for I/O access - Embedded

This is a discussion on mmap for I/O access - Embedded ; 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 ...

+ Reply to Thread
Results 1 to 7 of 7

Thread: mmap for I/O access

  1. mmap for I/O access

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

    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

  2. Re: mmap for I/O access

    Robert Scott wrote:
    > My call to mmap is causing a Segmentation fault. Is this the right way to do
    > 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.

  3. Re: mmap for I/O access

    On Mon, 07 Jan 2008 22:33:07 +0000, "Geronimo W. Christ Esq"
    wrote:

    >Robert Scott wrote:
    >> My call to mmap is causing a Segmentation fault. Is this the right way to do
    >> 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.


    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

  4. Re: mmap for I/O access

    In article <478286ac.198578@newsgroups.comcast.net>,
    Robert Scott <---@---> wrote:
    >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
    >#include
    >#include
    >#include
    >#include
    >
    >main() {
    > int fm = open("/dev/mem",O_RDWR);
    > printf("handle to /dev/mem = %08x\r\n",fm);
    >
    > char *mptr = (char*)mmap(


    More reasonable: (you want mptr to point to an int right?)
    int *mptr = 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)));


    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.

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



    --
    --
    Albert van der Horst, UTRECHT,THE NETHERLANDS
    Economic growth -- like all pyramid schemes -- ultimately falters.
    albert@spe&ar&c.xs4all.nl &=n http://home.hccnet.nl/a.w.m.van.der.horst

  5. Re: mmap for I/O access

    On 15 Jan 2008 21:04:59 GMT, Albert van der Horst
    wrote:

    >In article <478286ac.198578@newsgroups.comcast.net>,
    >Robert Scott <---@---> wrote:
    >>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
    >>#include
    >>#include
    >>#include
    >>#include
    >>
    >>main() {
    >> int fm = open("/dev/mem",O_RDWR);
    >> printf("handle to /dev/mem = %08x\r\n",fm);
    >>
    >> char *mptr = (char*)mmap(

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


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


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

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


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

    >Maybe you managed to confuse the compiler. It is certainly
    >worthwhile to leave the second line out, see what happens.


    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

  6. Re: mmap for I/O access

    Robert Scott wrote:

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


    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.


  7. Re: mmap for I/O access

    Geronimo W. Christ Esq wrote:
    > Robert Scott wrote:
    >
    >> 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))

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


    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

+ Reply to Thread