编写设备驱动程序

为用户访问分配内核内存

使用 ddi_umem_alloc(9F) 可以分配导出到应用程序的内核内存。 ddi_umem_alloc() 的语法如下所示:

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

其中:

size

要分配的字节数。

flag

用于确定休眠条件和内存类型。

cookiep

指向内核内存 cookie 的指针。

ddi_umem_alloc(9F) 分配按页对齐的内核内存。ddi_umem_alloc () 返回一个指向所分配内存的指针。最初,内存被零填充。分配的字节数是系统页面大小的倍数,该页面大小是通过 size 参数向上舍入得到的。分配的内存可在内核中使用。此内存也可导出到应用程序。cookiep 是指向用来描述所分配的内核内存的内核内存 cookie 的指针。驱动程序将内核内存导出到用户应用程序时,devmap_umem_setup(9F) 中会使用 cookiep

flag 参数用于指示 ddi_umem_alloc(9F) 是立即阻塞还是返回,以及分配的内核内存是否可换页。flag 参数的值如下所示:

DDI_UMEM_NOSLEEP

驱动程序无需等待内存成为可用。如果内存不可用,则返回 NULL

DDI_UMEM_SLEEP

驱动程序可以无限等待,直到内存可用为止。

DDI_UMEM_PAGEABLE

驱动程序允许内存页被换出。如果未设置,则锁定内存。

ddi_umem_lock() 函数可以执行设备锁定内存检查。此函数针对 project.max-locked-memory 中指定的限制值进行检查。如果当前项目的锁定内存使用量低于限制,则会增加项目的锁定内存字节计数。进行限制检查后,内存将会锁定。ddi_umem_unlock() 函数可以解除锁定内存,从而减少项目的锁定内存字节计数。

其中所用的记帐方法是不严密的 "full price"(足价)模式。例如,对于同一项目中 umem_lockmemory() 的具有重叠内存区域的两个调用程序会被计数两次。

有关 project.max-locked-memoryzone.max-locked_memory 对安装了区域的 Solaris 系统的资源控制的信息,请参见《Solaris 10 资源管理器开发者指南》resource_controls(5)

以下示例说明如何为应用程序访问分配内核内存。驱动程序会导出一页内核内存,它将被多个应用程序用作共享存储区。应用程序第一次映射共享页时,会在 segmap(9E) 中分配内存。如果驱动程序必须支持多个应用程序数据模型,则会再分配一页。例如,64 位驱动程序可能同时将内存导出到 64 位应用程序和 32 位应用程序。64 位应用程序共享第一页,32 位应用程序共享第二页。


示例 10–4 使用 ddi_umem_alloc() 例程

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