冬雨财经 发表于 2024-9-26 18:51:53

HarmonyOS驱动加载过程分析

一、HarmonyOS驱动概述
         HarmonyOS驱动框架接纳C语言面向对象编程模型构建,通过平台解耦、内核解耦,来达到兼容不同内核,统一平台底座的目标,从而帮助开发者实现驱动的“一次开发,多系统部署”。
         为了告竣这个目标, HarmonyOS驱动框架提供了:
         1. 操作系统适配层(OSAL,operating system abstraction layer):提供内核操作相干接口进行统一封装,屏蔽不同系统操作接口。
         2. 平台驱动接口:提供Board部门驱动(例如:I2C/SPI/UART总线等平台资源)支持,同时对Board硬件操作接口进行统一的适配抽象,开发者只需开发新硬件抽象接口,即可获得新增Board部门驱动支持。
         3. 驱动模型:面向器件驱动,提供常见的驱动抽象模型,主要告竣两个目标:
         ● 提供标准化的器件驱动,开发者无需独立开发,通过配置即可完成驱动的部署。
         ● 提供驱动模型抽象,屏蔽驱动与不同系统组件间的交互,使得驱动更具备通用性。
         为了进一步简化HarmonyOS驱动开发,HarmonyOS驱动框架支持多种驱动加载方式:
         ● 支持驱动动态加载和静态加载,排除驱动代码和框架间的直接代码依靠,使得驱动步伐可以独立编译和部署;
         ● 支持按需动态加载方式,避免装备驱动全量加载,可有用降低系统资源的占用。
         本文主要分析HarmonyOS驱动加载过程,在正式介绍之前,起首了解HarmonyOS驱动架构的组成、工作原理和机制,从而了解驱动加载的细节。
         官网相干介绍:文档中心
二、HarmonyOS驱动架构介绍
2.1 HarmonyOS驱动架构组成

https://img-blog.csdnimg.cn/img_convert/3e5aefa0515540e070ff2c3d3d76d93a.png

图1 HarmonyOS驱动架构
         HarmonyOS驱动架构主要由HDF驱动框架、驱动步伐、驱动配置文件和驱动接口四个部门组成。
         1)HDF驱动框架提供统一的硬件资源管理,驱动加载管理以及装备节点管理等功能。
        驱动框架接纳的是主从模式设计,由Device Manager和Device Host组成。
        Device Manager提供了统一的驱动管理,Device Manager启动时根据Device Information提供驱动装备信息加载相应的驱动Device Host,并控制Host完成驱动的加载。
         Device Host提供驱动运行的情况,同时预置Host Framework与Device Manager进行协同,完成驱动加载和调用。根据业务的需求Device Host可以有多个实例。
         阐明:
         Device Host顾名思义就是驱动宿主,提供驱动运行的情况。
         当驱动部署在用户态时,Device Host可以由独立的进程进行承载。
         当驱动在部署在内核态时,Device Host仅表示逻辑隔离。
         Device Host的分别原则:Device Host属于一类装备聚合,如Camera,Audio,Display等。
         驱动步伐是部署在一个Device Host还是部署在不同的Device Host,主要思量驱动步伐之间是否存的业务耦合性,如果两个驱动步伐之间存在依靠,可以思量将这部门驱动步伐部署在统一Host。
         2)驱动步伐实现驱动的具体功能,每个驱动由一个大概多个驱动步伐组成,每个驱动步伐都对应着一个Driver Entry。Driver Entry主要完成驱动的初始化和驱动接口绑定功能。
         3)驱动配置文件.hcs主要由装备信息(Device Information)和装备资源(Device Resource)组成。
         Device Information完成装备信息的配置,如配置接口发布计谋,驱动加载的方式等。Device Resource 完成装备资源的配置,如GPIO管脚、寄存器等资源信息的配置。
         4)驱动接口HDI(Hardware Driver interface )提供标准化的接口界说和实现,驱动框架提供IO Service和IO Dispatcher机制,使得不同部署形态下驱动接口趋于形式一致。
         当驱动部署在RTOS(Real-Time Operating System)轻量化操作系统时,驱动接口和驱动步伐之间接纳的是Function Call方式调用,因此驱动接口仅提供界说,驱动接口实现由驱动步伐提供。
