4. U-boot的修改与编译

借助LubanCat-SDK,我们可以很方便的进行U-boot的编译,但是有时候我们还要根据板卡的实际情况来修改U-boot,实现一些定制功能。 为此,我们必须对U-boot进行一个深入的了解。

下面的内容,我们将会了解LubanCat-SDK是如何实现对U-boot的一键构建,构建参数又与哪些文件有关

不同LubanCat板卡使用相同版本的U-Boot源码进行构建,仅少量配置不同, 下述文档以使用RK3568处理器的鲁班猫板卡为例进行说明,使用其他型号处理器的鲁班猫板卡内容基本相同, 仅在必要处指出不同点。

4.1. 获取U-boot

由于主线版U-boot对rk356x系列处理器的支持十分有限,所以我们选择使用RK版本的U-Boot:next-dev, 而RK版本的U-Boot又分为两部分,一个是U-boot本身的代码仓库,也就是u-boot目录下的内容, 还有一部分是工具包仓库,存放RK不开源的二进制文件、脚本、打包工具,用于打包生成loader、trust、uboot固件,在rkbin目录下。

注意

rkbin和U-Boot工程必须保持同级目录关系。

在LubanCat-SDK中已经有了这两部分内容,我们可以直接使用,也可用从官方获取。

4.1.1. 下载源代码

官方GitHub:

https://github.com/Caesar-github/u-boot next-dev分支

https://github.com/Caesar-github/rkbin master分支

野火源码仓库下载链接:

https://github.com/LubanCat

4.1.2. 下载指定分支

通常一个U-boot仓库往往维护着不同分支的U-boot,进入仓库目录下可通过命令查看及切换U-boot分支,

1
2
git clone --branch=next-dev https://github.com/LubanCat/u-boot.git
git clone --branch=master https://github.com/LubanCat/rkbin.git

4.2. U-boot编译

在LubanCat-SDK中,自动编译脚本基本上都存放在build.sh中,这是SDK的主要功能入口

在build.sh中,U-boot的构建函数是function build_uboot() 具体内容如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
function build_uboot(){
    check_config RK_UBOOT_DEFCONFIG || return 0
    build_check_cross_compile
    prebuild_uboot

    echo "============Start building uboot============"
    echo "TARGET_UBOOT_CONFIG=$RK_UBOOT_DEFCONFIG"
    echo "========================================="

    if [ "$RK_RAMDISK_SECURITY_BOOTUP" = "true" ];then
        if [ -n "$RK_CFG_RAMBOOT" ];then
            build_ramboot
        else
            build_kernel
        fi

        if [ -n "$RK_CFG_RECOVERY" ]; then
            build_recovery
        fi
        cp -f $TOP_DIR/rockdev/boot.img $TOP_DIR/u-boot/boot.img
        cp -f $TOP_DIR/rockdev/recovery.img $TOP_DIR/u-boot/recovery.img || true
    fi

    cd u-boot
    rm -f *_loader_*.bin
    if [ "$RK_LOADER_UPDATE_SPL" = "true" ]; then
        rm -f *spl.bin
    fi

    if [ -n "$RK_UBOOT_DEFCONFIG_FRAGMENT" ]; then
        if [ -f "configs/${RK_UBOOT_DEFCONFIG}_defconfig" ]; then
            make ${RK_UBOOT_DEFCONFIG}_defconfig $RK_UBOOT_DEFCONFIG_FRAGMENT
        else
            make ${RK_UBOOT_DEFCONFIG}.config $RK_UBOOT_DEFCONFIG_FRAGMENT
        fi
        ./make.sh $UBOOT_COMPILE_COMMANDS
    elif [ -d "$TOP_DIR/prebuilts/gcc/linux-x86/arm/gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf" ]; then
        ./make.sh $RK_UBOOT_DEFCONFIG \
            $UBOOT_COMPILE_COMMANDS CROSS_COMPILE=$CROSS_COMPILE
    elif [ -d "$TOP_DIR/prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu" ]; then
        ./make.sh $RK_UBOOT_DEFCONFIG \
            $UBOOT_COMPILE_COMMANDS CROSS_COMPILE=$CROSS_COMPILE
    else
        ./make.sh $RK_UBOOT_DEFCONFIG \
            $UBOOT_COMPILE_COMMANDS
    fi

    if [ "$RK_IDBLOCK_UPDATE_SPL" = "true" ]; then
        ./make.sh --idblock --spl
    fi

    if [ "$RK_RAMDISK_SECURITY_BOOTUP" = "true" ];then
        ln -rsf $TOP_DIR/u-boot/boot.img $TOP_DIR/rockdev/
        ln -rsf $TOP_DIR/u-boot/recovery.img $TOP_DIR/rockdev/ || true
    fi

    finish_build
}
  • check_config检查是否有 RK_UBOOT_DEFCONFIG 这个配置变量,定义了U-boot编译用到的配置文件, 这个变量定义在device/rockchip/rk356x/BoardConfig-*.mk中

  • build_check_cross_compilep判断是否存在arm-none-linux-gnueabihf或aarch64-none-linux-gnu交叉编译工具链, 我们没有使用,这一部分可以忽略。

  • prebuild_uboot根据BoardConfig-*.mk中的定义来设定编译参数UBOOT_COMPILE_COMMANDS

  • 判断RK_RAMDISK_SECURITY_BOOTUP值是否为true,是否使用secure boot来对镜像进行签名认证, 我们没有定义,直接跳过

  • cd进入u-boot目录,先清除以前生成的miniloader文件,再判断uboot前一阶段是否为SPL, 如果是的话还要清除spl文件

  • RK_UBOOT_DEFCONFIG_FRAGMENT:由于RK版本U-boot支持配置文件的overlay功能, 这里判断是否开启了该功能,如果开启的话先将配置文件合并,我们没有使用到

  • 判断有没有arm-none-linux-gnueabihf或aarch64-none-linux-gnu来进行编译,没有使用,可以忽略。

  • 没有找到上面两个编译器,向./make.sh传递构建参数进行构建U-boot操作

  • RK_IDBLOCK_UPDATE_SPL和RK_RAMDISK_SECURITY_BOOTUP都没有定义,直接跳过

  • finish_build编译完成的一个提示函数。

