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