Writing Device Drivers for Oracle® Solaris 11.2

Exit Print View

Updated: September 2014
 
 

Allocating Kernel Memory for User Access

Use ddi_umem_alloc(9F) to allocate kernel memory that is exported to applications. ddi_umem_alloc() uses the following syntax:

void *ddi_umem_alloc(size_t size, int flag, ddi_umem_cookie_t 
*cookiep);

where:

size

Number of bytes to allocate.

flag

Used to determine the sleep conditions and the memory type.

cookiep

Pointer to a kernel memory cookie.

ddi_umem_alloc(9F) allocates page-aligned kernel memory. ddi_umem_alloc() returns a pointer to the allocated memory. Initially, the memory is filled with zeroes. The number of bytes that are allocated is a multiple of the system page size, which is rounded up from the size parameter. The allocated memory can be used in the kernel. This memory can be exported to applications as well. cookiep is a pointer to the kernel memory cookie that describes the kernel memory being allocated. cookiep is used in devmap_umem_setup(9F) when the driver exports the kernel memory to a user application.

The flag argument indicates whether ddi_umem_alloc(9F) blocks or returns immediately, and whether the allocated kernel memory is pageable. The values for the flag argument as follows:

DDI_UMEM_NOSLEEP

Driver does not need to wait for memory to become available. Return NULL if memory is not available.

DDI_UMEM_SLEEP

Driver can wait indefinitely for memory to become available.

DDI_UMEM_PAGEABLE

Driver allows memory to be paged out. If not set, the memory is locked down.

The ddi_umem_lock() function can perform device-locked-memory checks. The function checks against the limit value that is specified in project.max-locked-memory. If the current project locked-memory usage is below the limit, the project's locked-memory byte count is increased. After the limit check, the memory is locked. The ddi_umem_unlock() function unlocks the memory, and the project's locked-memory byte count is decremented.

The accounting method that is used is an imprecise full price model. For example, two callers of umem_lockmemory() within the same project with overlapping memory regions are charged twice.

For information about the project.max-locked-memory and zone.max-locked_memory resource controls on Oracle Solaris systems with zones installed, see Resource Management and Oracle Solaris Zones Developer’s Guide and see resource_controls(5).

The following example shows how to allocate kernel memory for application access. The driver exports one page of kernel memory, which is used by multiple applications as a shared memory area. The memory is allocated in segmap(9E) when an application maps the shared page the first time. An additional page is allocated if the driver has to support multiple application data models. For example, a 64-bit driver might export memory both to 64-bit applications and to 32-bit applications. 64-bit applications share the first page, and 32-bit applications share the second page.

Example 10-4  Using the ddi_umem_alloc() Routine
static int
xxsegmap(dev_t dev, off_t off, struct as *asp, caddr_t *addrp, off_t len,
    unsigned int prot, unsigned int maxprot, unsigned int flags, 
    cred_t *credp)
{
    int error;
    minor_t instance = getminor(dev);
    struct xxstate *xsp = ddi_get_soft_state(statep, instance);

    size_t mem_size;
        /* 64-bit driver supports 64-bit and 32-bit applications */
    switch (ddi_mmap_get_model()) {
        case DDI_MODEL_LP64:
             mem_size = ptob(2);
             break;
        case DDI_MODEL_ILP32:
             mem_size = ptob(1);
             break;
    }

    mutex_enter(&xsp->mu);
    if (xsp->umem == NULL) {
        /* allocate the shared area as kernel pageable memory */
        xsp->umem = ddi_umem_alloc(mem_size,
            DDI_UMEM_SLEEP | DDI_UMEM_PAGEABLE, &xsp->ucookie);
    }
    mutex_exit(&xsp->mu);
    /* Set up the user mapping */
    error = devmap_setup(dev, (offset_t)off, asp, addrp, len,
        prot, maxprot, flags, credp);
    return (error);
}