编写设备驱动程序

将内核内存导出到应用程序

使用 devmap_umem_setup(9F) 可将内核内存导出到用户应用程序。devmap_umem_setup() 必须通过驱动程序的 devmap(9E) 入口点进行调用 。devmap_umem_setup() 的语法如下所示:

int devmap_umem_setup(devmap_cookie_t handle, dev_info_t *dip,
    struct devmap_callback_ctl *callbackops, ddi_umem_cookie_t cookie,
    offset_t koff, size_t len, uint_t maxprot, uint_t flags,
    ddi_device_acc_attr_t *accattrp);

其中:

handle

用于描述映射的不透明结构。

dip

指向设备的 dev_info 结构的指针。

callbackops

指向 devmap_callback_ctl(9S) 结构的指针。

cookie

ddi_umem_alloc(9F) 返回的内核内存 cookie。

koff

cookie 指定的内核内存中的偏移。

len

导出的长度(以字节为单位)。

maxprot

用于为导出的映射指定可能的最大保护。

flags

必须设置为 DEVMAP_DEFAULTS

accattrp

指向 ddi_device_acc_attr(9S) 结构的指针。

handle 是系统用来标识映射的设备映射句柄。handle 通过 devmap(9E) 入口点传入。dip 是指向设备的 dev_info 结构的指针。callbackops 允许向驱动程序通知有关映射的用户事件。导出内核内存时,大多数驱动程序都会将 callbackops 设置为 NULL

kofflen 用于在 ddi_umem_alloc(9F) 分配的内核内存中指定一个范围。如果用户的应用程序映射位于通过 devmap(9E) 入口点传入的偏移上,则可对此范围进行访问。驱动程序通常将 devmap(9E) 偏移直接传递给 devmap_umem_setup(9F)。然后,mmap(2) 的返回地址将映射到 ddi_umem_alloc(9F) 返回的内核地址。kofflen 必须按页对齐。

通过 maxprot,驱动程序可为导出的内核内存中的不同区域指定不同的保护。例如,通过仅设置 PROT_READPROT_USER,一个区域可能不允许写访问。

以下示例说明如何将内核内存导出到应用程序。驱动程序首先检查请求的映射是否位于分配的内核内存区域之内。如果 64 位驱动程序收到来自 32 位应用程序的映射请求,则会将该请求重定向到内核存储区的第二页。此重定向可确保仅有编译到相同数据模型的应用程序才能共享相同的页。


示例 10–5 devmap_umem_setup(9F) 例程

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;

    /* round up len to a multiple of a page size */
    len = ptob(btopr(len));
    /* check if the requested range is ok */
    if (off + len > ptob(1))
        return (ENXIO);
    xsp = ddi_get_soft_state(statep, getminor(dev));
    if (xsp == NULL)
        return (ENXIO);

    if (ddi_model_convert_from(model) == DDI_MODEL_ILP32)
        /* request from 32-bit application. Skip first page */
        off += ptob(1);

    /* export the memory to the application */
    error = devmap_umem_setup(handle, xsp->dip, NULL, xsp->ucookie,
        off, len, PROT_ALL, DEVMAP_DEFAULTS, NULL);
    *maplen = len;
    return (error);
}