OpenHarmony 進階——HDF 驅動框架的原理小結

文章大綱

  • 引言
  • 一、HDF的驅動加載(驅動安裝)方式
    • 1、動態加載(主要是uhdf)
    • 2、靜態加載(主要是khdf)
      • 2.1、驅動入口實現
        • 2.1.1、Bind接口
        • 2.1.2、Init接口
        • 2.1.3、Release接口
      • 2.2、HDF_INIT 驅動入口符號
      • 2.3、獲取驅動列表
      • 2.4、獲取設備列表
      • 2.5、設備與驅動的匹配
      • 2.6、HDF驅動框架的啟動
      • 2.7、驅動靜態加載的全流程總結
  • 二、驅動框架交互流程
  • 三、驅動的開發
    • 3.1、實現驅動的業務功能邏輯的三個接口
    • 3.2、定義用于注冊驅動入口對象的結構體DriverEntry
    • 3.3、驅動配置信息
      • 3.3.1、驅動設備描述(必選)
      • 3.3.2、驅動私有配置信息(可選)
      • 3.3.3、配置SeLinux

引言

前面HDF 驅動框架基礎理論入門文章簡單的總結了HDF最基礎的理論知識,接下來好好學習下HDF的一些核心工作原理。

一、HDF的驅動加載(驅動安裝)方式

1、動態加載(主要是uhdf)

傳統so方式,先dlopen打開指定的so,驅動程序通過指定symbol方式找到驅動函數入口進行加載。

2、靜態加載(主要是khdf)

OpenHarmony驅動主要部署在內核態,當前主要采用靜態鏈接方式,隨內核子系統編譯和系統鏡像打包。HDF驅動加載包括按需加載和按序加載。按需加載是HDF框架支持驅動在系統啟動過程中默認加載,或者在系統啟動之后動態加載;按序加載是HDF框架支持驅動在系統啟動的過程中按照驅動的優先級進行加載。HDF框架定義的驅動按需加載方式的策略是由配置文件中的 preload 字段來控制,preload 字段的取值范圍以及含義如下:
在這里插入圖片描述
驅動的按序加載是通過配置文件中的 priority(取值范圍為整數 0 到 200)來決定的,priority 值越小,表示的優先級越高。驅動的加載順序,優先根據 host 的 priority 決定,如果host 的 priority 相同,再根據 host 內的驅動 priority 值來決定加載順序。
在這里插入圖片描述
采用將驅動程序通過Scatter編譯到指定的Section,再通過訪問指定Section的地址找到驅動函數入口進行加載,如下是內核態驅動靜態加載具體流程:

2.1、驅動入口實現

在HDF驅動框架中,HdfDriverEntry對象用于描述驅動入口的實現:

struct HdfDriverEntry {int32_t moduleVersion;const char *moduleName;int32_t (*Bind) (struct HdfDeviceObject *device0bject) ;int32_t (*Init) (struct HdfDeviceObject *device0bject) ;void (*Release) (struct HdfDevice0bject *device0bject) ;
}
2.1.1、Bind接口

用于驅動接口實例化綁定,若需要發布驅動接口,會在驅動加載過程中被調用,實例化該接口的驅動服務和DeviceObject綁定。驅動對外提供的服務能力,將相關的服務接口綁定到HDF框架。該接口的作用主要是完成驅動設備和設備服務接口的bind動作。

在HdfDriverEntry的Bind方法中,必須完成全部驅動服務接口的綁定,禁止將服務接口未定義或定義為空,因為驅動定義的服務接口,均是對外暴露的,如果未定義或定義為空,可能會導致外部調用時產生異常,從而降低驅動的可靠性。

2.1.2、Init接口

當框架完成設備綁定動作后,就開始調用驅動初始化接口,初始化成功后,驅動框架根據配置文件決定是對外創建設備服務接口,還是接口只對當前服務可見。如果Init初始化失敗,驅動框架就會主動釋放創建的設備接口等信息。

2.1.3、Release接口

用于驅動的卸載,在該接口中需要釋放驅動實例的軟硬件資源。當需要卸載驅動時,驅動框架先通過該接口通知驅動程序釋放資源,然后再釋放其他內部資源。

2.2、HDF_INIT 驅動入口符號

系統啟動時會執行HDF_INIT宏,

int SampleDriverBind(struct HdfDevice0bject *device0bject)
int SampleDriverInit (struct HdfDeviceObject *device0bject)
void SampleDriverRelease(struct HdfDeviceObject *device0bject)struct HdfDriverEntry g_sampleDriverEntry = {.moduleVersion = 1,.moduleName = "sample_driver",.Bind = SampleDriverBind, // 職責:綁定驅動對外提供的服務接口到HDF.Init = SampleDriverInit, // 職責:初始化驅動自身的業務.Release = SampleDriverRelease, // 職責:釋放驅動資源,發生異常時也會調用
};
HDF_INIT (g_sampleDriverEntry) ;

