用户态驱动

描述

用户态驱动作为内核功能的拓展,一般都是对物理设备的接口封装和抽象。 在内核中会有一些基础的驱动,和内核一起编译。 但是,在有些情况下,驱动程序由于硬件状态的改变,导致程序崩溃,那么就会影响内核,因此可以把驱动放到用户态, 可以避免由于驱动程序的崩溃导致内核故障。

内核需要做的就是对设备资源的抽象,并暴露一些接口给用户态驱动去使用,用户可以根据这些接口来开发驱动。

其中,最为核心的功能就是对中断的处理,如何及时响应中断,并对中断进行应答,是我们需要去研究的重要内容。

NXOS 采取的策略是内核和用户态相结合,而不是所有的操作都是通过用户自己去完成。 因此,内核需要对某个驱动的开发做一定底层的抽象与封装,并暴露接口给用户驱动使用。

用户态驱动框架

功能支持

在用户态中也支持了NX_Device和NX_Driver等结构,可以跟在内核中一样使用。

当执行NX_DriverRegister的时候就会注册改驱动信息到内核结构体中,从此便可以通过通用的设备接口访问改设备了。

具体实现,依赖于内核的udrver驱动框架来实现。通过 hub 机制转发操作请求到用户态驱动,驱动执行完成后返回,即可完成改操作。

  • 文件:src/drivers/udriver/udriver.c
/**
 * Copyright (c) 2018-2022, NXOS Development Team
 * SPDX-License-Identifier: Apache-2.0
 * 
 * Contains: udriver driver
 * 
 * Change Logs:
 * Date           Author            Notes
 * 2022-3-15      JasonHu           Init
 */

#include <base/driver.h>

#define NX_LOG_NAME "udriver"
#include <base/log.h>
#include <base/hub.h>
#include <base/string.h>
#include <base/malloc.h>
#include <base/debug.h>
#include <base/uaccess.h>

#define UDRIVER_HUB_PREFIX "udrv_"

typedef struct DriverExtension
{
    NX_UserDriver * udrv; /* user driver */
    char hubName[NX_HUB_NAME_LEN];   /* udriver hub name */
} DriverExtension;

enum UdriverOpsAPI
{
    UDRIVER_OPS_OPEN = 0,
    UDRIVER_OPS_CLOSE,
    UDRIVER_OPS_READ,
    UDRIVER_OPS_WRITE,
    UDRIVER_OPS_CONTROL,
    UDRIVER_OPS_MAPPABLE,
};

NX_PRIVATE NX_Error UdriverOpen(struct NX_Device *device, NX_U32 flags)
{
    NX_Error err;
    NX_Driver * kdrv;
    NX_UserDevice * udev;
    NX_Size retVal = 0;
    NX_HubParam param;
    DriverExtension * drvext;

    kdrv = device->driver;
    udev = (NX_UserDevice * )device->extension;
    drvext = (DriverExtension * )kdrv->extension;

    param.api = UDRIVER_OPS_OPEN;
    param.args[0] = (NX_Size)drvext->udrv;
    param.args[1] = (NX_Size)udev;
    param.args[2] = (NX_Size)flags;

    if ((err = NX_HubCallParamName(drvext->hubName, &param, &retVal)) != NX_EOK)
    {
        return err;
    }

    return retVal;
}

NX_PRIVATE NX_Error UdriverClose(struct NX_Device *device)
{
    NX_Error err;
    NX_Driver * kdrv;
    NX_UserDevice * udev;
    NX_Size retVal = 0;
    NX_HubParam param;
    DriverExtension * drvext;

    kdrv = device->driver;
    udev = (NX_UserDevice * )device->extension;
    drvext = (DriverExtension * )kdrv->extension;

    param.api = UDRIVER_OPS_CLOSE;
    param.args[0] = (NX_Size)drvext->udrv;
    param.args[1] = (NX_Size)udev;

    if ((err = NX_HubCallParamName(drvext->hubName, &param, &retVal)) != NX_EOK)
    {
        return err;
    }

    return retVal;
}

