Next | Prev | Up | Top | Contents | Index

Entry Point map()

The pfxmap() entry point can be defined in either a character or a block driver (it is the only mapping entry point that a block driver can supply). The function prototype is

int pfxmap(dev_t dev, vhandl_t *vt, off_t off, int len, int prot);

The argument values are

dev A dev_t value from which you can extract both the major and minor device numbers.
vtThe address of an opaque structure that describes the assigned address in the user process address space. The structure contents are subject to change.
off, lenThe offset and length arguments passed to mmap() by the user process.
prot Flags showing the access intentions of the user process.

The first task of the driver is to verify that the access specified in prot is allowed. The next task is to validate the off and len values: do they fall in the valid address space of the device?

When the device driver approves of a mapping, it uses a kernel function, v_mapphys(), to establish the mapping. This function (documented in the v_mapphys(D3) reference page) takes the vhandle_t, an address in kernel cached or uncached memory, and a length. It makes the specified region of kernel space a part of the address space of the user process.

For example, a pseudo-device driver that intends to share kernel virtual memory with user processes would first allocate the memory:

caddr_t *kaddr = kmem_alloc (len , KM_CACHEALIGN);

It would then use the address of the allocated memory with the vhandle_t value it had received to map the allocated memory into the user space:

v_mapphys (vt, kaddr, len)

Note: There are no special precautions to take when mapping cached memory into user space, or when mapping device registers or bus addresses. However, you should almost never map uncached memory into user space. The effects of uncached memory access are hardware dependent and differ between multiprocessors and uniprocessors. Among uniprocessors, the IP26 CPU module has highly restrictive rules for the use of uncached memory (see "Uncached Memory Access in the IP26 CPU"). In general, mapping uncached memory makes a driver nonportable and is likely to lead to subtle failures that are hard to resolve. Example 8-3 contains an edited fragment of code from a Silicon Graphics device driver. This pseudo-device driver, whose prefix is flash_, provides access to "flash" PROM in certain computer models. It allows a user process to map the PROM into user space.

Example 8-3 : Edited Fragment of flash_map()

int flash_map(dev_t dev, vhandl_t *vt, off_t off, long len)
{
   long offset = (long) off; /*Actual offset in flash prom*/
/* Don't allow requests which exceed the flash prom size */
   if ((offset + len) > FLASHPROM_SIZE)
      return ENOSPC;
/* Don't allow non page-aligned offsets */
   if ((offset % NBPC) != 0)
      return EIO;
/* Only allow mapping of entire pages */
   if ((len % NBPC) != 0)
      return EIO;
   return v_mapphys(vt, FLASHMAP_ADDR + offset, len);
}
When the driver allocates some memory resource associated with the mapping, and when more than one mapping can be active at a time, the driver needs to tag each memory resource so it can be located when the pfxunmap() entry point is called. One answer is to use the vt_gethandle() macro defined in sys/region.h. This macro takes a pointer to a vhandle_t and returns a unique pointer-sized integer that can be used to tag allocations. No other information in sys/region.h is supported for driver use.


Next | Prev | Up | Top | Contents | Index