Sun Microsystems, Inc.
spacerspacer
spacer www.sun.com docs.sun.com |
spacer
black dot
 
 
  Previous   Contents   Next 
   
 
Chapter 12

Mapping Device and Kernel Memory

Some device drivers allow applications to access device or kernel memory using mmap(2). Examples are frame buffer drivers, which allow the frame buffer to be mapped into a user thread, or a pseudo driver that communicates with an application using a shared kernel memory pool. This chapter provides information on the following subjects:

Memory Mapping Operation Overview

In general, the steps a driver must take to export device or kernel memory are:

  1. Set the D_DEVMAP flag in the cb_flag flag of the cb_ops(9S) structure.

  2. Define a devmap(9E) driver entry point to export the mapping.

  3. Use devmap_devmem_setup(9F) to set up user mappings to a device. To set up user mappings to kernel memory, use devmap_umem_setup(9F).

Exporting the Mapping

The devmap(9E) entry point is called as a result of the mmap(2) system call. devmap(9E) is used to:

  • Validate the user mapping to the device or kernel memory.

  • Translate the logical offset within the application mapping to the corresponding offset within the device or kernel memory.

  • Pass the mapping information to the system for setting up the mapping.

int devmap(dev_t dev, devmap_cookie_t handle, offset_t off,
     size_t len, size_t *maplen, uint_t model);

where:

dev

Device whose memory is to be mapped

handle

Device-mapping handle that the system creates and uses to describe a mapping to contiguous device or kernel memory

off

Logical offset within the application mapping that has to be translated by the driver to the corresponding offset within the device or kernel memory

len

Length (in bytes) of the memory being mapped

maplen

Allows driver to associate different kernel memory regions or multiple physically discontiguous memory regions with one contiguous user application mapping

model

Data model type of the current thread

The system creates multiple mapping handles in one mmap(2) system call (for example, if the mapping contains multiple physically discontiguous memory regions).

Initially devmap(9E) is called with parameters off and len, which were passed by the application to mmap(2). devmap(9E) sets *maplen to the length from off to the end of a contiguous memory region. *maplen must be rounded up to a multiple of a page size. If *maplen is set to less than the original mapping length len, the system will repeatedly call devmap(9E) with a new mapping handle and adjusted off and len parameters until the initial mapping length is satisfied.

If a driver supports multiple application data models, model has to be passed to ddi_model_convert_from(9F) to determine whether there is a data model mismatch between the current thread and the device driver. The device driver might have to adjust the shape of data structures before exporting them to a user thread that supports a different data model. See the Appendix C, Making a Device Driver 64-Bit Ready man page for more details.

devmap(9E) must return -1 if the logical offset, off, is out of the range of memory exported by the driver.

Associating Device Memory With User Mappings

devmap_devmem_setup(9F) is provided to export device memory to user applications.


Note - devmap_devmem_setup(9F) has to be called from the driver's devmap(9E) entry point.


The syntax for devmap_devmem_setup() follows:

int devmap_devmem_setup(devmap_cookie_t handle, dev_info_t *dip,
         struct devmap_callback_ctl *callbackops, uint_t rnumber, 
         offset_t roff, size_t len, uint_t maxprot, uint_t flags, 
         ddi_device_acc_attr_t *accattrp);

where:

handle

Opaque device-mapping handle that the system uses to identify the mapping

dip

Pointer to the device's dev_info structure

callbackops

Pointer to a devmap_callback_ctl(9S) structure that allows the driver to be notified of user events on the mapping

rnumber

Index number to the register address space set

roff

Offset into the device memory

len

Length in bytes that is exported

maxprot

Allows the driver to specify different protections for different regions within the exported device memory

flags

Must be set to DEVMAP_DEFAULTS

accattrp

Pointer to a ddi_device_acc_attr(9S) structure

roff and len describe a range within the device memory specified by the register set rnumber. The register specifications referred to by rnumber are described by the reg property. For devices with only one register set, pass zero for rnumber. The range described by roff and len are made accessible to the user's application mapping at the offset passed in by the devmap(9E) entry point. Usually the driver passes the devmap(9E) offset directly to devmap_devmem_setup(9F). The return address of mmap(2) then maps to the beginning address of the register set.

maxprot allows the driver to specify different protections for different regions within the exported device memory. For example, one region might not allow write access by setting only PROT_READ and PROT_USER.

Example 12-1 shows how to export device memory to an application. The driver first determines whether the requested mapping falls within the device memory region. The size of the device memory is determined using ddi_dev_regsize(9F). The length of the mapping is rounded up to a multiple of a page size using ptob(9F) and btopr(9F), and devmap_devmem_setup(9F) is called to export the device memory to the application.


Example 12-1 devmap_devmem_setup(9F) Routine

static int
xxdevmap(dev_t dev, devmap_cookie_t handle, offset_t off, size_t len,
    size_t *maplen, uint_t model)
{
        struct xxstate *xsp;
        int    error, rnumber;
        off_t regsize;
    
        /* Set up data access attribute structure */
        struct ddi_device_acc_attr xx_acc_attr = {
            DDI_DEVICE_ATTR_V0,
            DDI_NEVERSWAP_ACC,
            DDI_STRICTORDER_ACC
        };
        xsp = ddi_get_soft_state(statep, getminor(dev));
        if (xsp == NULL)
                return (-1);
        /* use register set 0 */
        rnumber = 0;
        /* get size of register set */
        if (ddi_dev_regsize(xsp->dip, rnumber, &regsize) != DDI_SUCCESS)
                return (-1);
        /* round up len to a multiple of a page size */
           len = ptob(btopr(len));
        if (off + len > regsize)
                return (-1);
        /* Set up the device mapping */
        error = devmap_devmem_setup(handle, xsp->dip, NULL, rnumber, 
        off, len, PROT_ALL, DEVMAP_DEFAULTS, &xx_acc_attr);
        /* acknowledge the entire range */
        *maplen = len;
        return (error);
}

 
 
 
  Previous   Contents   Next