NX_PRIVATE NX_Error UdriverRead(struct NX_Device *device, void *buf, NX_Offset off, NX_Size len, NX_Size *outLen)
{
    NX_Error err;
    NX_Driver * kdrv;
    NX_UserDevice * udev;
    NX_Size retVal = 0;
    NX_HubParam param;
    DriverExtension * drvext;

    kdrv = device->driver;
    udev = (NX_UserDevice * )device->extension;
    drvext = (DriverExtension * )kdrv->extension;

    param.api = UDRIVER_OPS_READ;
    param.args[0] = (NX_Size)drvext->udrv;
    param.args[1] = (NX_Size)udev;
    param.args[2] = (NX_Size)buf;
    param.args[3] = (NX_Size)off;
    param.args[4] = (NX_Size)len;
    param.args[5] = (NX_Size)outLen;

    if ((err = NX_HubCallParamName(drvext->hubName, &param, &retVal)) != NX_EOK)
    {
        return err;
    }
    return retVal;
}

NX_PRIVATE NX_Error UdriverWrite(struct NX_Device *device, void *buf, NX_Offset off, NX_Size len, NX_Size *outLen)
{
    NX_Error err;
    NX_Driver * kdrv;
    NX_UserDevice * udev;
    NX_Size retVal = 0;
    NX_HubParam param;
    DriverExtension * drvext;

    kdrv = device->driver;
    udev = (NX_UserDevice * )device->extension;
    drvext = (DriverExtension * )kdrv->extension;

    param.api = UDRIVER_OPS_WRITE;
    param.args[0] = (NX_Size)drvext->udrv;
    param.args[1] = (NX_Size)udev;
    param.args[2] = (NX_Size)buf;
    param.args[3] = (NX_Size)off;
    param.args[4] = (NX_Size)len;
    param.args[5] = (NX_Size)outLen;

    if ((err = NX_HubCallParamName(drvext->hubName, &param, &retVal)) != NX_EOK)
    {
        return err;
    }
    return retVal;
}

NX_PRIVATE NX_Error UdriverControl(struct NX_Device *device, NX_U32 cmd, void *arg)
{
    NX_Error err;
    NX_Driver * kdrv;
    NX_UserDevice * udev;
    NX_Size retVal = 0;
    NX_HubParam param;
    DriverExtension * drvext;

    kdrv = device->driver;
    udev = (NX_UserDevice * )device->extension;
    drvext = (DriverExtension * )kdrv->extension;

    param.api = UDRIVER_OPS_CONTROL;
    param.args[0] = (NX_Size)drvext->udrv;
    param.args[1] = (NX_Size)udev;
    param.args[2] = (NX_Size)cmd;
    param.args[3] = (NX_Size)arg;

    if ((err = NX_HubCallParamName(drvext->hubName, &param, &retVal)) != NX_EOK)
    {
        return err;
    }

    return retVal;
}

NX_PRIVATE NX_Error UdriverMappable(struct NX_Device *device, NX_Size length, NX_U32 prot, NX_Addr * outPhyAddr)
{
    NX_Error err;
    NX_Driver * kdrv;
    NX_UserDevice * udev;
    NX_Size retVal = 0;
    NX_HubParam param;
    DriverExtension * drvext;

    kdrv = device->driver;
    udev = (NX_UserDevice * )device->extension;
    drvext = (DriverExtension * )kdrv->extension;

    param.api = UDRIVER_OPS_MAPPABLE;
    param.args[0] = (NX_Size)drvext->udrv;
    param.args[1] = (NX_Size)udev;
    param.args[2] = (NX_Size)length;
    param.args[3] = (NX_Size)prot;
    param.args[4] = (NX_Size)outPhyAddr;

    if ((err = NX_HubCallParamName(drvext->hubName, &param, &retVal)) != NX_EOK)
    {
        return err;
    }

    return retVal;
}

NX_PRIVATE NX_DriverOps UdriverDriverOps = {
    .open = UdriverOpen,
    .close = UdriverClose,
    .read = UdriverRead,
    .write = UdriverWrite,
    .control = UdriverControl,
    .mappable = UdriverMappable,
};

