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

: [] lr : [] 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

Reply to
Robert Scott
Loading thread data ...

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.

Reply to
Geronimo W. Christ Esq

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

Reply to
Robert Scott

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@spe&ar&c.xs4all.nl &=n http://home.hccnet.nl/a.w.m.van.der.horst
Reply to
Albert van der Horst

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

Reply to
Robert Scott

the

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.

Reply to
Geronimo W. Christ Esq

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

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.