2.2 HDF驱动框架工作原理

https://img-blog.csdnimg.cn/img_convert/f6d39e680675caa84b6d092acc2269a8.png
 
图2 HDF驱动框架工作原理
         Device Manager提供了统一的驱动加载管理机制和驱动接口发布机制。
         当Device Host情况加载完成时,Device Manager根据Device Information信息,请求Host加载相应的驱动步伐,Device Host在收到请求时,进行以下操作:
         1)根据请求加载装备信息,查找并加载指定路径下驱动镜像或从指定段地点(section)查找驱动步伐入口;
         2)查找驱动装备形貌符,匹配对应的装备驱动;
         3)当驱动匹配成功时,加载指定驱动步伐镜像;
         4)Host Framework在驱动镜像加载成功后,调用驱动步伐(Driver Entry)的绑定接口和初始化接口,实现与驱动步伐的服务对象绑定,同时初始化装备驱动步伐;
         5)当Device Information配置中的服务计谋要求对外暴露驱动接口时,驱动框架就将驱动步伐的服务对象添加到对外发布的服务对象列表中,外部客户端步伐就可以通过此列表来查询并访问相应的服务接口。
2.3 驱动接口工作机制

https://img-blog.csdnimg.cn/img_convert/8d58338dd9a5061d1695e84e34650840.png

图3 驱动接口工作机制
         驱动接口主要存在以下几种实现:
         ● 当驱动以内核组件部署时,客户端步伐访问驱动步伐需要通过system call方式调用,驱动接口通过IO Service请求将消息通过system call方式调用到内核,并将消息分发到IO Dispatcher处理惩罚。
         ● 当驱动以用户态服务形式部署时,客户端进程访问驱动进程需要通过IPC方式通信,IO Service完成IPC通信的客户端消息请求封装,IO Dispacher完成驱动服务端消息请求封装,客户端消息通过IPC通信到达服务端并分发给IO Dispacher处理惩罚。
         为了使客户端和服务端驱动调用方式基本一致,驱动框架提供IO Service和IO Dispatcher机制屏蔽了调用消息传递方式的差异。
         驱动接口实现统一接纳长途调用方式,客户端驱动接口函数将请求序列化成内存数据,通过驱动框架提供的IO Service将消息发送到服务端处理惩罚,服务端在收到请求消息时通过IO Dispatcher机制将消息分发给消息处理惩罚函数处理惩罚,处理惩罚函数将反序列化内存数据解析成相应的请求。如许的做到好处是,开发者只需重点关注接口的界说,无需过多的关注怎样实现不同平台上接口适配。
三、驱动加载过程分析
         HarmonyOS驱动根据部署的不同方式,存在两种驱动加载方式:
         ● 动态加载方式:接纳传统的so(共享库)加载方式,驱动步伐通过指定Symbol找到驱动函数入口进行加载。
         ● 静态加载方式:接纳将驱动步伐通过Scatter编译方式,编译到指定的Section,再通过访问指定Section对应的地点,找到驱动函数入口进行加载。
       下面结合一个Sample示例代码,讲解驱动加载过程,重点分析静态加载方式下内核态驱动加载过程。
3.1 实现驱动步伐初始化接口
         在HDF驱动框架中,HdfDriverEntry对象被用来形貌一个驱动实现。