4.3. U-boot修改

一般来说,要适配一块新的板卡,在U-boot中主要设计三部分的修改和添加,分别是board目录下涉及板卡初始化的部分、 configs目录下对应板卡的配置文件、arch目录下与板级外设相关的文件。

得益于Rockchip U-boot对rk系列处理器的完善支持,在U-boot阶段,我们直接根据使用的处理器型号选择Rockchip官方参考板的配置即可。 例如rk356x处理器使用evb_rk3568,rk3588x则使用evb_rk3588。

野火仅在U-boot中添加了设备树插件功能的实现。并使用boot_scripts方式进行启动引导,用于实现extboot分区的启动。

boot_scripts启动方式的启动命令脚本在SDK目录下的kernel/arch/arm64/boot/dts/rockchip/uEnv/boot.cmd, 在构建boot分区时进行编译,并打包到extboot分区内,命名为boot.scr,在系统启动前被U-boot读取并加载。 具体流程请查看上一章节 《U-boot启动内核过程》

4.3.1. U-boot配置文件

我们编译使用的配置文件由BoardConfig-*.mk的RK_UBOOT_DEFCONFIG变量定义, 在LubanCat-RK系列板卡上使用的具体文件是u-boot/configs/rk3568_defconfig和rk3566.config, 这里以LubanCat-2为例,如果我们要修改的话,可以借助menuconfig工具。

首先我们要来到U-boot根目录下,然后执行以下操作:

1
2
3
4
5
# 应用配置文件
make rk3568_defconfig

# 使用menuconfig来管理修改配置文件
make menuconfig
menuconfig

修改完成之后按ESC按键退出,并保存

1
2
3
4
5
# 保存defconfig文件
make savedefconfig

# 覆盖原来的配置文件
cp defconfig configs/rk3568_defconfig

4.3.2. 设备树文件

设备树文件是板级设备的描述文件,系统通过设备树文件得知板卡上有哪些外设,从而加载相应的驱动使外设正常工作。

原生的U-Boot只支持使用U-Boot自己的DTB,RK平台增加了kernel DTB机制的支持, 即使用kernel DTB去初始化外设。主要目的是为了兼容外设板级差异,如:power、clock、display 等。

二者的作用:

  • U-Boot DTB:负责初始化存储、打印串口等设备;

  • Kernel DTB:负责初始化存储、打印串口以外的设备;

U-Boot初始化时先用U-Boot DTB完成存储、打印串口初始化, 然后从存储上加载Kernel DTB并转而使用这份DTB继续初始化其余外设。

开发者一般不需要修改 U-Boot DTB(除非更换打印串口),RK系列处理器使用的defconfig都已启用kernel DTB机制。 所以通常对于外设的DTS修改,用户应该修改kernel DTB。

关于U-Boot DTB:

DTS目录:

  • u-boot/arch/arm/dts/rk3568-evb.dts

  • u-boot/arch/arm/dts/rk3588-evb.dts

启用kernel DTB机制后:编译阶段会把U-Boot DTS里带 u-boot,dm-pre-reloc 和 u-boot,dm-spl 属性的节点过滤出来, 在此基础上再剔除defconfig中 CONFIG_OF_SPL_REMOVE_PROPS 指定的property, 最终生成u-boot.dtb文件并且追加在u-boot.bin的末尾。

4.4. 参考资料

RK U-boot添加了很多自定义的功能,但其主体还是基于官方U-boot的,所以关于U-boot的操作都是基本相同的,我们可以参考以下wiki。

官方uboot下载链接: http://www.denx.de/wiki/uboot/WebHome

官方uboot GitHub: https://github.com/uboot/uboot

uboot wiki: http://www.denx.de/wiki/uboot/WebHome

RK U-boot的自定义功能则可以详细查看Rockchip文档 《U-Boot v2017(next-dev) 开发指南》