宏展開后,在宏里定義了一個驅動的模塊名+HdfEntry的符號并放到.hdf.section,即在編譯時通過Scatter文件把HDF_INIT為開頭的模塊module的指針全部放到.hdf.section,放的Driver Entry的指針。

#define HDF_SECTION__attribute__((section(.hdf.driver”)))
#define HDF_DRIVER_INIT(module) \
const size_t USED_ATTR module##HdfEntry HDF_SECTION = (size_t)(&(module))

在這里插入圖片描述
可以看到 HDF_INIT 宏是定義了一個“驅動模塊名+HdfEntry”的符號放到".hdf.driver"所在 section,該符號指向的內存地址即為驅動程序入口結構體的地址。這個特殊的 section 將用于開機啟動時查找設備驅動。

2.3、獲取驅動列表

HDF 驅動框架通過將驅動程序入口符號的地址集中存放到一個特殊的 section 來實現對驅動的索引,這個 section 的開頭和末尾插入了_hdf_drivers_start、_hdf_drivers_end 兩個特殊符號,用于標記這個 section 的范圍,兩個特殊符號之間的數據即為驅動實現指針。
在這里插入圖片描述

2.4、獲取設備列表

在這里插入圖片描述
系統啟動時會根據Device Info創建對應的Host 節點。配置文本編譯后會變成二進制格式的配置文件,其中設備相關信息被存放在一個用“hdf_manager”標記的 device_info 配置塊中,host的內容以塊的形式在 device_info 塊中依次排列,host 塊中記錄了 host 名稱、啟動優先級和設備列表信息。設備信息中的 moduleName 字段將用于和驅動程序入口中的 moduleName 進行匹配,從而為設備匹配到正確的驅動程序。從而為設備匹配到正確的驅動程序,完成設備與驅動的匹配,具體流程圖如下:
在這里插入圖片描述

2.5、設備與驅動的匹配

系統啟動時Device Manager和Device Host 即HDF框架首先啟動,在系統啟動時,驅動框架先啟動(如何先啟動?),通過解析配置文件獲取到設備列表,通過讀取”.hdf
drivers"段讀取到驅動程序(Driver Entry)列表,然后遍歷設備列表與驅動程序列表進行匹配,并加
載匹配成功的驅動。驅動框架有兩大核心管理者:

  • DeviceManager 負責設備的管理,包括設備加載、卸載和查詢等設備相關功能。
  • DeviceServiceManager 負責管理設備發布的接口服務,提供接口服務的發布、查詢等功能。
    驅動加載主要由 DeviceManager 主導,首先 DeviceManager 要解析配置文件中的Host 列表,根據Host 列表中的信息來實例化對應的Host 對象。Host 解析配置文件獲取到關聯的設備列表,遍歷設備列表去獲取與之匹配的驅動程序名稱,然后基于驅動程序名稱遍歷前面提到的.hdf.driver section 獲得驅動程序地址。

2.6、HDF驅動框架的啟動

HDF驅動框架通過late_initcall 啟動

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

2.7、驅動靜態加載的全流程總結

  • 在系統啟動時,DeviceManagerInit通過late_initcall先啟動。
  • Device Manager 根據 Device Information 信息,解析配置文件中的Host 列表,根據 Host 歹
    表中的信息來實例化對應的 Host 對象。
  • Host遍歷設備列表去獲取與之匹配的驅動程序名稱,然后基于驅動程序名稱遍歷.hdf.driver sec
    on 獲得驅動程序地址
  • 設備與驅動匹配成功之后,獲取指定驅動的入口地址,加載對應的設備驅動程序。
  • 調用指定驅動的 Bind 接口,用于關聯設備和服務實例。
  • 調用指定驅動的 Init 接口,用于完成驅動的相關初始化工作。
  • 如果驅動被卸載或者因為硬件等原因Init 接口返回失敗,Release 將被調用,用于釋放驅動申請
    的各類資源。

二、驅動框架交互流程

