当前位置: 首页 > 科技观察

OpenHarmony-HDF驱动框架介绍及加载过程分析_0

时间:2023-03-13 06:19:13 科技观察

更多内容请访问:51CTO与华为官方共建鸿蒙技术社区https://ost.51cto.com前言HarmonyOS面向万物互联时代,而万物互联涉及到大量的硬件设备。这些硬件具有高度的离散性,其性能和配置差异很大。因此,这就需要使用更灵活、更强大、功耗更低的Drive框架。OpenHarmony系统的HDF驱动框架采用C语言面向对象编程模型构建。通过平台解耦和内核解耦,达到兼容不同内核,统一平台基础的目的,从而帮助开发者实现一次驱动开发,多系统部署的效果。1、HDF驱动框架OpenHarmony系统HDF驱动框架主要由四部分组成:驱动基础框架、驱动程序、驱动配置文件和驱动接口。(1)HDF驱动基础设施提供统一的硬件资源管理、驱动加载管理、设备节点管理。驱动框架采用主从模式设计,由DeviceManager和DeviceHost组成。设备管理器提供统一的驱动程序管理。DeviceManager启动时,根据DeviceInformation提供的驱动设备信息加载对应的驱动DeviceHost,并控制Host完成驱动加载。DeviceHost为驱动程序提供运行环境,同时预置HostFramework配合DeviceManager完成驱动程序的加载和调用。根据业务需要,DeviceHost可以有多个实例。(2)驱动程序实现了驱动程序的具体功能。每个驱动由一个或多个驱动组成,每个驱动对应一个DriverEntry。DriverEntry主要完成驱动初始化和驱动接口绑定功能。(3)驱动配置文件.hcs主要由DeviceInformation和DeviceResource组成。设备信息完成设备信息的配置。例如配置接口发布策略,加载驱动的方式等。DeviceResource完成设备资源的配置。比如GPIO管脚、寄存器等资源信息的配置。(4)驱动接口HDI(HardwareDriverinterface)提供标准化的接口定义和实现,驱动框架提供IOService和IODispatcher机制,使得驱动接口在不同的部署形式下趋于一致。HDF框架以组件化驱动模型为核心设计思想,为开发者提供更精细化的驱动管理,使驱动开发部署更加规范。HDF框架将一类设备驱动放在同一个宿主机中,开发者也可以分层独立开发和部署驱动功能,支持一个驱动多节点。HDF驱动模型如下图所示:2.HDF驱动开发基于HDF驱动开发框架主要分为驱动实现和驱动配置两部分。详细的开发流程如下:2.1驱动实现驱动实现包括驱动业务代码和驱动入口注册。2.1.1驱动业务代码//驱动对外提供的服务能力,将相关服务接口绑定到HDF框架。int32_tHdfSampleDriverBind(structHdfDeviceObject*deviceObject){HDF_LOGD("示例驱动绑定成功");返回0;}//驱动自身业务初始化的接口。int32_tHdfSampleDriverInit(structHdfDeviceObject*deviceObject){HDF_LOGD("示例驱动初始化成功");返回0;}//驱动资源释放接口。voidHdfSampleDriverRelease(structHdfDeviceObject*deviceObject){HDF_LOGD("示例驱动发布成功");返回;}2.1.2将驱动入口注册到HDF框架//定义驱动入口的对象必须是HdfDriverEntry(在hdf_device_desc.h中定义)structHdfDriverEntry类型的全局变量g_sampleDriverEntry={.moduleVersion=1,.moduleName="sample_driver",.Bind=HdfSampleDriverBind,.Init=HdfSampleDriverInit,.Release=HdfSampleDriverRelease,};HDF_INIT(g_sampleDriverEntry);//IT会调用HDF框架中的驱动入口HDF_IN注册。在加载驱动时,HDF框架会先调用Bind函数,然后调用Init函数加载驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。2.2驱动配置驱动配置包括两部分,HDF框架定义的驱动设备的描述和驱动的私有配置信息。HDF使用HCS作为配置描述源码,内容以Key-Value键值对形式为主。实现了配置代码和驱动代码的解耦,方便开发者管理配置。HC-GEN(全称HDFConfigurationGenerator)是一款HCS配置转换工具,可以将HDF配置文件转换成软件可以读取的文件格式:在性能较弱的环境下,转换成配置树源码,以及驱动可以直接调用C代码获取配置;在高性能环境下,转换为HCB(HDFConfigurationBinary)二进制文件,驱动可以使用HDF框架提供的配置解析接口获取配置.HCS由HC-GEN编译生成HCB文件。HDF驱动程序框架中的HCS解析器模块将从HCB文件重建配置树。HDF驱动模块使用HCSParser提供的配置读取接口获取配置内容。驱动配置过程示意图如下:2.2.1驱动设备描述(必填)HDF框架加载驱动所需的信息来自于HDF框架定义的驱动设备描述,因此开发的驱动基于HDF框架必须在HDF框架定义的device_info.hcs配置文件中添加相应的设备描述,驱动的设备描述填写如下:sample_host::host{hostName="host0";//hostname,host节点用于存放某类驱动容器。优先级=100;//主机启动优先级(0-200),值越大优先级越低。建议默认配置100。如果优先级相同,则无法保证主机的加载顺序。device_sample::device{//示例设备节点。device0::deviceNode{//样本驱动的DeviceNode节点。政策=1;//司机服务发布策略priority=100;//驱动启动优先级(0-200),值越大优先级越低,建议默认配置100,相同优先级不保证设备的加载顺序preload=0;//驱动按需加载字段permission=0664;//驱动创建设备节点权限moduleName="sample_driver";//驱动名称,该字段的值必须与驱动入口结构体的moduleName值保持一致serviceName="sample_service";//驱动对外发布服务的名称必须是唯一的deviceMatchAttr="sample_config";//驱动私有数据匹配的关键字必须等于驱动私有数据配置表中的match_attr值。}}}2.2.2驱动私有配置信息(可选)如果驱动有私有配置,可以添加一个驱动配置文件,填写一些驱动默认配置信息。当HDF框架加载驱动程序时,会获取配置信息并将其存储在HdfDeviceObject的属性中,并通过Bind和Init传递给驱动程序。驱动配置信息示例如下:root{SampleDriverConfig{sample_version=1;样本总线=“I2C_0”;match_attr="sample_config";//该字段的值必须与device_info.hcs中deviceMatchAttr的值一致}}3.HDF驱动加载HDF驱动加载包括按需加载和顺序加载。按需加载是指HDF框架支持驱动在系统启动过程中默认加载,或者系统启动后动态加载;顺序加载是指HDF框架支持在系统启动过程中根据驱动的优先级来加载驱动。HDF框架定义的驱动按需加载模式的策略由配置文件中的preload字段控制。preload字段的取值范围和含义如下:驱动程序的顺序加载是通过配置文件中的优先级(取值范围是0到200的整数),优先级值越小,优先级越高。驱动程序的加载顺序是根据宿主机的优先级优先确定的。如果宿主机的优先级相同,则根据驱动程序在宿主机中的优先级值确定加载顺序。3.1HDF_INIT宏扩展驱动入口注册到HDF框架,会调用HDF_INIT函数将驱动入口地址注册到HDF框架。#defineHDF_SECTION__attribute__((section(“.hdf.driver”)))#defineHDF_DRIVER_INIT(module)\constsize_tUSED_ATTRmodule##HdfEntryHDF_SECTION=(size_t)(&(module))可以看到HDF_INIT宏定义了一个“驱动模块名+HdfEntry”的符号放在“.hdf.driver”所在的段中,该符号指向的内存地址就是驱动入口结构的地址。这个特殊部分将用于在引导时查找设备驱动程序。3.2获取驱动列表HDF驱动框架通过在一个特殊的section中存储驱动入口符号的地址来实现对驱动的索引。在这个section的开头和结尾插入两个特殊符号_hdf_drivers_start和_hdf_drivers_end来标记这个section的范围,两个特殊符号之间的数据就是驱动实现指针。3.3获取设备列表配置文本编译后会成为一个二进制格式的配置文件,其中设备相关的信息存放在一个标有“hdf_manager”的device_info配置块中,host的内容在device_info中依次排列以块的形式块。主机块记录主机名、启动优先级和设备列表信息。设备信息中的moduleName字段将用于匹配驱动入口中的moduleName,为设备匹配正确的驱动,完成设备与驱动的匹配。具体流程图如下:3.4驱动框架启动late_initcall宏展开。__define_initcall宏扩展。___define_initcall宏扩展。宏含义:(1)声明一个函数指针,类型为initcall_t,名称为__initcall_DeviceManagerInit。(2)将该函数指针初始化为DeviceManagerInit。(3)编译时,需要将这个函数指针变量放在名为“.initcall7.init”的段中。其实质就是把函数DeviceManagerInit的首地址放在这个.initcall7.init段。内核初始化的内存映射:__init用来标记初始化函数,初始化后不会调用,__initdata是初始化数据,__initparam是初始化参数,另外7个初始化宏是给初始化函数使用的。是时候按下了。按照.initcall1.init->.initcall7.init的顺序进行初始化。do_basic_setup执行.initcall1.init->.initcall7.init的顺序初始化。4.总结(1)系统启动时,DeviceManagerInit首先通过late_initcall启动。(2)DeviceManager根据DeviceInformation信息解析配置文件中的Host列表,并根据Host列表中的信息实例化对应的Host对象。(3)Host遍历设备列表获取匹配的驱动名,然后根据驱动名遍历.hdf.driver段获取驱动地址。(4)设备与驱动匹配成功后,获取指定驱动的入口地址,加载对应的设备驱动。()调用指定驱动的Bind接口将设备与服务实例相关联。(6)调用指定驱动的Init接口,完成驱动的相关初始化工作。(7)如果驱动被卸载或者由于硬件等原因导致Init接口返回失败,将调用Release释放驱动请求的各种资源。更多资讯请浏览:?????????????????????????????????????????????????????????