<span style="background-color:#f0f0f0"><span style="color:black"><strong>struct</strong> HdfDriverEntry {
       int32_t moduleVersion;
       <strong>const</strong> <strong>char</strong> *moduleName;
       int32_t (*Bind)(<strong>struct</strong> HdfDeviceObject *deviceObject);
       int32_t (*Init)(<strong>struct</strong> HdfDeviceObject *deviceObject);
       <strong>void</strong> (*Release)(<strong>struct</strong> HdfDeviceObject *deviceObject);
};</span></span>          编写一个简单的驱动,起首需要实现驱动步伐 (Driver Entry)入口中的三个主要接口:
         ■ Bind接口:
         实现驱动接口实例化绑定,如果需要发布驱动接口,会在驱动加载过程中被调用,实例化该接口的驱动服务并和DeviceObject绑定。
         ■ Init接口:
         实现驱动的初始化,返回错误将中止驱动加载流程。
         ■ Release接口:
         实现驱动的卸载,在该接口中开释驱动实例的软硬件资源。
<span style="background-color:#f0f0f0"><span style="color:black"><strong>int</strong> SampleDriverBind(<strong>struct</strong> HdfDeviceObject *deviceObject)
 {
        HDF_LOGE(<span style="color:#880000">"SampleDriverBind enter!"</span>);
        <strong>static</strong> <strong>struct</strong> IDeviceIoService testService = {
              .Dispatch = SampleServiceDispatch,
              .Open = <span style="color:#008800">NULL</span>,
              .Release = <span style="color:#008800">NULL</span>,
        };
        deviceObject->service = &testService;
        <strong>return</strong> HDF_SUCCESS;
 }
  
<strong>int</strong> SampleDriverInit(<strong>struct</strong> HdfDeviceObject *deviceObject)
 {
        HDF_LOGE(<span style="color:#880000">"SampleDriverInit enter"</span>);
        <strong>return</strong> HDF_SUCCESS;
 }
 
 <strong>void</strong> SampleDriverRelease(<strong>struct</strong> HdfDeviceObject *deviceObject)
 {
        HDF_LOGE(<span style="color:#880000">"SampleDriverRelease enter"</span>);
        <strong>return</strong>;
 }
 
 <strong>struct</strong> HdfDriverEntry g_sampleDriverEntry = {
        .moduleVersion = <span style="color:#008800">1</span>,
        .moduleName = <span style="color:#880000">"sample_driver"</span>,
        .Bind = SampleDriverBind,
        .Init = SampleDriverInit,
        .Release = SampleDriverRelease,
 };

 HDF_INIT(g_sampleDriverEntry);</span></span> 3.2 导出驱动步伐入口符号
         实现驱动步伐初始化后,需要将驱动步伐入口通过驱动声明宏导出,如许驱动框架才能在启动时辨认到驱动步伐的存在,驱动才能被加载:
<span style="background-color:#f0f0f0"><span style="color:black"><span style="color:#880000">#<strong>define</strong> HDF_INIT(module)  HDF_DRIVER_INIT(module)</span></span></span>          这里将HDF_INIT宏睁开:
<span style="background-color:#f0f0f0"><span style="color:black"><span style="color:#880000">#<strong>define</strong> HDF_SECTION __attribute__((section(".hdf.driver")))</span>
 <span style="color:#880000">#<strong>define</strong> HDF_DRIVER_INIT(module) \ </span>
<strong>const</strong> size_t USED_ATTR module<span style="color:#880000">##HdfEntry HDF_SECTION = (size_t)(&(module))</span></span></span>          下面是实现原理:

https://img-blog.csdnimg.cn/img_convert/b92054bbdd5d8d29abb1d25f0dd00d44.png
 
图4 Driver Entry内存分布
         可以看到HDF_INIT宏是界说了一个“驱动模块名+HdfEntry”的符号放到".hdf.driver" 地点section,该符号指向的内存地点即为驱动步伐入口布局体的地点。这个特殊的section将用于开机启动时查找装备驱动。
3.3 添加装备配置
         在装备对应的device_info.hcs添加sample驱动的配置:
<span style="background-color:#f0f0f0"><span style="color:black">sample_host :: host {
       hostName = <span style="color:#880000">"sample_host"</span>;
       sample_device :: device {
              device0 :: deviceNode {
                     policy = <span style="color:#008800">2</span>;
                     priority = <span style="color:#008800">100</span>;
                     preload = <span style="color:#008800">1</span>;
                     permission = <span style="color:#008800">0664</span>;
                     moduleName = <span style="color:#880000">"sample_driver"</span>;
                     serviceName = <span style="color:#880000">"sample_service"</span>;
              }
       }
}</span></span>          在配置中界说的device将在加载过程中产生一个装备实例,通过moduleName字段指定装备对应的驱动名称,从而将装备与驱动关联起来。其中,装备与驱动可以是一对多的关系,即可以实现一个驱动支持多个同类型装备。
3.4 驱动启动过程
         我们添加的驱动是怎样被实行的呢?简单来说,在系统启动时,驱动框架先启动,通过解析配置文件获取到装备列表,通过读取".hdf.driver"段读取到驱动步伐(Driver Entry)列表,然后遍历装备列表与驱动步伐列表进行匹配,并加载匹配成功的驱动。
         驱动框架有两大核心管理者:
         ● DeviceManager:负责装备的管理,包罗装备加载、卸载和查询等装备相干功能。
         ● DeviceServiceManager:负责管理装备发布的接口服务,提供接口服务的发布和查询等功能。
         驱动加载主要由DeviceManager主导,起首DeviceManager要解析配置文件中的Host列表,根据Host列表中的信息来实例化对应的Host对象。Host解析配置文件获取到关联的装备列表,遍历装备列表去获取与之匹配的驱动步伐名称,然后基于驱动步伐名称遍历前面提到的".hdf.driver" section获得驱动步伐地点。
         下面介绍具体过程。
         3.4.1 获取装备列表

https://img-blog.csdnimg.cn/img_convert/0b69943f2cb2534a264ed442ccd6d208.png

图5 装备列表布局
         配置文本编译后会变成二进制格式的配置文件,其中装备相干信息被存放在一个用“hdf_manager”标记的device_info配置块中,host的内容以块的形式在device_info块中依次分列,host块中记录了host名称、启动优先级和装备列表信息。装备信息中的moduleName字段将用于和驱动步伐入口中的moduleName进行匹配,从而为装备匹配到精确的驱动步伐。
         3.4.2 获取驱动步伐列表

https://img-blog.csdnimg.cn/img_convert/eb8d3c325290e2972099c92e59fe8d53.png

图6 驱动步伐(DriverEntry)内存布局
         HDF驱动框架通过驱动步伐入口符号的地点集中存放到一个特殊的section来实现对驱动的索引,这个section的开头和末尾插入了_hdf_drivers_start、_hdf_drivers_end两个特殊符号,用于标记这个section的范围,两个特殊符号之间的数据即为驱动实现指针。
         3.4.3 驱动步伐加载流程

https://img-blog.csdnimg.cn/img_convert/315ac622583f53917afebd486f817cb6.png
 图7 HDF驱动加载流程
         Device Manager遍历装备列表,当查找到对应驱动实现时,为装备创建Device对象实例,如果装备配置中的policy字段为需要对外发布驱动接口(SERVICE_POLICY_CAPACITY),那么驱动的Bind接口将起首被调用,用于关联装备和服务实例。然后驱动的Init接口将被调用,用于完成驱动的相干初始化工作。如果驱动被卸载大概由于硬件等原因Init接口返回失败,Release将被调用,用于开释驱动申请的各类资源。
四、总结
         本次和大家分享了HarmonyOS驱动的主要设计思想,重点分析了内核态驱动加载的过程,关于HarmonyOS驱动其他内容,后续会有更多技术文章向大家连续分享,敬请期待。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: HarmonyOS驱动加载过程分析