NX_PRIVATE NX_Error UdriverUnregister(NX_Driver * drv)
{
    DriverExtension * drvext;
    NX_Error err;

    if (!drv)
    {
        return NX_EINVAL;
    }

    drvext = (DriverExtension * )drv->extension;

    if ((err = NX_HubUnregister(drvext->hubName)) != NX_EOK)
    {
        NX_LOG_W("udriver %s unregister hub %s failed with error %s!", drv->name, drvext->hubName, NX_ErrorToString(err));
        return err;
    }

    NX_Device *device, *n;
    NX_ListForEachEntrySafe(device, n, &drv->deviceListHead, list)
    {
        NX_DriverDetachDevice(drv, device->name);
    }
    if (drv->extension)
    {
        NX_MemFree(drv->extension);
    }
    NX_DriverUnregister(drv);
    NX_DriverDestroy(drv);
    return NX_EOK;
}

NX_PRIVATE NX_Error UdriverCloseSolt(void * object, NX_ExposedObjectType type)
{
    NX_Driver * drv;

    if (type != NX_EXOBJ_UDRIVER)
    {
        return NX_ENORES;
    }

    drv = (NX_Driver *) object;
    NX_ASSERT(drv);

    return UdriverUnregister(drv);
}

NX_Error NX_UserDriverRegister(NX_UserDriver * drv, NX_Solt * outSolt)
{
    if (!drv)
    {
        return NX_EINVAL;
    }

    NX_Solt solt = NX_SOLT_INVALID_VALUE;
    NX_Error err;
    DriverExtension * drvext;
    NX_Device *device;
    char hubName[NX_HUB_NAME_LEN + 1] = {0};
    NX_Driver *driver = NX_DriverCreate(drv->name, drv->type, drv->flags, &UdriverDriverOps);
    if (driver == NX_NULL)
    {
        NX_LOG_E("create udriver %s failed!", drv->name);
        return NX_ENOMEM;
    }

    drvext = NX_MemAlloc(sizeof(DriverExtension));
    if (drvext == NX_NULL)
    {
        NX_LOG_E("alloc udriver %s extension failed!", drv->name);
        NX_DriverDestroy(driver);
        return NX_ENOMEM;
    }

    drvext->udrv = drv;
    NX_StrCopy(hubName, UDRIVER_HUB_PREFIX);
    NX_StrCat(hubName, drv->name);
    NX_StrCopy(drvext->hubName, hubName);

    driver->extension = drvext;

    /* register hub server */
    if ((err = NX_HubRegister(hubName, 1, NX_NULL)) != NX_EOK) /* driver only opened onece */
    {
        NX_LOG_E("udriver %s register hub %s failed with err %s!", drv->name, hubName, NX_ErrorToString(err));
        NX_MemFree(drvext);
        NX_DriverDestroy(driver);
        return err;
    }

    NX_UserDevice * userDev;

    NX_ListForEachEntry (userDev, &drv->deviceListHead, list)
    {
        if ((err = NX_DriverAttachDevice(driver, userDev->name, &device)) != NX_EOK)
        {
            NX_LOG_E("udriver %s attach device %s failed with err %s!", drv->name, userDev->name, NX_ErrorToString(err));
            NX_HubUnregister(hubName);
            NX_MemFree(drvext);
            NX_DriverCleanup(drv->name);
            return NX_ENOMEM;
        }
        device->extension = userDev;
    }

    if ((err = NX_DriverRegister(driver)) != NX_EOK)
    {
        NX_LOG_E("udriver %s register failed with err %s!", drv->name, NX_ErrorToString(err));
        NX_HubUnregister(hubName);
        NX_MemFree(drvext);
        NX_DriverCleanup(drv->name);
        return err;
    }

    /* install udriver exobj */
    if (NX_ProcessInstallSolt(NX_ProcessCurrent(), driver, NX_EXOBJ_UDRIVER, UdriverCloseSolt, &solt) != NX_EOK)
    {
        NX_LOG_E("udriver %s install failed with err %s!", drv->name, NX_ErrorToString(err));
        NX_HubUnregister(hubName);
        NX_MemFree(drvext);
        NX_DriverCleanup(drv->name);
        return err;
    }

    if (outSolt)
    {
        NX_CopyToUser((char *)outSolt, (char *)&solt, sizeof(solt));
    }

    return err;
}

results matching ""

    No results matching ""