Find the answer to your Linux question:
Results 1 to 9 of 9
Hi, I am using mmap to be able to access some HW registers on a chip which are memory mapped. The registers I need to access start at the base ...
Enjoy an ad free experience by logging in. Not a member yet? Register.
  1. #1
    Just Joined!
    Join Date
    Oct 2012
    Posts
    5

    MMAP Question: 'length' parameter in mmap not serving its purpose


    Hi,

    I am using mmap to be able to access some HW registers on a chip which are memory mapped. The registers I need to access start at the base address 0xfd000000.

    I have the following code:

    #define LEN 0x1 //place the size here
    #define OFFSET 0xfd000000 //place the offset address here

    volatile uint32_t* map = (volatile uint32_t*)mmap(0,LEN,PROT_READ|PROT_WRITE, MAP_SHARED,_fdmem,OFFSET);

    length is supposed to be in bytes. Now if I place a value of 1 for len, I should only be able to access one byte of the mapped memory. But this is not the case. I can access a lot more, I have not checked the limit, but I was able to R/W to memory atleast 1000 bytes more then I should be allowed.

    Technically, I should only be able to access 0xfd00000-0xfd000001.

    Why is this the case? The reason I want to know is because it seems the 'len' parameter is not functioning as it should.

    Regards,
    Bilal

  2. #2
    Linux Newbie
    Join Date
    Mar 2010
    Posts
    152
    You'll probably be able to access a whole page (4 kB) without triggering a segment violation. Linux can only map complete 4 kB pages (4 MB if your kernel uses large pages) - this is a feature of the hardware, and it is impossible to circumvent in software. In other words, even though you only requested one byte, Linux has been forced to round this up to the nearest page size; there is no way to get around this.
    Programming and other random guff: cat /dev/thoughts > blogspot.com (previously prognix.blogspot.com)

  3. #3
    Just Joined!
    Join Date
    Oct 2012
    Posts
    5
    I see.

    If this is the case, I should then be able to access 0xfd000000+0x1000 (4096, the page size, in decimal) = 0xfd001000

    However, reading from this value gives me garbage.

    Also, I do not get segmentation fault if I try accessing addresses beyond 0xfd001000 such as 0xfd00100c, however the values returned are incorrect.

    Shouldn't I be getting a segmentation fault if I'm accessing addresses greater than the page size of 4096 bytes? Also, shouldn't 0xfd001000 be accessible to me?

    Thanks.

  4. $spacer_open
    $spacer_close
  5. #4
    Linux Newbie
    Join Date
    Mar 2010
    Posts
    152
    Quote Originally Posted by bbjunaid View Post
    If this is the case, I should then be able to access 0xfd000000+0x1000 (4096, the page size, in decimal) = 0xfd001000

    However, reading from this value gives me garbage.
    Yeah, probably. What do you expect to be there? That's memory you haven't requested from Linux and are not supposed to access, but because it's within a page your process is allowed to access (i.e. that's been mapped into your memory space as a data page) the system won't complain, as it has no way to know that you're accessing this memory.


    Quote Originally Posted by bbjunaid View Post
    Also, I do not get segmentation fault if I try accessing addresses beyond 0xfd001000 such as 0xfd00100c, however the values returned are incorrect.
    Like you just said, this is garbage. This memory hasn't been requested by you - why would you expect it to contain anything but garbage?


    Quote Originally Posted by bbjunaid View Post
    Shouldn't I be getting a segmentation fault if I'm accessing addresses greater than the page size of 4096 bytes? Also, shouldn't 0xfd001000 be accessible to me?
    No on both counts. First off, your system (for all I know) could be using large 4 MB pages. Secondly, what memory has been mapped onto the next virtual page? You, as an application developer, cannot possibly know. It may well be your heap, it might be your stack, it might be some poor shared library's data section you're trampling all over. Either way, no good can come from accessing it. The kernel has decided to make that page accessible to your process (not to you as a caller of mmap()) completely by accident - the situation could be different on another run of your program/another system.

    Look, you're over-complicating this - your call requests that one byte of memory be mmap()'d into your virtual address space. Just use it and remember:

    Any access of memory you're not supposed to access couses undefined behaviour.

    This means reading such memory could return garbage, zero, or generate a segmentat violation. The OS is not guaranteed (nor should it be relied upon) to do any of these.
    Programming and other random guff: cat /dev/thoughts > blogspot.com (previously prognix.blogspot.com)

  6. #5
    Just Joined!
    Join Date
    Oct 2012
    Posts
    5
    Thanks for the replies.

    Firstly, my system page size is 4kb (4096 bytes).

    So from what I'm understanding, you're saying that I only requested 1 byte of memory, but due to a kernel limitation, it can only give me multiples of _PAGE_SIZE so gives me 4096 bytes instead. However, I can only access 1 byte of memory with certainty, while the remaining 4095 are undefined behavior??? If the kernel has infact decided to mmap 4kB, shouldn't I expect defined behavior in this 4kB range?

    BTW, I am able to confirm values I am reading through a gdb session in another CPU which has direct access to these registers.

    From my experimentation, I have noticed that I am able to obtain correct values for many registers in between 0xfd000000-0xfd001000. Many of these are not writable, so its hard to test at what "limit" I am able to correctly access registers till.

    __________________________

    I also have another question. Is there any way to obtain the last addressable location in /dev/mem? The requirement for my project is now that the OFFSET should be adjustable, and I should 1MB as my mmap length. I am not sure what could happen if the user enters an offset which when mmap'ed with the 1MB length may go over the memory range in /dev/mem.

  7. #6
    Linux Newbie
    Join Date
    Mar 2010
    Posts
    152
    Quote Originally Posted by bbjunaid View Post
    So from what I'm understanding, you're saying that I only requested 1 byte of memory, but due to a kernel limitation, it can only give me multiples of _PAGE_SIZE so gives me 4096 bytes instead. However, I can only access 1 byte of memory with certainty, while the remaining 4095 are undefined behavior??? If the kernel has infact decided to mmap 4kB, shouldn't I expect defined behavior in this 4kB range?
    Well, it's due to a hardware limitation really - processors with virtual memory only let whole pages (in your cake 4 kB) be mapped into/out of processes, so it has to allocate you 4 kB at a time. It is possible that other/future hardware will be able to map less, so you must not rely on this. If you need to access more that 1 byte, request more from mmap(). Accessing the rest of the page may work okay for you right now, but you're setting yourself up for future pain. Just request what you need, and only use what you've requested.


    Quote Originally Posted by bbjunaid View Post
    BTW, I am able to confirm values I am reading through a gdb session in another CPU which has direct access to these registers.

    From my experimentation, I have noticed that I am able to obtain correct values for many registers in between 0xfd000000-0xfd001000. Many of these are not writable, so its hard to test at what "limit" I am able to correctly access registers till.
    Yeah, probably... I don't see what your point is. You've been allocated the whole page. Don't use it. Also the "limit" may change depending on where the kernel decides to place your program in memory, and you don't know where the next page of virtual memory has been mapped to, and hence what you'd be reading/trampling over.


    Quote Originally Posted by bbjunaid View Post
    I also have another question. Is there any way to obtain the last addressable location in /dev/mem? The requirement for my project is now that the OFFSET should be adjustable, and I should 1MB as my mmap length. I am not sure what could happen if the user enters an offset which when mmap'ed with the 1MB length may go over the memory range in /dev/mem.
    You could look at /proc/meminfo for the total amount of memory. Never encountered this sort of thing before, but I think it would work.
    Programming and other random guff: cat /dev/thoughts > blogspot.com (previously prognix.blogspot.com)

  8. #7
    Just Joined!
    Join Date
    Oct 2012
    Posts
    5
    I have a few more questions:

    1) The chip I am working is memory mapped from 0-4096 MB. A lot of the intial memory is RAM, external memory interface, PCI express.

    If I mmap to this region, the kernel hangs. Is this an expected behavior? I thought it would be okay as long as I'm not reading/writing to this mmap'ed region.

    2) How is the speed of map/unmap? I'm thinking of keeping a default map_length of 4MB. I do not want it to be so large that it coincides with senstive regions, but at the same time, I do not want it to be so small that I have to keep mapping/unmapping everytime a request to registers outside the mapped region is required.

    Is there any significant performance drop is map/unmap occurs often?

  9. #8
    Just Joined!
    Join Date
    Oct 2012
    Posts
    5
    Sigh...more problems:

    When I dereference the returned mmap pointer for certain offsets, I get the following error:

    [ 795.770000] Unhandled fault: external abort on non-linefetch (0x101 at 0x76f62f00
    Bus error

    I have ensured I have mapped enough length.

    When I access these registers through the gdb debugging session on the ARM CPU, I have noticed that gdb just returns 0 as their value, and even if I do set *address = val, x address always shows 0x0. This is a trend I have noticed with all the registers which give me a BUS error.

    Any suggestions on this?

  10. #9
    Linux Newbie
    Join Date
    Mar 2010
    Posts
    152
    On these last points, I'm afraid I'm unable to help you I don't work with that sort of thing, and even if I did, these issues are very hardware specific - try an ARM-specific board or the manufacturer. On the performace issue, I only suggest you start by doing whatever you want to do (i.e. only mapping for requests) and see if this becomes a performance bottlneck for your particular application.
    Programming and other random guff: cat /dev/thoughts > blogspot.com (previously prognix.blogspot.com)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •