OpenHarmony 2.0 Canary Linux Kernel 的编译流程 原创 精华

liangkz_梁开祝
发布于 2021-9-9 11:16
浏览
12收藏

OpenHarmony 2.0 Canary Linux Kernel的编译流程

liangkz 2021.09.09

 

OpenHarmony 2.0 Canary编译标准系统,默认使用的是Linux 4.19版本内核,在Canary上编译使用Linux内核的小型系统,cute(*^ω^*)遇见 已经给出过一篇详细的总结《编译linux内核的openharmony》,不过是在docker环境下编译的,在Linux环境下编译ipcamera_hispark_taurus_linux的话,需要先安装gcc-arm-linux-gnueabi编译工具:

$sudo apt install gcc-arm-linux-gnueabi

$arm-linux-gnueabi-gcc -v

然后就可以hb set 进行项目选择和 hb build 进行编译了。编译输出四个镜像:uImage_hi3516dv300_smp(内核镜像uImage改名而来)、rootfs_ext4.img、userfs_ext4.img、userdata_ext4.img,其中userdata_ext4.img烧录不烧录都没问题,注意fastboot引导命令的参数即可,与使用LiteOS_A内核的稍有不同:

setenv bootargs "mem=128M console=ttyAMA0,115200 root=/dev/mmcblk0p3 rw rootfstype=ext4 rootwait selinux=0 rootdelay=5 blkdevparts=mmcblk0:1M(boot),9M(kernel),50M(rootfs),50M(userfs),-(userdata)"

setenv bootcmd "mmc read 0x0 0x82000000 0x800 0x4800;bootm 0x82000000"

saveenv

reset

这里是烧录了userdata_ext4.img后,增加了,-(userdata)参数,不烧录就去掉。

标准系统的Linux内核和小型系统的Linux内核,是共用的,当然也可以配置为一个使用linux-5.10,另一个使用linux-4.19,针对性地修改一下编译配置脚本即可。

 

下面我们来详细看一下linux内核的编译流程和如何配置编译linux-5.10内核。

标准系统单独编译Linux内核组件的指令为:

$./build.sh --product-name Hi3516DV300 --ccache --build-target linux_kernel

而小型系统单独编译Linux内核组件的指令为:

$hb build -T linux_kernel

当执行上述语句,或者全编译系统编译到内核组件时,编译到内核组件的入口在:

//kernel/linux/build/BUILD.gn

打开这个文件看一下:

declare_args() {

    #默认Linux内核版本是4.19,想要编译5.10版本的内核,修改办法见下面【7-1】的说明

    kernel_version = "linux-4.19" 

}

 

if (defined(ohos_lite)) {

    #小型系统的Linux内核编译入口

    build_ext_component("linux_kernel") {

    exec_path = rebase_path(".", root_build_dir)

    outdir = rebase_path("$root_out_dir")

    clang_dir = ""

    if (ohos_build_compiler_dir != "") {

        clang_dir = rebase_path("${ohos_build_compiler_dir}")

    }

    build_type = "small"

    product_path_rebase = rebase_path(product_path, ohos_root_path)

    #小型系统编译Linux内核的执行脚本

    command = "./kernel_module_build.sh ${outdir} ${build_type} ${clang_dir} \

                ${product_path_rebase} ${board_name} ${kernel_version}"

    deps = [ "//build/lite:mark_as_prebuilts" ]

  }

} else {

    #标准系统的Linux内核编译入口

    kernel_build_script_dir = "//kernel/linux/build"

    #内核源代码是//kernel/linux/linux-4.19/,而不是//kernel/linux-4.19/,这个要注意

    kernel_source_dir = "//kernel/linux/$kernel_version"   

 

    action("build_kernel") {

        #标准系统编译Linux内核的执行脚本,会调用kernel_module_build.sh

        script = "build_kernel.sh"

        sources = [ kernel_source_dir ]

        product_path="vendor/$product_company/$product_name"

        build_type = "standard"

        outputs = [ "$root_build_dir/packages/phone/images/uImage" ]

        args = [

            rebase_path(kernel_build_script_dir, root_build_dir),

            rebase_path("$root_out_dir/../KERNEL_OBJ"),

            rebase_path("$root_build_dir/packages/phone/images"),

            build_type,

            rebase_path("$clang_base_path"),

            product_path,

            device_name,

            kernel_version

        ]

    }

 

    group("linux_kernel") {

        deps = [

            ":build_kernel",

        ]

    }

}

小型系统与标准系统编译Linux内核的脚本可以说是一样的,只是两者编译的参数稍有不同,导致Linux内核源代码拷贝到out目录下的路径有所不同而已,其它流程都是一样的。

先看标准系统编译内核的build_kernel.sh脚本:

./kernel_module_build.sh ${2} ${4} ${5} ${6} ${7} ${8}

mkdir -p ${3}

cp ${2}/kernel/src_tmp/${8}/arch/arm/boot/uImage ${3}/uImage

就是去掉1/3两个参数再调用kernel_module_build.sh,生成内核镜像uImage,然后再将uImage拷贝到参数3指定的路径下即可。

再看kernel_module_build.sh脚本,前面的if...elif判断,主要是为了配置LINUX_KERNEL_OUT路径和编译工具链等参数,标准系统和小型系统的配置有细微的差别。

 

接下来是“make -f kernel.mk”,编译成功或失败,都会echo相应的提示到终端。

编译成功的话,小型系统则在这里执行拷贝操作,uImage镜像名字改成了uImage_hi3516dv300_smp:

cp -rf ${LINUX_KERNEL_UIMAGE_FILE} ${OUT_DIR}/uImage_${DEVICE_NAME}_smp 

编译成功的话,标准系统则在上面的build_kernel.sh脚本中执行拷贝操作。

 

打开kernel.mk查看,编译内核也就这几步:

$(KERNEL_IMAGE_FILE):

 $(hide) echo "build kernel..."

【1】 $(hide) rm -rf $(KERNEL_SRC_TMP_PATH);mkdir -p $(KERNEL_SRC_TMP_PATH);cp -arfL $(KERNEL_SRC_PATH)/* $(KERNEL_SRC_TMP_PATH)/

【2】 $(hide) cd $(KERNEL_SRC_TMP_PATH) && patch -p1 < $(HDF_PATCH_FILE) && patch -p1 < $(DEVICE_PATCH_FILE)

【3】 $(hide) cp -rf $(KERNEL_CONFIG_PATH)/. $(KERNEL_SRC_TMP_PATH)/

【4】 $(hide) $(KERNEL_MAKE) -C $(KERNEL_SRC_TMP_PATH) ARCH=$(KERNEL_ARCH) $(KERNEL_CROSS_COMPILE) distclean

【5】 $(hide) $(KERNEL_MAKE) -C $(KERNEL_SRC_TMP_PATH) ARCH=$(KERNEL_ARCH) $(KERNEL_CROSS_COMPILE) $(DEFCONFIG_FILE)

ifeq ($(KERNEL_VERSION), linux-5.10)

【6】 $(hide) $(KERNEL_MAKE) -C $(KERNEL_SRC_TMP_PATH) ARCH=$(KERNEL_ARCH) $(KERNEL_CROSS_COMPILE) modules_prepare

endif

【7】 $(hide) $(KERNEL_MAKE) -C $(KERNEL_SRC_TMP_PATH) ARCH=$(KERNEL_ARCH) $(KERNEL_CROSS_COMPILE) -j64 uImage

endif

 

.PHONY: build-kernel

build-kernel: $(KERNEL_IMAGE_FILE)

下面就在我的编译环境下简单看一下做了些什么:

【7-1】删除KERNEL_SRC_TMP_PATH目录下的Linux Kernel源代码拷贝(包括上一次编译生成的中间文件和镜像文件),重新生成一个空的目录,再将KERNEL_SRC_PATH目录整体拷贝过去。

KERNEL_SRC_PATH目前配置是//kernel/linux/linux-4.19/,而不是//kernel/linux-4.19/,估计是与build/config/patches目录的位置有关。

【2021.08.31~09.07之间的代码,开始支持编译Linux5.10内核】如果要编译5.10版本的内核,需要改以下三处地方:

【A】//kernel/linux/build/BUILD.gn                                       的 kernel_version 字段修改成linux-5.10,

【B】//device/hisilicon/hispark_taurus/sdk_linux/config.gni  的 kernel_version 字段修改成linux-5.10,

【C】//device/hisilicon/hispark_taurus/sdk_linux/build.sh    的 export KERNEL_VERSION 字段修改成linux-5.10

再去编译时,KERNEL_SRC_PATH就会配置成//kernel/linux/linux-5.10/,去编译5.10版本内核了,编译出来的镜像烧录到开发板上也能正常跑起来,log如下:

## Booting kernel from Legacy Image at 82000000 ...

   Image Name:   Linux-5.10.57

   Image Type:   ARM Linux Kernel Image (uncompressed)

   Data Size:    4987452 Bytes = 4.8 MiB

   Load Address: 80008000

   Entry Point:  80008000

   Loading Kernel Image

Starting kernel ...

Booting Linux on physical CPU 0x0

Linux version 5.10.57 (ohos@ubuntu) (OHOS () clang version 10.0.1.69957   ......

 

2021.09.07之后的代码,对编译Linux内核的相关脚本做了调整【见评论】,默认编译Linux5.10版本内核,如需要编译Linux 4.19版本内核,只需要修改//build/ohos/kernel/kernel.gni 文件下的 linux_kernel_version = "linux-5.10" 为4.19版本即可,其它文件的内核版本都是从这里引用的。

默认编译"linux-5.10"时,虽然 //device/hisilicon/hispark_taurus/sdk_linux/config.gni 中也有一个 kernel_version = "4.19",但这个kernel_version看上去并没有使用到,不用管。

另外,09.07之后的代码,也删除了 //kernel/linux-4.19/ 目录,避免了代码引用的困扰。

 

KERNEL_SRC_TMP_PATH目录,按编译4.19版本内核来看:

标准系统:out/KERNEL_OBJ/kernel/src_tmp/linux-4.19/

小型系统:out/hispark_taurus/ipcamera_hispark_taurus_linux/kernel/linux-4.19/

 

【7-2】进入KERNEL_SRC_TMP_PATH,把//kernel/linux/patches/linux-4.19/hi3516dv300_patch/目录下的hdf.patch和hi3516dv300.patch两个patch加入到Linux Kernel中,一起编译进内核镜像里。

hdf.patch会把//drivers/framework/目录和//drivers/adapter/khdf/linux/目录软链接到KERNEL_SRC_TMP_PATH/drivers/hdf/目录下,编译这两个目录的时候,会在 //drivers/framework/ 和 //drivers/adapter/khdf/linux/目录下生成中间文件,其它的相关的修改如Makefile等,会patch到相关文件中。

hi3516dv300.patch主要是针对hi3516dv300开发板的板级硬件的驱动适配,包括设备树文件、具体硬件模块配置、驱动代码、编译配置等等。

 

【7-3】Hi3516开发板的CPU是32位的arm架构芯片,这一步将//kernel/linux/config/linux-4.19/目录下的芯片架构相关配置文件拷贝到KERNEL_SRC_TMP_PATH对应的子目录下,编译时据此进行针对性地编译相关模块。

 

【7-4】到【7-7】就是具体的make指令编译过程了,不再赘述。

 

因为CPU是32位的arm架构芯片,编译生成的uImage镜像在KERNEL_SRC_TMP_PATH/arch/arm/boot/目录下,在前面的build_kernel.sh/kernel_module_build.sh中,会被拷贝或改名拷贝到对应的目录下,被烧录工具拿去烧录。

 

附件是我单独编译标准系统的Linux内核的部分log。

 

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
分类
build_kernel.rar 1.66K 30次下载
已于2021-9-12 23:17:52修改
10
收藏 12
回复
举报
3条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

流程很清晰,学习一波,回去试试。

2
回复
2021-9-9 15:53:38
liangkz_梁开祝
liangkz_梁开祝

写上面这篇帖子所用的代码,是master分支,大概是8.30~9.5之间不记得是哪天更新的了,好好地编译小型系统+Linux4.19或5.10内核,都能好好工作,标准系统+Linux4.19内核也能好好工作,昨晚发现标准系统+Linux5.10内核会出现kernel panic现象,没找到原因。

 

今早起来,无意去 repo sync了一下代码,发现有不少改动,与上文提到的修改有了差异,赶紧到gitee看一下kernel_linux_build等相关仓库,~.~!! 

9.7 对内核编译部分做了一些调整,上文提到的修改位置看起来已经不准确了。

回复
2021-9-10 08:33:57
爱吃土豆丝的打工人
爱吃土豆丝的打工人

学习学习~

回复
2021-9-10 09:37:45
回复
    相关推荐