mmap(), mmap64()

Map a memory region into a process's address space

Synopsis:

#include <sys/mman.h>

void * mmap( void * addr,
             size_t len,
             int prot,
             int flags,
             int fildes,
             off_t off );

void * mmap64( void * addr,
               size_t len,
               int prot,
               int flags,
               int fildes,
               off64_t off );

Arguments:

addr
NULL, or a pointer to where you want the object to be mapped in the calling process's address space.
len
The number of bytes to map into the caller's address space. It can't be 0.
prot
The access capabilities that you want to use for the memory region being mapped. You can combine at least the following protection bits, as defined in <sys/mman.h>:
flags
Flags that specify further information about handling the mapped region; see below.
fildes
The file descriptor for a shared memory object, or NOFD if you're mapping physical memory.
off
The offset into shared memory of the location that you want to start mapping.

Library:

libc

Use the -l c option to qcc to link against this library. This library is usually included automatically.

Description:

The mmap() function maps a region within the object beginning at off and continuing for len into the caller's address space and returns the location.

Typically, you don't need to use addr; you can just pass NULL instead. If you set addr to a non-NULL value, whether the object is mapped depends on whether or not you set MAP_FIXED in flags:

MAP_FIXED is set
The object is mapped to the address in addr, or the function fails.
MAP_FIXED isn't set
The value of addr is taken as a hint as to where to map the object in the calling process's address space. The mapped area won't overlay any current mapped areas.

There are two parts to the flags parameter. The first part is a type (masked by the MAP_TYPE bits), which you must specify as one of the following:

MAP_PRIVATE
The mapping is private to the calling process. It allocates system RAM and copies the current object.
MAP_SHARED
The mapping may be shared by many processes.

You can OR the following flags into the above type to further specify the mapping:

MAP_ANON
This is most commonly used with MAP_PRIVATE. The fildes parameter must be NOFD. The allocated memory is zero-filled. This is equivalent to opening /dev/zero.
MAP_BELOW16M
Used with MAP_PHYS | MAP_ANON. The allocated memory area resides in physical memory below 16M. This is important for using DMA with ISA bus devices.
MAP_FIXED
Map the object to the address specified by addr. If this area is already mapped, the call changes the existing mapping of the area.

Note: Use MAP_FIXED with caution. Not all memory models support it. In general, you should assume that you can MAP_FIXED only at an address (and size) that a call to mmap() without MAP_FIXED returned.

A memory area being mapped with MAP_FIXED is first unmapped by the system using the same memory area. See munmap() for details.

MAP_LAZY
Delay acquiring system memory, and copying or zero-filling the MAP_PRIVATE or MAP_ANON pages, until an access to the area has occurred. If you set this flag, and there's no system memory at the time of the access, the thread gets a SIGBUS with a code of BUS_ADRERR. This flag is a hint to the memory manager.
MAP_PHYS
Physical memory is required. The fildes parameter must be NOFD. When used with MAP_PRIVATE or MAP_SHARED, the offset specifies the exact physical address to map (e.g. for video frame buffers), and is equivalent to opening /dev/mem. If used with MAP_ANON, then physically contiguous memory is allocated.

MAP_NOX64K and MAP_BELOW16M are used to further define the MAP_ANON allocated memory (useful on x86 only).


Note: You should use mmap_device_memory() instead of MAP_PHYS.

MAP_NOINIT
When specified, the POSIX requirement that the memory be zeroed is relaxed. The physical memory being used for this allocation must have been previously freed with UNMAP_INIT_OPTIONAL for this flag to have any effect.

Note: This flag was added in the QNX Neutrino Core OS 6.3.2.

MAP_NOX64K
(Useful on x86 only). Used with MAP_PHYS | MAP_ANON. Prevent the allocated memory area from crossing a 64K boundary. This may be important to some DMA devices. If more than 64K is requested, the area begins on a 64K boundary.
MAP_STACK
This flag tells the memory allocator what the MAP_ANON memory will be used for. It's only a hint.

Using the mapping flags described above, a process can easily share memory between processes:

/* Map in a shared memory region */
fd = shm_open( "/datapoints", O_RDWR, 0777 );
addr = mmap( 0, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0 );

To share memory with hardware such as video memory on an x86 platform:

/* Map in VGA display memory */
addr = mmap( 0,
             65536,
             PROT_READ|PROT_WRITE,
             MAP_PHYS|MAP_SHARED,
             NOFD,
             0xa0000 );

To allocate a DMA buffer for a bus-mastering PCI network card:

/* Allocate a physically contiguous buffer */
addr = mmap( 0,
             262144,
             PROT_READ|PROT_WRITE|PROT_NOCACHE,
             MAP_PHYS|MAP_ANON,
             NOFD,
             0 );

Returns:

The address of the mapped-in object, or MAP_FAILED if an error occurred (errno is set).

Errors:

EACCES
The file descriptor in fildes isn't open for reading, or you specified PROT_WRITE and MAP_SHARED, and fildes isn't open for writing.
EBADF
Invalid file descriptor, fildes.
EINVAL
Invalid flags type, or len is 0.
ENODEV
The fildes argument refers to an object for which mmap() is meaningless (e.g. a terminal).
ENOMEM
You specified MAP_FIXED, and the address range requested is outside of the allowed process address range, or there wasn't enough memory to satisfy the request.
ENXIO
The address from off for len bytes is invalid for the requested object, or you specified MAP_FIXED, and addr, len, and off are invalid for the requested object.

Examples:

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/mman.h>

int main(int argc, char *argv[])
{
  int          i;
  unsigned char         *addr, c;

  /* Map BIOS ROM */
  addr = mmap(0, 0x10000, PROT_READ | PROT_WRITE,
               MAP_SHARED | MAP_PHYS, NOFD, 0xf0000);
  if (addr == MAP_FAILED) {
    fprintf(stderr, "mmap failed : %s\n",
     strerror(errno));
     return EXIT_FAILURE;
  }
  printf("Map addr is %p\n",(void*) addr);

  for (i = 0; i < 3 * 80; ++i) {
     c = *addr++;
     if (c >= ' ' && c <= 0x7f)
       putchar(c);
     else
       putchar('.');
  }

  return EXIT_SUCCESS;
}

Classification:

mmap() is POSIX 1003.1 MF|SHM|TYM; mmap64() is Large-file support

Safety:
Cancellation point No
Interrupt handler No
Signal handler Yes
Thread Yes

See also:

mmap_device_io(), mmap_device_memory(), munmap()