OpenHarmony富設(shè)備移植指南(四)第三方內(nèi)核適配與定制
??想了解更多關(guān)于開(kāi)源的內(nèi)容,請(qǐng)?jiān)L問(wèn):??
??51CTO 開(kāi)源基礎(chǔ)軟件社區(qū)??
一、OpenHarmony移植為什么這么難?
為什么OpenHarmony的移植這么久才出來(lái),安卓手機(jī)廠商開(kāi)源了內(nèi)核代碼之后LineageOS可以很快跟進(jìn),這應(yīng)該是廣大網(wǎng)友都疑惑的事情,我這里可以簡(jiǎn)單解釋一下,這個(gè)跟內(nèi)核與驅(qū)動(dòng)有著直接關(guān)系。
下面是我總結(jié)的一個(gè)簡(jiǎn)單解釋:
Linux設(shè)備:標(biāo)準(zhǔn)Linux內(nèi)核 + 硬件驅(qū)動(dòng)
安卓設(shè)備:安卓?jī)?nèi)核(標(biāo)準(zhǔn)內(nèi)核+安卓定制)+ 硬件驅(qū)動(dòng)(調(diào)用部分定制接口)
OH設(shè)備:OH內(nèi)核(標(biāo)準(zhǔn)內(nèi)核+OH定制)+ 硬件驅(qū)動(dòng)(調(diào)用部分定制接口)
如果安卓設(shè)備的驅(qū)動(dòng)調(diào)用了安卓?jī)?nèi)核特有的接口,安卓的驅(qū)動(dòng)就不能用到標(biāo)準(zhǔn)內(nèi)核上,也不能用在OH內(nèi)核上,如果安卓的驅(qū)動(dòng)調(diào)用的是標(biāo)準(zhǔn)Linux內(nèi)核的接口,這就可以用到OH設(shè)備上,但是這個(gè)很少,這也是為什么你們會(huì)在pmOS看到有些設(shè)備的支持狀況是這樣的。
很多網(wǎng)友都期待OpenHarmony移植到自己的手機(jī)能打電話,以為只要開(kāi)發(fā)者堅(jiān)持就能成功,這里我可以潑一盆冷水,因?yàn)榛鶐酒尿?qū)動(dòng)廠商是不開(kāi)源的,沒(méi)有驅(qū)動(dòng)源碼就不可能有適配OH內(nèi)核的驅(qū)動(dòng),廠商也不可能花力氣去基于OH內(nèi)核幫你適配驅(qū)動(dòng),所以移植適配評(píng)估的時(shí)候我參考的是pmOS,因?yàn)閜mOS是用標(biāo)準(zhǔn)Linux內(nèi)核,Ubuntu Touch的內(nèi)核為什么不能用?了解過(guò)的同學(xué)應(yīng)該知道,Ubuntu Touch用的是安卓?jī)?nèi)核,它能用安卓驅(qū)動(dòng),所以小米6得Ubuntu Touch支持打電話,但是pmOS不行。
另外Linux內(nèi)核版本每次變更都會(huì)頻繁改動(dòng)代碼,這導(dǎo)致了同樣的代碼很可能無(wú)法編譯通過(guò),這也是為什么SOC廠商和驅(qū)動(dòng)廠商都對(duì)升級(jí)內(nèi)核版本不積極,可用內(nèi)核和可用驅(qū)動(dòng)的缺少導(dǎo)致了這么長(zhǎng)時(shí)間,移植OpenHarmony都是吃力不討好的事情,并且只能開(kāi)機(jī)點(diǎn)亮,沒(méi)有驅(qū)動(dòng),上限被卡死,所以移植這件事不是有人努力移植就行的,希望大家能多多理解。
二、OH內(nèi)核特性移植
在OH官方的doc倉(cāng)中,標(biāo)準(zhǔn)內(nèi)核介紹里有OH內(nèi)核特性的部分講解(如下圖),可惜這個(gè)只是部分,一些更基礎(chǔ)的驅(qū)動(dòng)沒(méi)有列出來(lái),接下來(lái)我們先移植基礎(chǔ)的部分,保證能開(kāi)機(jī)亮屏,更高級(jí)一點(diǎn)的特性先不移植。
???zh-cn/device-dev/kernel · OpenHarmony/docs - 碼云 - 開(kāi)源中國(guó) (gitee.com)??
1、添加設(shè)備內(nèi)核編譯配置文件
上篇文章【OH編譯框架適配與定制】中我們已經(jīng)把源碼下載到kernel/linux/linux-sagit目錄下,接下來(lái)我們找到【從postmarketOS獲取移植資源】文章中解包出的config配置,把config放到device/board/xiaomi/sagit/kernel/configs下并重命名為sagit_oh_defconfig,因?yàn)槲沂嵌ㄖ七^(guò)Linux編譯流程的,我的編譯腳本把會(huì)把sagit_oh_defconfig復(fù)制到linux-sagit/arch/arm64/configs下。
熟悉Linux內(nèi)核編譯的同學(xué)也可以按照自己的思路做,這一部只是簡(jiǎn)單的添加移植設(shè)備的編譯配置。
2、移植staging下OH添加的hilog,hievent,hisysevent,zerohung,hungtask,blackbox驅(qū)動(dòng)
(1)更新最新內(nèi)核代碼
移植驅(qū)動(dòng)前,我們先更新官方內(nèi)核到最新版,盡量保證驅(qū)動(dòng)沒(méi)有bug
(2)復(fù)制代碼,修正Kconfig,Makefile
復(fù)制linux-5.10/driver/staging/下的hilog,hievent,hisysevent,zerohung,hungtask,blackbox源碼到linux-sagit/driver/staging/目錄下。
修改linux-sagit/driver/staging/下的Kconfig文件,在末尾添加如下信息。
修改linux-sagit/driver/staging/下的Makefile文件,在末尾添加如下信息。
只是復(fù)制staging下的文件還不行,編譯的時(shí)候會(huì)報(bào)錯(cuò),還有些頭文件缺失。
復(fù)制linux-5.10/include下的dfx文件夾到linux-sagit/include下。
同時(shí)linux-5.10/include/linux/下的三個(gè)頭文件。
blackbox.h,blackbox_storage.h,blackbox_common.h。
也需要復(fù)制到對(duì)應(yīng)的linux-sagit/include/linux/下,補(bǔ)全頭文件。
(3)修復(fù)get_fs(),set_fs()函數(shù)缺失問(wèn)題
頭文件補(bǔ)全之后編譯仍會(huì)報(bào)錯(cuò),我調(diào)查發(fā)現(xiàn)這是因?yàn)閙m_segment_t,get_fs(),set_fs()等結(jié)構(gòu)體跟函數(shù)已經(jīng)在新版內(nèi)核中移除了,而且是在5.10內(nèi)核中標(biāo)記移除的,不懂為什么OH的內(nèi)核維護(hù)者不移除掉,這個(gè)操作因?yàn)闀?huì)導(dǎo)致安全問(wèn)題,現(xiàn)代cpu已經(jīng)不支持了,所以我們可以大膽的去掉這部分代碼,我實(shí)際驗(yàn)證也是不影響內(nèi)核運(yùn)行,所以搜索我們移植的文件,把這些都刪掉吧。
這是我的改動(dòng),注釋掉的部分就是已經(jīng)無(wú)用的代碼。
(4)修復(fù)inode_permission(),vfs_mkdir(),vfs_unlink()函數(shù)參數(shù)問(wèn)題
因?yàn)閍pi改動(dòng),上記三個(gè)函數(shù)參數(shù)增加了,我參考了內(nèi)核其他代碼的調(diào)用,確認(rèn)添加【&init_user_ns】參數(shù)可以解決問(wèn)題。
修改如下圖所示:
把下面的配置加到內(nèi)核編譯sagit_oh_defconfig的末尾,編譯一次內(nèi)核看看能否成功。
3、移植accesstokenid驅(qū)動(dòng)
(1)復(fù)制驅(qū)動(dòng)代碼,修正Kconfig,Makefile
復(fù)制linux-5.10/drivers下的accesstokenid文件夾到linux-sagit/drivers文件夾下.
同樣的做法,把Kconfig,Makefile修正添加進(jìn)accesstokenid驅(qū)動(dòng)。
(2)修改accesstokenid驅(qū)動(dòng)關(guān)聯(lián)文件
通過(guò)【CONFIG_ACCESS_TOKENID】進(jìn)行搜索,發(fā)現(xiàn)紅框中的文件有accesstokenid相關(guān)聯(lián)的改動(dòng),需要手動(dòng)處理。
官方linux-5.10內(nèi)核的改動(dòng)是在【FORBIDDEN_MMAP_FLAGS】后面添加代碼。
我們同樣把【CONFIG_ACCESS_TOKENID】包含的代碼復(fù)制到linux-sagit的內(nèi)核中,同時(shí)【ACCESS_TOKENID_FEATURE_VALUE】跟【BINDER_CURRENT_FEATURE_SET】是依賴【ENABLE_ACCESS_TOKENID】的,也一并復(fù)制。
接下來(lái)就是捉迷藏游戲,把這些改動(dòng)找出來(lái),然后再根據(jù)插入位置的上一行代碼或者下一行代碼進(jìn)行搜索,把他們都轉(zhuǎn)移到對(duì)應(yīng)的位置,手動(dòng)合并改動(dòng)。
有些找不到對(duì)應(yīng)位置的,有可能是把聲明移到.h頭文件了,比如binder_thread這個(gè)結(jié)構(gòu)體5.10版本的時(shí)候是放在binder.c文件,6.0抽到binder_internal.h里面了。
還有一些改動(dòng)是加到switch里面的,直接放到default前面就行。
linux-5.10:
linux-sagit:
這里需要注意【BINDER_FEATURE_SET】也要一起復(fù)制過(guò)來(lái),因?yàn)槎际荗H添加的,我一開(kāi)始沒(méi)復(fù)制,導(dǎo)致開(kāi)機(jī)時(shí)log里面一直報(bào)binder錯(cuò)誤,后面通過(guò)gitee的按行查看功能,查看了binder.c的代碼才確定這段代碼也是OH團(tuán)隊(duì)添加的,屬于ACCESS_TOKENID的相關(guān)功能。
還有一些是上游代碼優(yōu)化了寫(xiě)法的,這個(gè)要讀懂代碼才能改,比如binder_init下面這段。
kernel-5.10的binder_init中,OH在【debugfs_create_file("failed_transaction_log"】后面添加了一段代碼。
在我們的linux-sagit中是linux6.0的代碼,已經(jīng)優(yōu)化掉了,不能像之前那樣直接找到插入的位置。
新版直接用for循環(huán)簡(jiǎn)化掉了大段的代碼。
為了保證移植的正確,這時(shí)我們要分析代碼運(yùn)行了。
舊版:
1.debugfs_create_dir("binder", NULL);
2.debugfs_create_dir("proc",binder_debugfs_dir_entry_root);
3.debugfs_create_file("state"/"transactions"...
4.(OH)proc_create_data("transaction_proc"...
新版:
1.debugfs_create_dir("binder", NULL);
2.debugfs_create_file("state"/"transactions"..
3.debugfs_create_dir("proc",binder_debugfs_dir_entry_root);
根據(jù)函數(shù)名可以得知OH新加的時(shí)進(jìn)程相關(guān)的(proc),而且是在2.debugfs_create_dir("proc",binder_debugfs_dir_entry_root);的后面,所以我們參照這個(gè)邏輯,新版的改動(dòng)可以對(duì)應(yīng)為
新版:
1.debugfs_create_dir("binder", NULL);
2.debugfs_create_file("state"/"transactions"..
3.debugfs_create_dir("proc",binder_debugfs_dir_entry_root);
4.(OH)proc_create_data("transaction_proc"...
至此我移植時(shí)遇到的問(wèn)題以及解決的辦法已經(jīng)講完了,各位按照上面的這些辦法把需要移植代碼找到,添加到對(duì)應(yīng)的位置即可。
4、逆移植ashmem驅(qū)動(dòng)
后續(xù)我在點(diǎn)亮后發(fā)現(xiàn)桌面圖標(biāo)無(wú)法顯示,hilog瘋狂提示db方面的錯(cuò)誤,定位發(fā)現(xiàn)需要ashmem驅(qū)動(dòng),但是這個(gè)驅(qū)動(dòng)在Linux5.18的時(shí)候被移除了,我們需要把它重新移植回來(lái),我參考網(wǎng)上SoulInfernoDE發(fā)布的方法進(jìn)行了ashmem驅(qū)動(dòng)的還原
同時(shí)【CONFIG_ANDROID】這個(gè)標(biāo)志已經(jīng)移除了,我們還需要一些修改以便ashmem驅(qū)動(dòng)能正常編譯。
在staging下的Makefile中。
obj-$(CONFIG_ANDROID) 改成obj-y。
在staging/android下的Kconfig中。
去掉if ANDROID的判斷。
至此內(nèi)核代碼方面的改動(dòng)講解完成。
三、內(nèi)核編譯配置修改
1、添加設(shè)備必要內(nèi)核驅(qū)動(dòng)
在之前我們解包的文件中,有個(gè)deviceinfo的文件,里面可以看到,啟動(dòng)的時(shí)候,內(nèi)核需要加載以下這些模塊:
panel-jdi-fhd-r63452 msm i2c-qup rmi_i2c qcom_spmi_fg qcom_spmi_haptics。
我們直接把他們編譯進(jìn)內(nèi)核,這樣后續(xù)不需要修改gn處理ko模組文件,也不需要寫(xiě)init配置文件添加啟動(dòng)時(shí)模組加載的語(yǔ)句。
運(yùn)行命令進(jìn)入內(nèi)核配置菜單
按鍵盤的【/】鍵進(jìn)行搜索,輸入【r63452】
得到驅(qū)動(dòng)的狀態(tài)和菜單位置,我之前已經(jīng)該過(guò),所以現(xiàn)在時(shí)y(編譯進(jìn)內(nèi)核),默認(rèn)是m(編譯成模組)。
2、添加相關(guān)聯(lián)相關(guān)驅(qū)動(dòng)
把上面列出的這些必要的驅(qū)動(dòng)全部編譯進(jìn)內(nèi)核,同時(shí)關(guān)聯(lián)的驅(qū)動(dòng)也一并編譯進(jìn)內(nèi)核,比如:
觸摸屏?xí)鶬nput device support里面的這個(gè)event interface有關(guān)聯(lián),不一起編譯進(jìn)內(nèi)核的話觸摸屏驅(qū)動(dòng)無(wú)法正常工作。
添加ashmem驅(qū)動(dòng)。
3、添加OH定制驅(qū)動(dòng)
添加accestoken驅(qū)動(dòng),hdf可以不選。
添加關(guān)聯(lián)的binder ipc驅(qū)動(dòng)。
添加hilog,hievent等驅(qū)動(dòng)。
4、添加調(diào)試所需驅(qū)動(dòng)
根據(jù)pmOS的指導(dǎo),添加usb串口驅(qū)動(dòng)
按照pmOS給出的配置,在menuconfig界面搜索對(duì)應(yīng)驅(qū)動(dòng)進(jìn)行選擇,或者直接編輯defconfig文件加入。
至此內(nèi)核相關(guān)定制適配講解完成,下篇講解打包刷機(jī)調(diào)試,敬請(qǐng)期待。
??想了解更多關(guān)于開(kāi)源的內(nèi)容,請(qǐng)?jiān)L問(wèn):??