OpenHarmony系統(tǒng)HDF驅(qū)動(dòng)框架概述
OpenAtom OpenHarmony(以下簡(jiǎn)稱“OpenHarmony”)系統(tǒng) HDF 驅(qū)動(dòng)框架采用 C 語言面向?qū)ο?a href="http://m.xsypw.cn/v/tag/1315/" target="_blank">編程模型構(gòu)建,通過平臺(tái)解耦、內(nèi)核解耦,來達(dá)到兼容不同內(nèi)核,統(tǒng)一平臺(tái)底座的目的,從而幫助開發(fā)者實(shí)現(xiàn)驅(qū)動(dòng)一次開發(fā),多系統(tǒng)部署的效果。
為了達(dá)成這個(gè)目標(biāo), OpenHarmony 系統(tǒng) HDF 驅(qū)動(dòng)框架提供了:
操作系統(tǒng)適配層(OSAL,Operating System Abstraction Layer):對(duì)內(nèi)核操作相關(guān)接口進(jìn)行統(tǒng)一封裝,屏蔽不同系統(tǒng)操作接口。
平臺(tái)驅(qū)動(dòng)接口:提供 Board 部分驅(qū)動(dòng)(例如,I2C/SPI/UART 總線等平臺(tái)資源)支持,同時(shí)對(duì) Board 硬件操作進(jìn)行統(tǒng)一的適配接口抽象,方便開發(fā)者只需開發(fā)新硬件抽象接口,即可獲得新增 Board 部分驅(qū)動(dòng)支持。
驅(qū)動(dòng)模型:面向器件驅(qū)動(dòng),提供常見的驅(qū)動(dòng)抽象模型,主要達(dá)成兩個(gè)目的。
1)提供標(biāo)準(zhǔn)化的器件驅(qū)動(dòng)模型,開發(fā)者無需獨(dú)立開發(fā),通過配置即可完成驅(qū)動(dòng)部署。
2)提供驅(qū)動(dòng)模型抽象,屏蔽驅(qū)動(dòng)與不同系統(tǒng)組件間的交互,使得驅(qū)動(dòng)更具備通用型。
為了進(jìn)一步簡(jiǎn)化 OpenHarmony 系統(tǒng)驅(qū)動(dòng)開發(fā),OpenHarmony 系統(tǒng) HDF 驅(qū)動(dòng)框架支持多種驅(qū)動(dòng)加載方式:
支持驅(qū)動(dòng)動(dòng)態(tài)加載和靜態(tài)加載,解除驅(qū)動(dòng)代碼和框架間的直接代碼依賴,使得驅(qū)動(dòng)程序可以獨(dú)立編譯和部署;
支持按需動(dòng)態(tài)加載方式,避免設(shè)備驅(qū)動(dòng)全量加載,可有效降低系統(tǒng)資源的占用。
本文主要分析 OpenHarmony 系統(tǒng)驅(qū)動(dòng)加載過程,在正式介紹之前,首先了解 OpenHarmony 系統(tǒng)驅(qū)動(dòng)架構(gòu)的組成、工作原理和機(jī)制,從而了解驅(qū)動(dòng)加載的細(xì)節(jié)。
OpenHarmony系統(tǒng)
HDF驅(qū)動(dòng)框架介紹
OpenHarmony 系統(tǒng) HDF 驅(qū)動(dòng)框架主要由驅(qū)動(dòng)基礎(chǔ)框架、驅(qū)動(dòng)程序、驅(qū)動(dòng)配置文件和驅(qū)動(dòng)接口這四個(gè)部分組成。
1)HDF 驅(qū)動(dòng)基礎(chǔ)框架提供統(tǒng)一的硬件資源管理,驅(qū)動(dòng)加載管理以及設(shè)備節(jié)點(diǎn)管理等功能。驅(qū)動(dòng)框架采用的是主從模式設(shè)計(jì),由 Device Manager 和 Device Host 組成。
Device Manager 提供了統(tǒng)一的驅(qū)動(dòng)管理,Device Manager 啟動(dòng)時(shí)根據(jù) Device Information 提供驅(qū)動(dòng)設(shè)備信息加載相應(yīng)的驅(qū)動(dòng) Device Host,并控制 Host 完成驅(qū)動(dòng)的加載。
Device Host 提供驅(qū)動(dòng)運(yùn)行的環(huán)境,同時(shí)預(yù)置 Host Framework 與 Device Manager 進(jìn)行協(xié)同,完成驅(qū)動(dòng)加載和調(diào)用。根據(jù)業(yè)務(wù)的需求 Device Host 可以有多個(gè)實(shí)例。
說明Device Host 顧名思義就是驅(qū)動(dòng)宿主,提供驅(qū)動(dòng)運(yùn)行的環(huán)境。 當(dāng)驅(qū)動(dòng)部署在用戶態(tài)時(shí),Device Host 可以由獨(dú)立的進(jìn)程進(jìn)行承載, 當(dāng)驅(qū)動(dòng)在部署在內(nèi)核態(tài)時(shí),Device Host 僅表示邏輯隔離。 Device Host 的劃分原則: Device Host 屬于一類設(shè)備聚合,如 Camera,Audio,Display 等。 驅(qū)動(dòng)程序是部署在一個(gè) Device Host 還是部署在不同的 Device Host,主要考慮驅(qū)動(dòng)程序之間是否存的業(yè)務(wù)耦合性,如果兩個(gè)驅(qū)動(dòng)程序之間存在依賴,可以考慮將這部分驅(qū)動(dòng)程序部署在統(tǒng)一 Host。
2)驅(qū)動(dòng)程序?qū)崿F(xiàn)驅(qū)動(dòng)具體的功能,每個(gè)驅(qū)動(dòng)由一個(gè)或者多個(gè)驅(qū)動(dòng)程序組成,每個(gè)驅(qū)動(dòng)程序都對(duì)應(yīng)著一個(gè) Driver Entry。Driver Entry 主要完成驅(qū)動(dòng)的初始化和驅(qū)動(dòng)接口綁定功能。
3)驅(qū)動(dòng)配置文件.hcs主要由設(shè)備信息(Device Information)和設(shè)備資源(Device Resource)組成。Device Information 完成設(shè)備信息的配置。如配置接口發(fā)布策略,驅(qū)動(dòng)加載的方式等。Device Resource 完成設(shè)備資源的配置。如 GPIO 管腳、寄存器等資源信息的配置。 4)驅(qū)動(dòng)接口 HDI(Hardware Driver Interface )提供標(biāo)準(zhǔn)化的接口定義和實(shí)現(xiàn),驅(qū)動(dòng)框架提供 IO Service 和 IO Dispatcher 機(jī)制,使得不同部署形態(tài)下驅(qū)動(dòng)接口趨于形式一致。驅(qū)動(dòng)接口主要存在以下幾種實(shí)現(xiàn):
當(dāng)驅(qū)動(dòng)以內(nèi)核組件部署時(shí),客戶端程序訪問驅(qū)動(dòng)程序需要通過 system call 方式調(diào)用,驅(qū)動(dòng)接口通過 IO Service 請(qǐng)求將消息通過 system call 方式調(diào)用到內(nèi)核,并將消息分發(fā)到 IO Dispatcher 處理。
當(dāng)驅(qū)動(dòng)以用戶態(tài)服務(wù)形式部署時(shí),客戶端進(jìn)程訪問驅(qū)動(dòng)進(jìn)程需要通過 IPC 方式通信,IO Service 完成 IPC 通信的客戶端消息請(qǐng)求封裝,IO Dispatcher 完成驅(qū)動(dòng)服務(wù)端消息請(qǐng)求封裝,客戶端消息通過 IPC 通信到達(dá)服務(wù)端并分發(fā)給 IO Dispatcher 處理。
當(dāng)驅(qū)動(dòng)部署在 RTOS(Real-Time Operating System)輕量化操作系統(tǒng)時(shí),驅(qū)動(dòng)接口和驅(qū)動(dòng)程序之間采用的是 Function Call 方式調(diào)用,因此驅(qū)動(dòng)接口僅提供定義,驅(qū)動(dòng)接口實(shí)現(xiàn)由驅(qū)動(dòng)程序提供。
Device Manager 提供了統(tǒng)一的驅(qū)動(dòng)加載管理機(jī)制和驅(qū)動(dòng)接口發(fā)布機(jī)制。
當(dāng) Device Host 環(huán)境加載完成時(shí),Device Manager 根據(jù) Device Information 信息,請(qǐng)求 Host 加載相應(yīng)的驅(qū)動(dòng)程序,Device Host 在收到請(qǐng)求時(shí),進(jìn)行以下操作:
1.根據(jù)請(qǐng)求加載設(shè)備信息,查找并加載指定路徑下驅(qū)動(dòng)鏡像或從指定段地址(section)查找驅(qū)動(dòng)程序入口。
2.查找驅(qū)動(dòng)設(shè)備描述符,匹配對(duì)應(yīng)的設(shè)備驅(qū)動(dòng)。
3.當(dāng)驅(qū)動(dòng)匹配成功時(shí),加載指定驅(qū)動(dòng)程序鏡像。
4.Host Framework 在驅(qū)動(dòng)程序鏡像加載成功后,調(diào)用驅(qū)動(dòng)程序(Driver Entry)的綁定接口和初始化接口,實(shí)現(xiàn)與驅(qū)動(dòng)程序的服務(wù)對(duì)象綁定,同時(shí)初始化設(shè)備驅(qū)動(dòng)程序。
5.當(dāng) Device Information 配置中的服務(wù)策略要求對(duì)外暴露驅(qū)動(dòng)接口時(shí),驅(qū)動(dòng)框架就將驅(qū)動(dòng)程序的服務(wù)對(duì)象添加到對(duì)外發(fā)布的服務(wù)對(duì)象列表中,外部客戶端程序就可以通過此列表來查詢并訪問相應(yīng)的服務(wù)接口。
對(duì)于驅(qū)動(dòng)接口實(shí)現(xiàn)而言:
當(dāng)驅(qū)動(dòng)部署在內(nèi)核態(tài)時(shí),驅(qū)動(dòng)接口部署在用戶態(tài),驅(qū)動(dòng)實(shí)現(xiàn)在內(nèi)核態(tài),驅(qū)動(dòng)接口和驅(qū)動(dòng)實(shí)現(xiàn)之間通過 syscall 調(diào)用方式實(shí)現(xiàn)調(diào)用交互。
當(dāng)驅(qū)動(dòng)部署在用戶態(tài)時(shí),驅(qū)動(dòng)接口和驅(qū)動(dòng)實(shí)現(xiàn)分別部署在兩個(gè)進(jìn)程中。驅(qū)動(dòng)接口和驅(qū)動(dòng)實(shí)現(xiàn)之間通過 IPC 調(diào)用方式實(shí)現(xiàn)調(diào)用交互。
為了使客戶端和服務(wù)端驅(qū)動(dòng)調(diào)用方式基本一致,驅(qū)動(dòng)框架提供 IO Service 和 IO Dispatcher 機(jī)制屏蔽了調(diào)用消息傳遞方式的差異。
驅(qū)動(dòng)接口實(shí)現(xiàn)統(tǒng)一采用遠(yuǎn)程調(diào)用的方式實(shí)現(xiàn),客戶端驅(qū)動(dòng)接口函數(shù)將請(qǐng)求序列化成內(nèi)存數(shù)據(jù),通過驅(qū)動(dòng)框架提供的 IO Service 將消息發(fā)送到服務(wù)端處理,服務(wù)端在收到請(qǐng)求消息時(shí)通過 IO Dispatcher 機(jī)制將消息分發(fā)給消息處理函數(shù)處理,處理函數(shù)將反序列化內(nèi)存數(shù)據(jù)解析成相應(yīng)的請(qǐng)求。這樣的做到好處是,開發(fā)者只需重點(diǎn)關(guān)注接口的定義,無需過多的關(guān)注如何實(shí)現(xiàn)不同平臺(tái)上接口適配。
驅(qū)動(dòng)加載過程分析
OpenHarmony 系統(tǒng)驅(qū)動(dòng)根據(jù)驅(qū)動(dòng)程序部署的不同方式,存在兩種驅(qū)動(dòng)加載方式:
動(dòng)態(tài)加載方式:采用傳統(tǒng)的 so(共享庫(kù))加載方式,驅(qū)動(dòng)程序通過指定 Symbol 方式找到驅(qū)動(dòng)函數(shù)入口進(jìn)行加載。
靜態(tài)加載方式:采用將驅(qū)動(dòng)程序通過 Scatter 編譯到指定的 Section,再通過訪問指定 Section 對(duì)應(yīng)的地址,找到驅(qū)動(dòng)函數(shù)入口進(jìn)行加載。
下面結(jié)合一個(gè) Sample 示例代碼,講解驅(qū)動(dòng)加載過程,重點(diǎn)分析靜態(tài)加載方式下內(nèi)核態(tài)驅(qū)動(dòng)加載過程。 實(shí)現(xiàn)驅(qū)動(dòng)程序初始化接口在 HDF 驅(qū)動(dòng)框架中,HdfDriverEntry 對(duì)象被用來描述一個(gè)驅(qū)動(dòng)實(shí)現(xiàn)。
struct HdfDriverEntry { int32_t moduleVersion; const char *moduleName; int32_t (*Bind)(struct HdfDeviceObject *deviceObject); int32_t (*Init)(struct HdfDeviceObject *deviceObject); void (*Release)(struct HdfDeviceObject *deviceObject);};
編寫一個(gè)簡(jiǎn)單的驅(qū)動(dòng),首先需要實(shí)現(xiàn)驅(qū)動(dòng)程序 (Driver Entry)入口中的三個(gè)主要接口:
Bind 接口:實(shí)現(xiàn)驅(qū)動(dòng)接口實(shí)例化綁定,如果需要發(fā)布驅(qū)動(dòng)接口,會(huì)在驅(qū)動(dòng)加載過程中被調(diào)用,實(shí)例化該接口的驅(qū)動(dòng)服務(wù)并和 DeviceObject 綁定。
Init 接口:實(shí)現(xiàn)驅(qū)動(dòng)的初始化,返回錯(cuò)誤將中止驅(qū)動(dòng)加載流程。
Release 接口:實(shí)現(xiàn)驅(qū)動(dòng)的卸載,在該接口中釋放驅(qū)動(dòng)實(shí)例的軟硬件資源。
int SampleDriverBind(struct HdfDeviceObject *deviceObject){ HDF_LOGE("SampleDriverBind enter!"); static struct IDeviceIoService testService = { .Dispatch = SampleServiceDispatch, .Open = NULL, .Release = NULL, }; deviceObject->service = &testService; return HDF_SUCCESS;} int SampleDriverInit(struct HdfDeviceObject *deviceObject){ HDF_LOGE("SampleDriverInit enter"); return HDF_SUCCESS;} void SampleDriverRelease(struct HdfDeviceObject *deviceObject){ HDF_LOGE("SampleDriverRelease enter"); return;} struct HdfDriverEntry g_sampleDriverEntry = { .moduleVersion = 1, .moduleName = "sample_driver", .Bind = SampleDriverBind, .Init = SampleDriverInit, .Release = SampleDriverRelease,}; HDF_INIT(g_sampleDriverEntry);
導(dǎo)出驅(qū)動(dòng)程序入口符號(hào)實(shí)現(xiàn)驅(qū)動(dòng)程序初始化后,需要將驅(qū)動(dòng)程序入口通過驅(qū)動(dòng)聲明宏導(dǎo)出,這樣驅(qū)動(dòng)框架才能在啟動(dòng)時(shí)識(shí)別到驅(qū)動(dòng)程序的存在,驅(qū)動(dòng)才能被加載:
#define HDF_INIT(module) HDF_DRIVER_INIT(module)
(左右滑動(dòng),查看更多)
這里將 HDF_INIT 宏展開:
#define HDF_SECTION __attribute__((section(".hdf.driver")))#define HDF_DRIVER_INIT(module) constsize_tUSED_ATTRmodule##HdfEntryHDF_SECTION=(size_t)(&(module))
(左右滑動(dòng),查看更多)
下面是其實(shí)現(xiàn)原理:
圖4 Driver Entry內(nèi)存分布
可以看到 HDF_INIT 宏是定義了一個(gè)“驅(qū)動(dòng)模塊名+HdfEntry”的符號(hào)放到".hdf.driver"所在 section,該符號(hào)指向的內(nèi)存地址即為驅(qū)動(dòng)程序入口結(jié)構(gòu)體的地址。這個(gè)特殊的 section 將用于開機(jī)啟動(dòng)時(shí)查找設(shè)備驅(qū)動(dòng)。
添加設(shè)備配置
在設(shè)備對(duì)應(yīng)的 device_info.hcs 添加 sample 驅(qū)動(dòng)的配置:
sample_host :: host { hostName = "sample_host"; sample_device :: device { device0 :: deviceNode { policy = 2; priority = 100; preload = 1; permission = 0664; moduleName = "sample_driver"; serviceName = "sample_service"; } }}
在配置中定義的 device 將在加載過程中產(chǎn)生一個(gè)設(shè)備實(shí)例,通過 moduleName 字段指定設(shè)備對(duì)應(yīng)的驅(qū)動(dòng)名稱,從而將設(shè)備與驅(qū)動(dòng)關(guān)聯(lián)起來,其中,設(shè)備與驅(qū)動(dòng)可以是一對(duì)多的關(guān)系,即可以實(shí)現(xiàn)一個(gè)驅(qū)動(dòng)支持多個(gè)同類型設(shè)備。 驅(qū)動(dòng)啟動(dòng)過程我們添加的驅(qū)動(dòng)是如何被執(zhí)行的呢?簡(jiǎn)單來說,在系統(tǒng)啟動(dòng)時(shí),驅(qū)動(dòng)框架先啟動(dòng),通過解析配置文件獲取到設(shè)備列表,通過讀取".hdf.drivers"段讀取到驅(qū)動(dòng)程序(Driver Entry)列表,然后遍歷設(shè)備列表與驅(qū)動(dòng)程序列表進(jìn)行匹配,并加載匹配成功的驅(qū)動(dòng)。驅(qū)動(dòng)框架有兩大核心管理者:
DeviceManager 負(fù)責(zé)設(shè)備的管理,包括設(shè)備加載、卸載和查詢等設(shè)備相關(guān)功能。
DeviceServiceManager 負(fù)責(zé)管理設(shè)備發(fā)布的接口服務(wù),提供接口服務(wù)的發(fā)布、查詢等功能。
驅(qū)動(dòng)加載主要由 DeviceManager 主導(dǎo),首先 DeviceManager 要解析配置文件中的 Host 列表,根據(jù) Host 列表中的信息來實(shí)例化對(duì)應(yīng)的 Host 對(duì)象。Host 解析配置文件獲取到關(guān)聯(lián)的設(shè)備列表,遍歷設(shè)備列表去獲取與之匹配的驅(qū)動(dòng)程序名稱,然后基于驅(qū)動(dòng)程序名稱遍歷前面提到的.hdf.driver section 獲得驅(qū)動(dòng)程序地址。
配置文本編譯后會(huì)變成二進(jìn)制格式的配置文件,其中設(shè)備相關(guān)信息被存放在一個(gè)用“hdf_manager”標(biāo)記的 device_info配置塊中,host 的內(nèi)容以塊的形式在 device_info 塊中依次排列,host 塊中記錄了 host 名稱、啟動(dòng)優(yōu)先級(jí)和設(shè)備列表信息。設(shè)備信息中的 moduleName 字段將用于和驅(qū)動(dòng)程序入口中的 moduleName 進(jìn)行匹配,從而為設(shè)備匹配到正確的驅(qū)動(dòng)程序。 獲取驅(qū)動(dòng)程序列表
HDF 驅(qū)動(dòng)框架通過將驅(qū)動(dòng)程序入口符號(hào)的地址集中存放到一個(gè)特殊的 section 來實(shí)現(xiàn)對(duì)驅(qū)動(dòng)的索引,這個(gè) section 的開頭和末尾插入了_hdf_drivers_start、_hdf_drivers_end 兩個(gè)特殊符號(hào),用于標(biāo)記這個(gè) section 的范圍,兩個(gè)特殊符號(hào)之間的數(shù)據(jù)即為驅(qū)動(dòng)實(shí)現(xiàn)指針。 驅(qū)動(dòng)程序加載流程
Device Manager 遍歷設(shè)備列表,當(dāng)查找到對(duì)應(yīng)驅(qū)動(dòng)實(shí)現(xiàn)時(shí),為設(shè)備創(chuàng)建 Device 對(duì)象實(shí)例,如果設(shè)備配置中的 policy 字段為需要對(duì)外發(fā)布的驅(qū)動(dòng)接口(SERVICE_POLICY_CAPACITY),那么驅(qū)動(dòng)的 Bind 接口將首先被調(diào)用,用于關(guān)聯(lián)設(shè)備和服務(wù)實(shí)例。然后驅(qū)動(dòng)的 Init 接口將被調(diào)用,用于完成驅(qū)動(dòng)的相關(guān)初始化工作。如果驅(qū)動(dòng)被卸載或者因?yàn)橛布仍?Init 接口返回失敗,Release 將被調(diào)用,用于釋放驅(qū)動(dòng)申請(qǐng)的各類資源。
總結(jié)
本次和大家分享了 OpenHarmony 系統(tǒng)驅(qū)動(dòng)的主要設(shè)計(jì)思想,重點(diǎn)分析了內(nèi)核態(tài)驅(qū)動(dòng)加載的過程,關(guān)于 OpenHarmony 系統(tǒng)驅(qū)動(dòng)其他內(nèi)容,后續(xù)會(huì)有更多技術(shù)文章向大家持續(xù)分享,敬請(qǐng)期待。
責(zé)任編輯:haq
-
驅(qū)動(dòng)
+關(guān)注
關(guān)注
12文章
1878瀏覽量
86290 -
框架
+關(guān)注
關(guān)注
0文章
404瀏覽量
17717 -
HarmonyOS
+關(guān)注
關(guān)注
79文章
2005瀏覽量
31748 -
OpenHarmony
+關(guān)注
關(guān)注
26文章
3802瀏覽量
17703
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
【北京迅為】iTOP-RK3568開發(fā)板鴻蒙OpenHarmony系統(tǒng)南向驅(qū)動(dòng)開發(fā)實(shí)操-HDF驅(qū)動(dòng)配置UART

迅為RK3568開發(fā)板篇Openharmony配置HDF控制UART-實(shí)操-HDF驅(qū)動(dòng)配置UART-UART應(yīng)用開發(fā)-UART驅(qū)動(dòng)API接口介紹
北京迅為iTOP-RK3568開發(fā)板OpenHarmony系統(tǒng)南向驅(qū)動(dòng)開發(fā)實(shí)操-HDF驅(qū)動(dòng)配置LED

北京迅為RK3568開發(fā)板OpenHarmony系統(tǒng)南向驅(qū)動(dòng)開發(fā)內(nèi)核HDF驅(qū)動(dòng)框架架構(gòu)

迅為RK3568開發(fā)板篇Openharmony配置HDF控制UART-實(shí)操-HDF驅(qū)動(dòng)配置UART-UART應(yīng)用開發(fā)-UART驅(qū)動(dòng)API接口介紹
【北京迅為】iTOP-RK3568OpenHarmony系統(tǒng)南向驅(qū)動(dòng)開發(fā)GPIO基礎(chǔ)知識(shí)

迅為RK3568開發(fā)板篇Openharmony配置HDF控制UART-實(shí)操-HDF驅(qū)動(dòng)配置UART-修改HCS配置
迅為RK3568開發(fā)板篇OpenHarmony實(shí)操HDF驅(qū)動(dòng)控制LED-編寫應(yīng)用APP
迅為RK3568開發(fā)板篇OpenHarmony實(shí)操HDF驅(qū)動(dòng)控制LED-添加內(nèi)核編譯
迅為RK3568開發(fā)板篇OpenHarmony實(shí)操HDF驅(qū)動(dòng)控制LED-編寫內(nèi)核 LED HDF 驅(qū)動(dòng)程序
迅為RK3568開發(fā)板篇OpenHarmony配置HDF驅(qū)動(dòng)控制LED-新增 topeet子系統(tǒng)-編寫 bundle.json文件
迅為RK3568開發(fā)板篇OpenHarmony配置HDF驅(qū)動(dòng)控制LED-新增 topeet子系統(tǒng)
迅為RK3568開發(fā)板篇OpenHarmony配置HDF驅(qū)動(dòng)控制LED-配置創(chuàng)建私有配置文件
OpenHarmony程序分析框架論文入選ICSE 2025

鴻蒙開發(fā):【OpenHarmony 4.0 Release指導(dǎo)】

評(píng)論