OpenHarmony 系統 HDF 驅動框架主要由驅動基礎框架、驅動程序、驅動配置文件和驅動接口這四個部分組成。

  • HDF 驅動基礎框架提供統一的硬件資源管理,驅動加載管理以及設備節點管理等功能。驅動框架采用的是主從模式設計,由 Device Manager 和 Device Host 組成。Device Manager 提供了統一的驅動管理,Device Manager 啟動時根據 Device Information 提供驅動設備信息加載相應的驅動 Device Host,并控制 Host 完成驅動的加載。Device Host 提供驅動運行的環境,同時預置 Host Framework 與 Device Manager 進行協同,完成驅動加載和調用。根據業務的需求 Device Host 可以有多個實例。
  • 驅動程序實現驅動具體的功能,每個驅動由一個或者多個驅動程序組成,每個驅動程序都對應著一個 Driver Entry。Driver Entry 主要完成驅動的初始化和驅動接口綁定功能。
  • 驅動配置文件.hcs 主要由設備信息(Device Information)和設備資源(Device Resource)組成。Device Information 完成設備信息的配置。如配置接口發布策略,驅動加載的方式等。Device Resource 完成設備資源的配置。如 GPIO 管腳、寄存器等資源信息的配置。
  • 驅動接口 HDI(Hardware Driver interface )提供標準化的接口定義和實現,驅動框架提供 IO Service和IO Dispatcher 機制,使得不同部署形態下驅動接口趨于形式一致。
    在這里插入圖片描述

驅動框架完成大部分驅動加載的動作,用戶只需注冊自己所需的接口和配置,然后驅動框架就會解析配置的內容,完成驅動加載和初始化動作。

三、驅動的開發

