Writing Device Drivers

Allocating Kernel Memory for User Access

ddi_umem_alloc(9F) is provided to allocate kernel memory that is exported to applications:

void *ddi_umem_alloc(size_t size, int flag, ddi_umem_cookie_t *cookiep);            
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 and returns a pointer to the allocated memory. The initial contents of the memory is zero-filled. The number of bytes allocated is a multiple of the system page size (roundup of size). The allocated memory can be used in the kernel and can be exported to applications. cookiep is a pointer to the kernel memory cookie that describes the kernel memory being allocated. It 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) will block or return immediately, and whether the allocated kernel memory is pageable. Table 12-1 lists the values for flag.

Table 12-1 ddi_umem_alloc(9F) flag Values

Values 

Indicated Action 

DDI_UMEM_NOSLEEP

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

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. 

Example 12-2 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 exporting memory to 64-bit and 32-bit applications). 64-bit applications share the first page, and 32-bit applications share the second page.


Example 12-2 ddi_umem_alloc(9F) 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;
        #ifdef  _MULTI_DATAMODEL
            /* 64-bit driver supports 64-bit and 32-bit applications */
                mem_size = ptob(2);
        #else
                mem_size = ptob(1);
        #endif /* _MULTI_DATAMODEL */

        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);
}