开发Openharmony的设备开发第一步就是移植内核,本文基于openharmony的sdk角度介绍openharmony的内核编译方式和单独编译内核的命令
这里内核有两个位置,一个是内核原始源码位置,这是oh标准内核,位置为/kernel/linux/linux-5.10/
在这个内核上,会添加如下几个依赖仓库的改动如下
"kernel/linux/build" # 编译相关脚本 "kernel/linux/linux-5.10" # 内核仓库 "kernel/linux/patches" # 内核相关补丁 "kernel/linux/config" # 内核的defconfig "kernel/linux/common_modules" # oh特性的内核驱动 "third_party/bounds_checking_function" # libboundscheck库,安全函数,带边界检查的标准函数 "device/soc/hisilicon/common/platform/wifi" # 海思wifi "third_party/FreeBSD/sys/dev/evdev" # evdev 头文件 "drivers/hdf_core" # hdf 核心驱动 "prebuilts/clang/ohos/linux-x86_64/llvm/bin" # llvm
这里值得注意的是,patch目录,它需要对内核合入hdf补丁,并且需要合入rk3568芯片的基础改动的patch,主要如下
└── rk3568_patch ├── kernel.patch # linux-5.10 rk3568 SOC patches └── hdf.patch # linux-5.10 rk3568 定制 HDF patches
我们通常做移植的后续工作是设配oh的硬件抽象层,主要如下
├── adapter ├── bundle.json ├── figures ├── framework ├── interfaces ├── LICENSE ├── OAT.xml ├── README.md └── README_zh.md
编译后的内核位置为/out/kernel/src_tmp/linux-5.10/
, 编译后内核的中间文件位置为/out/kernel/OBJ/linux-5.10/
此时代码是已经合入补丁和相关oh特性功能的代码。
编译内核可以分为最外层sdk模块编译,内核源码build_kernel.sh脚本编译(合并前),内核源码make-ohos.sh脚本编译(合并后),和内核分步骤编译,可以按需自行编译
对于内核而言,sdk模块编译目前默认不支持,但sdk外层编译有必要解释一下,所以编译内核的最外层sdk编译命令如下
./build.sh --product-name rk3568 --ccache
上述命令可以整体环境编译,故内核也编译了,但是缺点是编译一次时间太长。为了指定模块的单独编译,可以设置--build-target,如下是代码示例
group("make_images") group("eng_system_image") group("eng_chipset_image") group("chip_prod_image") group("sys_prod_image") group("system_image") group("userdata_image") group("vendor_image") group("ramdisk_image") group("updater_ramdisk_image") group("updater_image")
可以知道,通过如下参数指定编译
./build.sh --product-name rk3568 --ccache --build-target make_images ./build.sh --product-name rk3568 --ccache --build-target system_image ./build.sh --product-name rk3568 --ccache --build-target userdata_image
build-target还能通过指定gn路径+目标名指定模块编译,如下
./build.sh --product-name rk3568 --ccache --build-target commonlibrary/c_utils/base:util
这里commonlibrary/c_utils/base是BUILD.gn文件目录,util是BUILD.gn声明的模块名称。
虽然内核不能单独编译,但是执行全量编译只需要等待即可获得boot_linux.img文件
查看build-target支持的选项,如下命令
prebuilts/build-tools/linux-x86/bin/ninja -w dupbuild=warn -C out/rk3568/ -t targets
对于查出来的选项,可以直接用ninja编译模块,以内核举例
prebuilts/build-tools/linux-x86/bin/ninja -w dupbuild=warn -C out/rk3568/ kernel
如果使用hb命令,可以如下编译内核
hb build -T kernel
build_kernel.sh作为内核单模块BUILD.gn拉起的脚本,我们可以主动调用它来单独编译内核,但是前提是代码是全编过一次的,也就是out/rk3568目录存在。编译命令如下
`pwd`/../../device/board/hihope/rk3568/kernel/build_kernel.sh `pwd`/../../kernel/linux/linux-5.10 `pwd`/../../out/rk3568/packages/phone/images `pwd`/../../device/board/hihope/rk3568 vendor/hihope/rk3568 `pwd`/../../ rockchip rk3568 hihope root default disable_lto_O0 enable_ramdisk
这里解释如下
此命令需要绝对路径
build_kernel.sh需要11个形参分别如下 $1=../../kernel/linux/linux-5.10 # pushd 参数,切换目录到linux-5.10上 $2=out/rk3568/packages/phone/images # 镜像输出目录 $3=device/board/hihope/rk3568 # BUILD_SCRIPT_PATH变量 $4=vendor/hihope/rk3568 # PRODUCT_PATH变量 $5=`pwd` # ROOT_DIR变量 $6=rockchip # DEVICE_COMPANY变量 $7=rk3568 # DEVICE_NAME变量 $8=hihope # PRODUCT_COMPANY变量 $9=root # KERNEL_FORM变量 $10=default # KERNEL_PROD变量 $11=disable_lto_O0 # ENABLE_LTO_O0变量 $12=enable_ramdisk # 判断是否生成ramdisk
此命令如果是第一次运行,会自动打patch和复制oh特性驱动代码。如果不是第一次运行,则跳过不应用补丁,直接开始编译。此命令会主动拷贝文件到out/rk3568/packages/phone/images目录。
根据对build_kernel.sh的解析,为了在代码目录out/kernel/src_tmp/linux-5.10直接编译,可以直接如下命令编译
KBUILD_OUTPUT=../../OBJ/linux-5.10 PRODUCT_PATH=vendor/hihope/rk3568 DEVICE_COMPANY=rockchip DEVICE_NAME=rk3568 PRODUCT_COMPANY=hihope GPUDRIVER=mali ./make-ohos.sh TB-RK3568X0 enable_ramdisk
对于参数解析如下:
KBUILD_OUTPUT:指定内核编译中间文件位置 PRODUCT_PATH:指定产品路径,khdf需要使用 GPUDRIVER: 指定显卡驱动,瑞芯微支持mali和panfrost两种驱动 TB-RK3568X0:指定开发板类型,当前oh的sdk只支持TB-RK3568X0和TB-RK3568X10两款开发板,两个开发板对应的设备树不一样而已,其他没区别 enable_ramdisk:指定生成ramdisk镜像
通过上述命令可以在源码目录生成boot_linux目录和boot_linux.img,注意,此时的boot_linux.img不会主动复制到out/rk3568/packages/phone/images目录。
内核编译分三个步骤
编译defconfig 编译ko模块 编译image内核二进制
内核打包通过mke2fs打包ext2格式的镜像,通过make-boot.sh打包
涉及命令主要如下:
make KBUILD_OUTPUT=../../OBJ/linux-5.10 PRODUCT_PATH=vendor/hihope/rk3568 LLVM=1 LLVM_IAS=1 CROSS_COMPILE=aarch64-linux-gnu- ARCH=arm64 rockchip_linux_defconfig make KBUILD_OUTPUT=../../OBJ/linux-5.10 PRODUCT_PATH=vendor/hihope/rk3568 LLVM=1 LLVM_IAS=1 CROSS_COMPILE=aarch64-linux-gnu- ARCH=arm64 modules_prepare rm -rf ../../../kernel/vendor/hihope/rk3568/hdf_config/khdf/hdf_test/ make KBUILD_OUTPUT=../../OBJ/linux-5.10 PRODUCT_PATH=vendor/hihope/rk3568 LLVM=1 LLVM_IAS=1 CROSS_COMPILE=aarch64-linux-gnu- ARCH=arm64 rk3568-toybrick-x0-linux.img -j96
这时候内核已经编译成Image文件,需要手动cp一下
cp ../../OBJ/linux-5.10/arch/arm64/boot/Image boot_linux/extlinux/Image
然后运行make-boot.sh脚本打包boot_linux.img
./make-boot.sh ../../../
此时boot_linux.img文件存放在/rk3568/packages/phone/images/内
默认的hdf_test在单编译的时候会报错如下:
ld.lld: error: drivers/built-in.a(../../../vendor/hihope/rk3568/hdf_config/khdf/hdf_test/hdf_hcs_hex.o): Invalid value (Producer: 'LLVM15.0.4' Reader: 'LLVM 12.0.1')
上述日志说明hdf_hcs_hex.o和当前单编的llvm版本不一样,所以删除.o即可,如下操作
rm -rf ../../../kernel/vendor/hihope/rk3568/hdf_config/khdf/hdf_test/
缺少工具是因为缺少包导致,错误信息如下
BTF: .tmp_vmlinux.btf: pahole (pahole) is not available
安装dwarves包即可
apt install dwarves
如果编译环境出问题,如下命令清理一下
KBUILD_OUTPUT=../../OBJ/linux-5.10 make LLVM=1 LLVM_IAS=1 CROSS_COMPILE=aarch64-linux-gnu- ARCH=arm64 PRODUCT_PATH=vendor/hihope/rk3568 DEVICE_COMPANY=rockchip mrproper
如果是误操作在out/kernel/src_tmp/linux-5.10编译了中间文件,则需要在本目录操作mrproper,如下
make LLVM=1 LLVM_IAS=1 CROSS_COMPILE=aarch64-linux-gnu- ARCH=arm64 PRODUCT_PATH=vendor/hihope/rk3568 DEVICE_COMPANY=rockchip mrproper