基于HDF(Hardware Driver Foundation開發驅動,開發者只需注冊所需接口和配置,驅動框架就會解析配置內容,完成驅動加載和初始化動作:

3.1、實現驅動的業務功能邏輯的三個接口

HDF_INIT(g_sampleDriverEntry); 系統內核自動調用的一個宏,驅動入口對象注冊到HDF框架,會調用HDF_INIT函數將驅動入口地址注冊到HDF框架。

當調用HDF_INIT將驅動入口注冊到HDF框架中,在加載驅動時HDF框架會先調用Bind函數,再調用Init函數加載該驅動,當Init調用異常時,HDF框架會調用Release釋放驅動資源并退出。所以首先就是驅動入口部分相關的Bind, Init 和Release三個接口:

  • Bind接口,驅動對外提供的服務能力,將相關的服務接口綁定到HDF框架
    該接口的作用主要是完成驅動設備和設備服務接口的bind動作。
int32_t SampleDriverBind(struct HdfDeviceObject *deviceObject)
{return HDF_SUCCESS;
}
  • Init接口
    在HdfDriverEntry的Init方法中,應當調用HdfDeviceSetClass接口,對驅動的類型進行定義。驅動的類型可以用于歸類當前設備的驅動程序,也可以用來查詢當前設備的驅動能力。為了便于后續驅動的統一管理,建議通過HdfDeviceSetClass接口來設置當前驅動的類型。
int32_t SampleDriverInit(struct HdfDeviceObject *deviceObject)
{// 設置驅動的類型為DISPLAYif (!HdfDeviceSetClass(deviceObject, DEVICE_CLASS_DISPLAY)) {HDF_LOGE("HdfDeviceSetClass failed");return HDF_FAILURE;}return HDF_SUCCESS;
}
  • Release接口
    當用戶需要卸載驅動時,驅動框架先通過該接口通知驅動程序釋放資源,然后再釋放其他內部資源
void SampleDriverRelease(struct HdfDeviceObject *deviceObject)
{//驅動資源釋放的接口 Release all resources.return;
}

3.2、定義用于注冊驅動入口對象的結構體DriverEntry

定義驅動入口的對象,必須為HdfDriverEntry(在hdf_device_desc.h中定義)類型的全局變量,主要是把三個接口賦值,相當于是完成映射。

struct HdfDriverEntry g_deviceSample = {.moduleVersion = 1,.moduleName = "sample_driver", .Bind = SampleDriverBind,.Init = SampleDriverInit,.Release = SampleDriverRelease,
};

3.3、驅動配置信息

驅動配置包含兩部分,HDF框架定義的驅動設備描述和驅動的私有配置信息。HDF使用HCS作為配置描述源碼,內容以 Key-Value 鍵值對為主要形式。它實現了配置代碼與驅動代碼解耦,便于開發者進行配置管理。HC-GEN (全稱 HDF Configuration Generator) 是 HCS 配置轉換工具,可以將 HDF 配置文件轉換為軟件可讀取的文件格式:在弱性能環境中,轉換為配置樹源碼,驅動可直接調用 C代碼獲取配置;在高性能環境中,轉換為 HCB(HDF Configuration Binary)二進制文件,驅動可使用 HDF框架提供的配置解析接口獲取配置。HCS經過HC-GEN編譯生成HCB文件,HDF驅動框架中的HCS Parser模塊會從HCB文件中重建配置樹,HDF驅動模塊使用HCS Parser提供的配置讀取接口獲取配置內容。

3.3.1、驅動設備描述(必選)

HDF框架加載驅動所需要的信息來源于HDF框架定義的驅動設備描述,因此基于HDF框架開發的驅動必須要在HDF框架定義的device_info.hcs配置文件中添加對應的設備描述,驅動的設備描述填寫如下所示:

sample_host :: host{hostName = "host0"; //host名稱,host節點是用來存放某一類驅動的容器。priority = 100; //host啟動優先級(0-200),值越大優先級越低,建議默認配100,優先級相同則不保證host的加載順序。device_sample :: device { //sample設備節點。device0 :: deviceNode { //sample驅動的DeviceNode節點。policy = 1; //驅動服務發布的策略priority = 100; //驅動啟動優先級(0-200),值越大優先級越低,建議默認配 100,優先級相同則不保證 device 的加載順序preload = 0; //驅動按需加載字段permission = 0664;//驅動創建設備節點權限moduleName = "sample_driver"; //驅動名稱,該字段的值必須和驅動入口結構的moduleName值一致serviceName = "sample_service"; //驅動對外發布服務的名稱,必須唯一deviceMatchAttr = "sample_config";//驅動私有數據匹配的關鍵字,必須和驅動私有數據配置表中的match_attr值相等。}}
}

3.3.2、驅動私有配置信息(可選)

如果驅動有私有配置,則可以添加一個驅動的配置文件,用來填寫一些驅動的默認配置信息,HDF框架在加載驅動的時候,會將對應的配置信息獲取并保存在HdfDeviceObject 中的property里面,通過Bind和Init傳遞給驅動,驅動的配置信息示例如下:

root {  SampleDriverConfig {sample_version = 1; sample_bus = "I2C_0"; match_attr = "sample_config";   //該字段的值必須和device_info.hcs中的deviceMatchAttr值一致}
}

3.3.3、配置SeLinux

在4.0后必須配置SeLinux 否則即使加載了So也無法正常被拉起,具體配置規則根據業務自行配置。

未完待續…

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/72400.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/72400.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/72400.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

大模型應用:多輪對話(prompt工程)

概述 在與大型語言模型(如ChatGPT)交互的過程中,我們常常體驗到與智能助手進行連貫多輪對話的便利性。那么,當我們開啟一個新的聊天時,系統是如何管理聊天上下文的呢? 一、初始上下文的建立 1. 創建新會…

如何為JAR設置定時重啟?

AI越來越火了,我們想要不被淘汰就得主動擁抱。推薦一個人工智能學習網站,通俗易懂,風趣幽默,最重要的屌圖甚多,忍不住分享一下給大家。點擊跳轉到網站 前面我們說過了如何將jar交由Systemctl管理,下面我們…

神碼AC-AP無線部署

神碼AC-AP無線部署: 1.設置基礎網絡 交換機設置 service dhcp ! ip dhcp pool ap (AP用地址) network-address 10.1.1.0 255.255.255.0 default-router 10.1.1.254 option 43 hex 010401010101 (AC IP地址16進制&#…

【Redis】常用命令匯總

Redis 作為高性能的鍵值存儲數據庫,提供了豐富的命令集,主要涵蓋 字符串 (String)、哈希 (Hash)、列表 (List)、集合 (Set)、有序集合 (ZSet)、鍵 (Keys)、Geo(地理位置)、HyperLogLog(基數統計)、Bitmap&a…

Redis - 高可用實現方案解析:主從復制與哨兵監控

文章目錄 Pre概述Redis 高可用實現方案一、主從復制機制1.1 全量同步流程1.2 增量同步(PSYNC)流程 二、哨兵監控機制2.1 故障轉移時序流程 三、方案對比與選型建議四、生產環境實踐建議 Pre Redis-入門到精通 Redis進階系列 Redis進階 - Redis主從工作…

2025年滲透測試面試題總結-02(題目+回答)

網絡安全領域各種資源,學習文檔,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各種好玩的項目及好用的工具,歡迎關注。 目錄 阿里云安全實習 一、代碼審計經驗與思路 二、越權漏洞原理與審計要點 三、SSRF漏洞解析與防御 四、教…

水滴tabbar canvas實現思路

廢話不多說之間看效果圖,只要解決了這個效果水滴tabbar就能做出來了 源碼地址 一、核心實現步驟分解 布局結構搭建 使用 作為繪制容器 設置 width=600, height=200 基礎尺寸 通過 JS 動態計算實際尺寸(適配高清屏) function initCanvas() {// 獲取設備像素比(解決 Re…

解決各大瀏覽器中http地址無權限調用麥克風攝像頭問題(包括谷歌,Edge,360,火狐)后續會陸續補充

項目場景: 在各大瀏覽器中http地址調用電腦麥克風攝像頭會沒有權限,http協議無法使用多媒體設備 原因分析: 為了用戶的隱私安全,http協議無法使用多媒體設備。因為像攝像頭和麥克風屬于可能涉及重大隱私問題的API,ge…

網絡安全蜜罐產品研究現狀

🍅 點擊文末小卡片 ,免費獲取網絡安全全套資料,資料在手,漲薪更快 一、知識點總結 1、蜜罐(Honeypot):誘捕攻擊者的一個陷阱。 2、蜜網(Honeynet):采用了技術…

el-card 結合 el-descriptions 作為信息展示

記錄下el-card 組合 el-descriptions 實現動態展示信息 文章結構 實現效果1. el-descriptions 組件使用1.1 結合v-for實現列表渲染1.2 解析 2. 自定義 el-descriptions 樣式2.1 修改背景色、字體顏色2.2 調整字體大小2.3 解析 3. el-card 結合 el-descriptions 作為信息展示3.…

【Java---數據結構】鏈表 LinkedList

1. 鏈表的概念 鏈表用于存儲一系列元素,由一系列節點組成,每個節點包含兩部分:數據域和指針域。 數據域:用于存儲數據元素 指針域:用于指向下一個節點的地址,通過指針將各個節點連接在一起,形…

python-leetcode-不同的二叉搜索樹 II

95. 不同的二叉搜索樹 II - 力扣(LeetCode) # Definition for a binary tree node. # class TreeNode: # def __init__(self, val0, leftNone, rightNone): # self.val val # self.left left # self.right right class S…

動態規劃/貪心算法

一、動態規劃 動態規劃 是一種用于解決優化問題的算法設計技術,尤其適用于具有重疊子問題和最優子結構性質的問題。它通過將復雜問題分解為更簡單的子問題,并保存這些子問題的解以避免重復計算,從而提高效率。 動態規劃的核心思想 最優子結…

2月28日,三極管測量,水利-51單片機

眾所周知,三極管(BJT)有三個管腳,基極(B)、集電極(C)、發射極(E),在實際應用中,不可避免地會遇到引腳辨別的問題。接下來就講下三極管…

Linux常見基本指令(二)

目錄 1、Linux基礎指令 文本查看 cat指令 more指令 less指令 head指令&tail指令 時間相關指令 查找、搜索相關指令 find指令 which指令 whereis指令 alias指令 grep指令 打包壓縮和解壓縮 zip指令(壓縮) unzip(解壓&…

Day 55 卡瑪筆記

這是基于代碼隨想錄的每日打卡 所有可達路徑 題目描述 ? 給定一個有 n 個節點的有向無環圖,節點編號從 1 到 n。請編寫一個函數,找出并返回所有從節點 1 到節點 n 的路徑。每條路徑應以節點編號的列表形式表示。 輸入描述 ? 第一行包含兩個整數…

2. 在后端代碼中加入日志記錄模塊

1. 說明 日志模塊基本上是每一個軟件系統開發中必不可少的,主要用于持久記錄一些代碼運行中的輸出信息,輔助編碼人員進行代碼調試,以及后期軟件上線運行報錯分析。在Python中加入日志模塊比較簡單,只需要借助logging和RotatingFi…

【Vue3】淺談setup語法糖

Vue3 的 setup 語法糖是通過 <script setup> 標簽啟用的特性&#xff0c;它是對 Composition API 的進一步封裝&#xff0c;旨在簡化組件的聲明式寫法&#xff0c;同時保留 Composition API 的邏輯組織能力。以下是其核心概念和原理分析&#xff1a; 一、<script setu…

物聯網小范圍高精度GPS使用

在園區內實現小范圍高精度GPS&#xff08;全球定位系統&#xff09;定位&#xff0c;通常需要結合多種技術來彌補傳統GPS在精度和覆蓋范圍上的不足。以下是實現小范圍高精度GPS定位的解決方案&#xff0c;包括技術選擇、系統設計和應用場景。 一、技術選擇 在園區內實現高精度…

【前端】前端設計中的響應式設計詳解

文章目錄 前言一、響應式設計的定義與作用二、響應式設計的原則三、響應式設計的實現四、響應式設計的最佳實踐總結 前言 在當今數字化時代&#xff0c;網站和應用程序需要適應各種設備&#xff0c;從桌面電腦到平板電腦和手機。響應式設計應運而生&#xff0c;成為一種可以適…