用户态驱动
描述
用户态驱动作为内核功能的拓展,一般都是对物理设备的接口封装和抽象。 在内核中会有一些基础的驱动,和内核一起编译。 但是,在有些情况下,驱动程序由于硬件状态的改变,导致程序崩溃,那么就会影响内核,因此可以把驱动放到用户态, 可以避免由于驱动程序的崩溃导致内核故障。
内核需要做的就是对设备资源的抽象,并暴露一些接口给用户态驱动去使用,用户可以根据这些接口来开发驱动。
其中,最为核心的功能就是对中断的处理,如何及时响应中断,并对中断进行应答,是我们需要去研究的重要内容。
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, ¶m, &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, ¶m, &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, ¶m, &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, ¶m, &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, ¶m, &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, ¶m, &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;
}