::: hljs-center
OHOS LTS 3.0移植到RaspberryPi 4B
liangkz
:::
1. 簡介
《沉浸式剖析OpenHarmony源代碼》一書沒有涉及系統移植方面的内容,是以在交了書稿到出版社之後,我就開始考慮系統移植方面的事情。在了解一些情況後綜合考量,我決定嘗試一下在Raspberry Pi 4B上移植OHOS,因為已經有成功的先例了,一來可行性沒問題,二來可以少走很多彎路。
本次移植參考了社群大佬 亮子力的“harmony-raspberry: 移植鴻蒙Harmony到樹莓派 (gitee.com)” 和 hazhuzhu哈豬豬 的“#星光計劃2.0# OpenHarmony3.0的樹莓派4B移植-學習記錄-開源基礎軟體社群-51CTO.COM” 。二位的成功移植案例,給了我不少啟發,雖然在實際移植過程中,我也經曆了一些他們沒遇到過的問題,但最終都比較順利地解決掉了。
下面是我将OHOS LTS3.0系統移植到 Raspberry Pi 4B 開發闆上所做的一些事情,感興趣的小夥伴可以參考下面的步驟進行操作,應該也能比較順利地完成初步的移植工作。
視訊連結:https://ost.51cto.com/show/13949
本次移植的相關代碼見碼雲倉庫:
https://gitee.com/liangkzgitee/ohoslts30rpi4b
已确認可運作的燒錄鏡像見百度網盤:
注意:本例觸屏方案為“EDT_FT5X06”,其他方案的觸屏可能會有顯示但無觸碰功能。
連結:https://pan.baidu.com/s/1KvSGFBf6pdyqdJTTq_1O6A?pwd=ohos
提取碼:ohos
連結内OhosLts30Pi4b目錄下的檔案清單:
1.ohos_rpi4b.img:完整的系統鏡像,直接用Raspberry Pi官方燒錄工具燒錄到SD卡上即可使用。
2.zImage:核心鏡像,可用于直接替換SD卡上“/boot/”分區裡的核心檔案。
3.boot.img:燒錄到SD卡上“/boot/”分區裡的内容,已包含核心鏡像。
4.system.img:OHOS系統鏡像,Linux下可用dd指令單獨燒錄到SD卡内的“/”分區,用sudo權限可修改該分區内的檔案,比如/system/etc/init.rpi4b.cfg 或 /system/etc/weston.ini 等。
5.vendor.img 和 userdata.img:目前并無實質性的重要内容,正常燒錄一次後就不用再管這兩個鏡像了。
2. OHOS LTS3.0
建立 LTS30 目錄,在該目錄内下載下傳 OHOS LTS3.0 源代碼:
$ repo init -u [email protected]:openharmony/manifest.git -b refs/tags/OpenHarmony-v3.0-LTS --no-repo-verify
$ repo sync -c -j4
$ repo forall -c 'git lfs pull'
$ ./build/prebuilts_download.sh
3. 産品配置部分
3.1 rpi4b.json 裝置部分
//productdefine/common/device/目錄下,拷貝“hi3516dv300.json”,并重命名為“rpi4b.json”,并修改相關字段:
{
"device_name": "rpi4b",
"device_company": "raspberrypi",
"target_os": "ohos",
"target_cpu": "arm",
"kernel_version": "",
"device_build_path": "device/raspberrypi/build"
}
3.2 rpi4b.json 産品部分
//productdefine/common/products/目錄下,拷貝“Hi3516DV300.json”,并重命名為 “rpi4b.json”,并修改相關字段:
{
"product_name": "rpi4b",
"product_company": "raspberrypi",
"product_device": "rpi4b",
"version": "2.0",
"type": "standard",
"product_build_path": "device/raspberrypi/build",
"parts":{
"ace:ace_engine_standard":{},
"ace:napi":{},
......
#【删除“hisilicon_products”這一行】
"hisilicon_products:hisilicon_products":{},
#【新增子系統和部件,//build/subsystem_config.json檔案中不添加該子系統資訊也沒關系】
"raspberrypi_products:raspberrypi_products":{},
......#【略,其他子系統/部件清單保持與Hi3516DV300一緻即可,也可自行裁剪】
"ark:ark":{},
"ark:ark_js_runtime":{},
"ark:ark_ts2abc":{}
}
}
可以對部件清單進行一下裁剪,把不相關部分部件去掉,但要注意可能會因為依賴關系的原因導緻編譯異常。
4. vendor部分
建立//vendor/raspberrypi/rpi4b/目錄,整體拷貝//vendor/hisilicon/Hi3516DV300/目錄下的 hdf_config 目錄到 //vendor/raspberrypi/rpi4b/ 目錄下,修改 hdf_config/khdf/hdf.hcs 檔案為:
#include "device_info/device_info.hcs"
root {
module = "raspberry,bcm2711_chip";
}
本例是有移植HDF的,不過在8.3的核心配置中,把“CONFIG_DRIVERS_HDF_TEST”注釋掉了,是以這裡需要增加一個Makefile去直接編譯 hdf_config/khdf/hdf.hcs, 而不去編譯 hdf_config/khdf/hdf_test/hdf.hcs。
以後再根據Raspberry Pi 4B的硬體實情來修改hdf_config的其他部分。
5. device部分
增加//device/raspberrypi/目錄下的内容,見本倉庫//device/raspberrypi/目錄下的檔案修改和同目錄下的README.md文檔
6. init_lite部分
修改//base/startup/init_lite/services/BUILD.gn 檔案,增加下面一句:
# init etc files group
ohos_prebuilt_etc("init.cfg") {
source = "//base/startup/init_lite/services/etc/init.cfg"
#add for rpi4b begin:
if( product_name == "rpi4b" ) {
source = "//base/startup/init_lite/services/etc/rpi4b_init_cfg/init.cfg"
}
#add for rpi4b end.
part_name = "init"
}
//base/startup/init_lite/services/etc/目錄下增加 “rpi4b_init_cfg/”目錄,将同目錄系的init.cfg檔案拷貝進去,并做修改。
7. drivers部分
把//drivers/peripheral/camera/hal/adapter/chipset/gni/ 目錄下的camera.rpi3.gni拷貝一份,并重命名為camera.rpi4b.gni,内容不需要修改。
8. kernel部分
8.1 //kernel/linux/ 核心代碼部分
Linux核心,不用OHOS自帶的 linux-5.10 源代碼,而是用RaspberryPi官方的5.10版本源代碼,這樣可以免去核心部分的移植工作。
在 //kernel/linux/ 目錄下建立 “linux-5.10-rpi4b” 目錄,把RaspberryPi官方的5.10分支核心源代碼,下載下傳到該目錄下:
git clone https://github.com/raspberrypi/linux linux-5.10-rpi4b
如果無法通過github下載下傳,那就在gitee上搜尋同版本的鏡像代碼下載下傳回來使用也可以。
8.2 //kernel/linux/build/ 編譯腳本部分
OHOS核心預設編譯生成 uImage,rpi4b 需要修改編譯生成 zImage。
BUILD.gn 檔案内:
增加下面兩處對(device_name == "rpi4b")的判斷和修改,可以讓rpi4b産品選用 8.1 中下載下傳的“linux-5.10-rpi4b”核心源代碼去生成zImage鏡像檔案。
if (device_name == "rpi4b") {
kernel_source_dir = "//kernel/linux/$linux_kernel_version-$device_name"
}
......
if (device_name == "rpi4b") {
outputs = [ "$root_build_dir/packages/phone/images/zImage" ]
} else {
outputs = [ "$root_build_dir/packages/phone/images/uImage" ]
}
build_kernel.sh 檔案内:
if [ "$7" == "rpi4b" ];then
# 将zImage、dtb、overlays、modules拷貝到images目錄下備用
cp ${2}/kernel/src_tmp/${8}/arch/arm/boot/zImage ${3}/zImage
cp ${2}/kernel/src_tmp/${8}/arch/arm/boot/dts/bcm2711-rpi-4-b.dtb ${3}/
cp -r ${2}/kernel/src_tmp/${8}/arch/arm/boot/dts/overlays ${3}/
cp -r ${2}/kernel/src_tmp/${8}/modules ${3}/
# 删除modules下的兩個軟連結,否則在制作img階段會把軟連結的内容一并拷貝,會出現異常。
rm ${3}/modules/lib/modules/5.10*/build
rm ${3}/modules/lib/modules/5.10*/source
else
#if [ "$7" == "hi3516dv300" ];then
cp ${2}/kernel/src_tmp/${8}/arch/arm/boot/uImage ${3}/uImage
fi
#在上述操作中拷貝的modules目錄,将會被拷貝到//out/ohos-arm-release/packages/phone/system/lib/目錄下,一并被打包到system.img内,燒錄到SD卡裡,系統啟動時會insmod其中的部分子產品。
kernel_module_build.sh 檔案内:
if [ "$5" == "rpi4b" ];then
LINUX_KERNEL_UIMAGE_FILE=${LINUX_KERNEL_OUT}/arch/arm/boot/zImage
else
LINUX_KERNEL_UIMAGE_FILE=${LINUX_KERNEL_OUT}/arch/arm/boot/uImage
fi
kernel.mk 檔案内:
從上到下的修改(請搜尋關鍵字“rpi4b”):
- 增加編譯modules的安裝路徑:
KERNEL_SRC_TMP_PATH := $(OUT_DIR)/kernel/src_tmp/${KERNEL_VERSION}
ifeq ($(DEVICE_NAME), rpi4b)
KERNEL_MODULES_PATH := $(OUT_DIR)/kernel/src_tmp/${KERNEL_VERSION}/modules
endif
- 修改核心源代碼路徑:
ifeq ($(DEVICE_NAME), rpi4b)
KERNEL_SRC_PATH := $(OHOS_BUILD_HOME)/kernel/linux/${KERNEL_VERSION}-${DEVICE_NAME}
else
KERNEL_SRC_PATH := $(OHOS_BUILD_HOME)/kernel/linux/${KERNEL_VERSION}
endif
- 修改編譯核心的工具鍊
OHOS預設使用 arm-linux-gnueabi 編譯工具來編譯Linux核心,用這個編譯rpi4b使用的核心也可以。
但建議用RaspberryPi官方推薦的 arm-linux-gnueabihf 編譯工具來編譯核心(32位系統)。
請先執行 “sudo apt install crossbuild-essential-armhf ” 将編譯工具安裝到預設的 /usr/bin/ 目錄下,然後修改編譯工具鍊:
ifeq ($(DEVICE_NAME), rpi4b)
KERNEL_TARGET_TOOLCHAIN := /usr/bin
KERNEL_TARGET_TOOLCHAIN_PREFIX := $(KERNEL_TARGET_TOOLCHAIN)/arm-linux-gnueabihf-
else
KERNEL_TARGET_TOOLCHAIN := $(PREBUILTS_GCC_DIR)/linux-x86/arm/gcc-linaro-7.5.0-arm-linux-gnueabi/bin
KERNEL_TARGET_TOOLCHAIN_PREFIX := $(KERNEL_TARGET_TOOLCHAIN)/arm-linux-gnueabi-
endif
- 修改編譯目标:
ifeq ($(DEVICE_NAME), rpi4b)
KERNEL_IMAGE_FILE := $(KERNEL_SRC_TMP_PATH)/arch/arm/boot/zImage
else
KERNEL_IMAGE_FILE := $(KERNEL_SRC_TMP_PATH)/arch/arm/boot/uImage
endif
- 修改make指令的編譯目标、安裝modules到INSTALL_MOD_PATH指定的位置:
ifeq ($(DEVICE_NAME), rpi4b)
$(hide) $(KERNEL_MAKE) -C $(KERNEL_SRC_TMP_PATH) ARCH=$(KERNEL_ARCH) $(KERNEL_CROSS_COMPILE) -j64 zImage modules dtbs
$(hide) $(KERNEL_MAKE) -C $(KERNEL_SRC_TMP_PATH) ARCH=$(KERNEL_ARCH) $(KERNEL_CROSS_COMPILE) -j64 INSTALL_MOD_PATH=$(KERNEL_MODULES_PATH) modules_install
else
$(hide) $(KERNEL_MAKE) -C $(KERNEL_SRC_TMP_PATH) ARCH=$(KERNEL_ARCH) $(KERNEL_CROSS_COMPILE) -j64 uImage
endif
8.3 //kernel/linux/config/ 編譯配置部分
//kernel/linux/linux-5.10-rpi4b/arch/arm/configs/bcm2711_defconfig
将上述檔案拷貝并改名到:
//kernel/linux/config/linux-5.10/arch/arm/configs/rpi4b_standard_defconfig
在該檔案内增加Android Binder、OHOS HDF、Security部分的配置,詳細配置的開關,見本倉庫上述路徑下的檔案,這些配置可根據實際情況微調。
另外,為避免OHOS HDF的USB部分編譯失敗,需将 rpi4b_standard_defconfig 檔案内的:
“CONFIG_USB_CONFIGFS=m”
修改為:
“CONFIG_USB_CONFIGFS=y”
将該子產品直接編譯進核心。
其他預設編譯成子產品的部分如:
CONFIG_DRM=m
...
CONFIG_DRM_V3D=m
CONFIG_DRM_VC4=m
等,可先保持不動,我們會在”5.device部分“的“init.rpi4b.cfg”檔案中加載相應的子產品起來運作即可。
或者在這裡将相應的CONFIG_XXX配置成“=y”,直接将其編譯進核心,則在”5.device部分“ 的 “init.rpi4b.cfg” 檔案中就不需要 insmod 了。
8.4 //kernel/linux/patches/ 編譯更新檔部分
//kernel/linux/patches/linux-5.10/rpi4b_patch/目錄下兩個patch檔案。
hdf.patch 檔案拷貝自 .../hi3516dv300_patch/hdf.patch,完全不用修改。
rpi4b.patch 檔案原本應該是OHOS移植到rpi4b平台上所需要的大量适配代碼的patch,但因為目前使用的kernel 代碼是RaspberryPi官方的核心,已經包含所有的适配代碼了,是以rpi4b.patch可以留白,這裡是直接拷貝 hi3516dv300_small.patch,并做簡單處理:
diff --git a/include/uapi/linux/android/binder.h b/include/uapi/linux/android/binder.h
index ec84ad106568..9d7b05055726 100644
--- a/include/uapi/linux/android/binder.h
+++ b/include/uapi/linux/android/binder.h
@@ -27,6 +27,7 @@
#define B_PACK_CHARS(c1, c2, c3, c4) \
((((c1)<<24)) | (((c2)<<16)) | (((c3)<<8)) | (c4))
#define B_TYPE_LARGE 0x85
+
enum {
BINDER_TYPE_BINDER = B_PACK_CHARS('s', 'b', '*', B_TYPE_LARGE),
9. third_party部分
9.1 eudev
//third_party/eudev/rules.d/touchscreen.rules 檔案的修改。
Raspberry Pi 4B的觸碰顯示屏,有多個硬體方案,不同方案需要加載不同的驅動程式。
對于我的Raspberry Pi 4B開發闆,在Raspberry Pi 4B上運作官方系統時,通過檢視觸屏的裝置資訊和驅動程式(驅動程式用于insmod,或者在編譯核心時直接編譯進去),看到有"vc4"和"generic ft5x06 (79)"兩個,把它們都加進rules檔案中去。這一步需要請小夥伴們根據自己的觸屏裝置的實際資訊修改和添加:
ATTRS{name}=="vc4", ENV{ID_INPUT}="1", ENV{ID_INPUT_TOUCHSCREEN}="1"
ATTRS{name}=="generic ft5x06 (79)", ENV{ID_INPUT}="1", ENV{ID_INPUT_TOUCHSCREEN}="1"
......
9.2 weston.ini
//third_party/weston/weston.ini 檔案的修改。
在我的環境下,不改這個檔案,顯示屏也會有正常顯示,但是觸屏的觸碰輸入功能會失效,必須要在此檔案末尾增加如下修改,觸碰輸入功能才會正常。
[output]
name=card0
#name=HDMI-A-1
注意:如果Raspberry Pi 4B不帶(或不接)觸屏,則要把HDMI裝置接到HDMI0端口上,再把上面的name字段設定為“HDMI-A-1”即可。如果HDMI裝置接到HDMI1端口上,則隻會在開機階段顯示終端上的log,weston運作起來之後會無輸出了。
10. build 部分
10.1 打包modules到system.img
修改 //build/ohos/images/build_image.py 腳本:
def _prepare_root(system_path):
......
os.symlink('/system/bin', os.path.join(root_dir, 'bin'))
os.symlink('/system/bin/init', os.path.join(root_dir, 'init'))
os.symlink('/system/etc', os.path.join(root_dir, 'etc'))
#rpi4b added begin:
# if modules_src exists:
# copy .../phone/images/modules/lib/modules to .../system/lib/modules
modules_src = os.path.join(system_path, "../images/modules/lib/modules")
if os.path.exists(modules_src):
modules_dest = os.path.join(system_path, 'lib/modules')
shutil.rmtree(modules_dest, ignore_errors=True)
shutil.copytree(modules_src, modules_dest, symlinks=True)
os.symlink('/system/lib', os.path.join(root_dir, 'lib'))
#rpi4b added end.
在 _prepare_root 函數末尾增加這幾句話,把modules部分拷貝到system對應目錄下,一并生成到system.img 鏡像内,并生成 /lib 到 /system/lib 的軟連結。【Hi3516DV300項目會因為不存在modules_src目錄而不會跑拷貝的步驟】
修改 //build/ohos/images/mkimage/dac.txt 檔案,增加兩句:
# dir
system/lib/modules, 00751, 0, 2000, 0
# file
system/lib/modules/*, 00755, 0, 2000, 0
為了讓system.img、vendor.img、userdata.img鏡像不至于太大,修改 //build/ohos/images/mkimage/ 目錄下的:
system_image_conf.txt 檔案【本檔案實際可不改】:
-1610612224
+536869888
vendor_image_conf.txt 檔案大小不改。
userdata_image_conf.txt 檔案【本檔案實際可不改】:
-1468006400
+268434944
10.2 編譯rpi4b産品
代碼根目錄下執行:
./build.sh --product-name rpi4b --ccache
即可開始編譯rpi4b産品。
11. 生成分離的燒錄鏡像
編譯成功,生成的鏡像有:zImage、system.img、vendor.img、userdata.img 這四個用于本項目的燒錄,updater.img 鏡像可先不管。
根據8.2的編譯核心的腳本的更改,zImage、dtb、overlays、modules會被拷貝到images目錄下。
根據10.1的打包鏡像腳本的更改,modules會被拷貝到.../system/lib/modules/目錄下,一并打包進system.img 裡。
如果你已有燒錄了Raspberry Pi官方系統的SD卡,可以保持上面的/boot分區不動,把這裡的zImage拷貝進去,在config.txt檔案中修改啟動的核心為:kernel=zImage。
再在Linux下用fdisk指令,删除/rootfs分區,并重建立立三個主分區,分區大小建議大于 10.1 中修改的各分區鏡像大小即可。再用dd指令分别将 system.img、vendor.img、userdata.img 三個鏡像燒錄到SD卡的mmcblk0p2、mmcblk0p3、mmcblk0p4 分區即可。
注意分區的燒錄位置,system.img一定要燒錄到mmcblk0p2分區,因為在/boot分區的cmdline.txt中指定了root分區的位置為 /dev/mmcblk0p2。
vendor.img和userdata.img兩個鏡像分别燒錄到mmcblk0p3、mmcblk0p4分區。在 /system/etc/init.cfg 中有:
"mount ext4 /dev/block/mmcblk0p3 /vendor wait rdonly barrier=1",
"mount ext4 /dev/block/mmcblk0p4 /data wait nosuid nodev noatime barrier=1,data=ordered,noauto_da_alloc"
會把它們分别挂載到/vendor和/data下。
12. 生成合并的ohos_rpi4b.img燒錄鏡像
如果想要生成合并的系統鏡像,可以參考并使用亮子力的腳本,見倉庫:harmony-raspberry: 移植鴻蒙Harmony到樹莓派 (gitee.com) 内的使用說明。
本地步驟如下:
12.1 整體拷貝燒錄官方rpi4b系統的SD卡的boot分區内容到://device/raspberrypi/rpi4b/build/boot/ 目錄下。
12.2 根據實際情況修改 cmdline.txt 中的root字段:
... root=/dev/mmcblk0p2 ...
12.3 修改 config.txt 檔案,将啟動的核心鏡像修改為 zImage:
# which kernel to boot
kernel=zImage
# 啟用fake KMS,而不是原來的vc4-kms-v3d
dtoverlay=vc4-fkms-v3d
12.4 建立 //device/raspberrypi/mkimg/目錄,把亮子力的倉庫中的:
https://gitee.com/liangzili/harmony-raspberry/blob/master/rpi4b/device/raspberrypi/images/
目錄下的腳本拷貝到此目錄下(實際隻需要mkboot.py 和 mergeImg.sh)。
在項目代碼根目錄下執行mkboot.py腳本指令,以生成 boot.img 鏡像:
python device/raspberrypi/mkimg/mkboot.py --input-path ./out/ohos-arm-release/packages/phone --output-image ./out/ohos-arm-release/packages/phone/images/boot.img
在項目代碼根目錄下執行mergeImg.sh腳本指令,以生成 ohos_rpi4b.img 鏡像:
./device/raspberrypi/mkimg/mergeImg.sh ./out/ohos-arm-release/packages/phone/images/boot.img ./out/ohos-arm-release/packages/phone/images/system.img ./out/ohos-arm-release/packages/phone/images/vendor.img ./out/ohos-arm-release/packages/phone/images/userdata.img ./out/ohos-arm-release/packages/phone/images/ohos_rpi4b.img
将 ohos_rpi4b.img 拷貝到Windows系統硬碟下,通過RaspberryPi官方的Imager燒錄工具将其燒錄到SD卡即可。
以後再修改代碼和編譯OHOS後:
- 如隻涉及核心的修改(不涉及modules的動态加載),可直接将新生成的zImage檔案拷貝并替換SD卡内的boot分區中的zImage檔案(或相關檔案)即可。
- 如隻涉及system分區内容的相關修改(包括涉及modules的動态加載),可直接在Linux指令行下,使用 “dd” 指令單獨燒錄system.img鏡像到SD卡的 /dev/mmcblk0p2 分區即可,不需要重新打包成ohos_rpi4b.img 和重新燒錄全部分區了。
- 預設的vendor分區和userdata分區,目前沒有什麼重要内容需要在rpi4b開發闆上用到,但這兩個分區會預設挂載到根目錄下,暫沒必要重複燒錄。
附件連結:https://ost.51cto.com/resource/2085