蜗窝科技

X-011-UBOOT-使用bootm命令启动kernel(Bubblegum-96平台)

wowo · · X Project · 阅读 17272 · 2016年9月存档

1. 前言

我们在“X-010-UBOOT-使用booti命令启动kernel(Bubblegum-96平台)”中介绍了使用u-boot booti指令加载并运行ARM64 Image格式kernel的方法。与此同时,我们在“u-boot FIT image介绍”介绍了一种新的uImage(u-boot Image)格式—-FIT uImage。本文将基于这两篇文章,介绍FIT uImage的编译、启动等方法,目的有二:

1)作为“u-boot FIT image介绍”的实践篇。

2)以后“X Project”和u-boot有关的image格式,将统一使用FIT uImage。

2. FIT uImage的生成

2.1 向unify kernel的目标迈进

“u-boot FIT image介绍”中提到了,为了实现unify kernel的目标,需要为不同的平台编译同一个kernel image。换句话说,就是要有相同的kernel defconfig文件。因此,以Bubblegum-96平台为例,我们要建立统一的defconfig文件—-xprj_defconfig,步骤如下:

cd ./linux
make ARCH=arm64 allnoconfig

直接保存并退出

cp .config arch/arm64/configs/xprj_defconfig

生成的deconfig文件可参考

# https://github.com/wowotechX/linux/commit/1d9204207e91ffc21b845552db5756512274a37d

注1:记得我们在“X-010-UBOOT-使用booti命令启动kernel(Bubblegum-96平台)”中,为了删减kernel默认的配置项,累的死去活来的,其实有简便方法—-make allnoconfig,会生成指定平台下能work的最小kernel。

与此同时,修改“X Project”的编译脚本,ARM64架构的版型,统一使用xprj_defconfig,如下:

diff –git a/Makefile b/Makefile
index b51d943..bd25f83 100644
— a/Makefile
+++ b/Makefile
@@ -22,6 +22,10 @@ OUT_DIR=$(BUILD_DIR)/out
UBOOT_OUT_DIR=$(OUT_DIR)/u-boot
KERNEL_OUT_DIR=$(OUT_DIR)/linux

+ifeq ($(BOARD_ARCH), arm64)
+KERNEL_DEFCONFIG=xprj_defconfig
+endif
+
all: uboot kernel

clean: dfu-clean uboot-clean kernel-clean

@@ -59,13 +63,13 @@ uboot-clean:

kernel-config:
mkdir -p $(KERNEL_OUT_DIR)

  • cp -f $(KERNEL_DIR)/arch/$(BOARD_ARCH)/configs/$(BOARD_NAME)_defconfig $(KERNEL_OUT_DIR)/.config
  • cp -f $(KERNEL_DIR)/arch/$(BOARD_ARCH)/configs/$(KERNEL_DEFCONFIG) $(KERNEL_OUT_DIR)/.config
    make -C $(KERNEL_DIR) KBUILD_OUTPUT=$(KERNEL_OUT_DIR) ARCH=$(BOARD_ARCH) menuconfig
  • cp -f $(KERNEL_OUT_DIR)/.config $(KERNEL_DIR)/arch/$(BOARD_ARCH)/configs/$(BOARD_NAME)_defconfig
  • cp -f $(KERNEL_OUT_DIR)/.config $(KERNEL_DIR)/arch/$(BOARD_ARCH)/configs/$(KERNEL_DEFCONFIG)

kernel:
mkdir -p $(KERNEL_OUT_DIR)

  • make -C $(KERNEL_DIR) CROSS_COMPILE=$(CROSS_COMPILE) KBUILD_OUTPUT=$(KERNEL_OUT_DIR) ARCH=$(BOARD_ARCH) $(BOARD_NAME)_defconfig
  • make -C $(KERNEL_DIR) CROSS_COMPILE=$(CROSS_COMPILE) KBUILD_OUTPUT=$(KERNEL_OUT_DIR) ARCH=$(BOARD_ARCH) $(KERNEL_DEFCONFIG)
    make -C $(KERNEL_DIR) CROSS_COMPILE=$(CROSS_COMPILE) KBUILD_OUTPUT=$(KERNEL_OUT_DIR) ARCH=$(BOARD_ARCH) Image dtbs

kernel-clean:

具体可参考“https://github.com/wowotechX/build/commit/bba23bf1d63aabb797400185e4d6d764b651e3b6”。

2.2 基于新生成的kernel config,打开对bubblegum的支持(为了编译dtb文件)

CONFIG_ARCH_OWL=y

具体可参考“X-010-UBOOT-使用booti命令启动kernel(Bubblegum-96平台)”中有关的描述,patch文件如下:

https://github.com/wowotechX/linux/commit/9a4169ba5187d748a99c11d524bcd1238fd92408

2.3 增加.its文件

参考u-boot的例子,新建一个.its文件,名称为fit_uImage.its,如下:

cd ./build

cp ../u-boot/doc/uImage.FIT/kernel_fdt.its fit_uImage.its

根据x project的实际情况,修改its文件,增加Kernel image和dtb文件两个节点,如下(注意,这个its文件是有问题的,后面调试的时候再改):

https://github.com/wowotechX/build/blob/b71ccd4c7530ec6c5aed7bab0cbd74f48f1fe48e/fit_uImage.its

与此同时,修改编译脚本,加入uImage的编译命令(make uImage),借助u-boot/tools目录下的mkimage工具,编译uImage:

+UIMAGE_ITS_FILE=$(BUILD_DIR)/fit_uImage.its
+UIMAGE_ITB_FILE=$(OUT_DIR)/xprj_uImage.itb
…
+uImage:

  • mkdir -p $(OUT_DIR)
  • $(UBOOT_OUT_DIR)/tools/mkimage -f $(UIMAGE_ITS_FILE) $(UIMAGE_ITB_FILE)

其中fit_uImage.its位于当前build目录;xprj_uImage.itb是将要生成的FIT uImage文件,位于./build/out目录;mkimage工具位于u-boot/tools目录,编译u-boot之后会自定生成。

2.4 编译生成FIT uImage

在build目录执行make kernel,生成kernel image和对应的dtb文件之后,再执行make uImage,即可将它们打包成FIT uImage。然后我们可以使用mkimage查看新生成的uImage的信息,如下:

pengo@ubuntu:~/work/xprj/build$ ./out/u-boot/tools/mkimage -l out/xprj_uImage.itb
FIT description: U-Boot uImage source file for X project
Created: Sat Sep 3 00:05:17 2016
Image 0 (kernel@arm64)
Description: Unify(TODO) ARM64 Linux kernel
Created: Sat Sep 3 00:05:17 2016
Type: Kernel Image
Compression: uncompressed
Data Size: 1229056 Bytes = 1200.25 kB = 1.17 MB
Architecture: ARM
OS: Linux
Load Address: 0x00080000
Entry Point: 0x00080000
Hash algo: crc32
Hash value: ff814746
Hash algo: sha1
Hash value: db4b1b6f40827d88b2e754e795c432cddf41f9bf
Image 1 (fdt@bubblegum96)
Description: Flattened Device Tree blob for Bubblegum-96
Created: Sat Sep 3 00:05:17 2016
Type: Flat Device Tree
Compression: uncompressed
Data Size: 181 Bytes = 0.18 kB = 0.00 MB
Architecture: ARM
Hash algo: crc32
Hash value: 8ee556df
Hash algo: sha1
Hash value: fd590fa50b2f79c18c736cfb410da70feadbfdaa
Default Configuration: ‘conf@bubblegum96’
Configuration 0 (conf@bubblegum96)
Description: Boot Linux kernel with FDT blob
Kernel: kernel@arm64
FDT: fdt@bubblegum96

Image信息和fit_uImage.its中所描述的完全一致,说明如下:

包含两个Image:
Image0,名称为kernel@arm64,类型是“Kernel Image”,Architecture为“ARM”,没有压缩,Load和Entry都是“0x00080000”;
Image1,名称为fdt@bubblegum96,类型是“Flat Device Tree”,Architecture为“ARM”,没有压缩,Load和Entry未指定。

包含一个Configuration,名称为conf@bubblegum96,该Configuration共包括“kernel@arm64”和“fdt@bubblegum96”两个Image。

默认的Configuration就是conf@bubblegum96。

3. FIT uImage的启动

3.1 使用bootm启动FIT uImage

生成“xprj_uImage.itb”之后,我们可以使用DFU工具将它下载到板子的DDR中,并使用bootm命令启动它(有关bootm命令的支持,可参考“X-010-UBOOT-使用booti命令启动kernel(Bubblegum-96平台)”),如下[1]:

执行spl image,初始化DDR

sudo ../tools/dfu/dfu bubblegum 0xe406b200 ../tools/actions/splboot.bin 1

将xprj_uImage.itb下载到DDR的收地址(最后一个参数表示不执行)

sudo ../tools/dfu/dfu bubblegum 0x0 ./out/xprj_uImage.itb 0

#下载并执行u-boot
sudo ../tools/dfu/dfu bubblegum 0x11000000 out/u-boot/u-boot-dtb.bin 1

启动到u-boot命令行执行,以xprj_uImage.itb所在的地址为参数,执行bootm命令,不幸的失败了,错误信息如下:

[xprj]# bootm 0x0

Current stack ends at 0x3ffc14e0 * kernel: cmdline image address = 0x00000000

Loading kernel from FIT Image at 00000000 …

No configuration specified, trying default…
Found default configuration: ‘conf@bubblegum96’
Using ‘conf@bubblegum96’ configuration
Trying ‘kernel@arm64’ kernel subimage
Description: Unify(TODO) ARM64 Linux kernel
Type: Kernel Image
Compression: uncompressed
Data Start: 0x000000ec
Data Size: 1229056 Bytes = 1.2 MiB
Architecture: ARM
OS: Linux
Load Address: 0x00080000
Entry Point: 0x00080000
Hash node: ‘hash@1’
Hash algo: crc32
Hash value: ff814746
Hash len: 4
Hash node: ‘hash@2’
Hash algo: sha1
Hash value: db4b1b6f40827d88b2e754e795c432cddf41f9bf
Hash len: 20
Verifying Hash Integrity … crc32 error!
Bad hash value for ‘hash@1’ hash node in ‘kernel@arm64’ image node
Bad Data Hash
ERROR: can’t get kernel image!
Command failed, result=1

3.2 删掉.its文件中的hash节点

原来hash值错了,好像fit_uImage.its指定了hash节点,但是我们没有特意的为两个Image计算hash值,简单起见,先删掉吧,如下:

kernel@arm64 {
description = “Unify(TODO) ARM64 Linux kernel”;
data = /incbin/("./out/linux/arch/arm64/boot/Image");
type = “kernel”;
arch = “arm”;
os = “linux”;
compression = “none”;
load = <0x00080000>;
entry = <0x00080000>;
};
fdt@bubblegum96 {
description = “Flattened Device Tree blob for Bubblegum-96”;
data = /incbin/("./out/linux/arch/arm64/boot/dts/actions/s900-bubblegum.dtb");
type = “flat_dt”;
arch = “arm”;
compression = “none”;
};

重复3.1的步骤,再来一次,还有问题:

xprj]# bootm 0x0

Current stack ends at 0x3ffc14e0 * kernel: cmdline image address = 0x00000000

Loading kernel from FIT Image at 00000000 …

No configuration specified, trying default…
Found default configuration: ‘conf@bubblegum96’
Using ‘conf@bubblegum96’ configuration
Trying ‘kernel@arm64’ kernel subimage
Description: Unify(TODO) ARM64 Linux kernel
Type: Kernel Image
Compression: uncompressed
Data Start: 0x000000ec
Data Size: 1229056 Bytes = 1.2 MiB
Architecture: ARM
OS: Linux
Load Address: 0x00080000
Entry Point: 0x00080000
Verifying Hash Integrity … OK
Unsupported Architecture
ERROR: can’t get kernel image!
Command failed, result=1

3.3 将架构修改为“arm64”

“Unsupported Architecture”,不支持的架构?在u-boot的source code中,查找一下架构有关的代码,原来要把arch改为arm64,如下:

kernel@arm64 {
description = “Unify(TODO) ARM64 Linux kernel”;
data = /incbin/("./out/linux/arch/arm64/boot/Image");
type = “kernel”;
arch = “arm64”;
os = “linux”;
compression = “none”;
load = <0x00080000>;
entry = <0x00080000>;
};
fdt@bubblegum96 {
description = “Flattened Device Tree blob for Bubblegum-96”;
data = /incbin/("./out/linux/arch/arm64/boot/dts/actions/s900-bubblegum.dtb");
type = “flat_dt”;
arch = “arm64”;
compression = “none”;
};

重复3.1的步骤,还有问题:

[xprj]# bootm 0x0

Current stack ends at 0x3ffc14e0 * kernel: cmdline image address = 0x00000000

Loading kernel from FIT Image at 00000000 …

No configuration specified, trying default…
Found default configuration: ‘conf@bubblegum96’
Using ‘conf@bubblegum96’ configuration
Trying ‘kernel@arm64’ kernel subimage
Description: Unify(TODO) ARM64 Linux kernel
Type: Kernel Image
Compression: uncompressed
Data Start: 0x000000ec
Data Size: 1229056 Bytes = 1.2 MiB
Architecture: AArch64
OS: Linux
Load Address: 0x00080000
Entry Point: 0x00080000
Verifying Hash Integrity … OK
kernel data at 0x000000ec, len = 0x0012c100 (1229056)
* ramdisk: using config ‘conf@bubblegum96’ from image at 0x00000000
* ramdisk: no ‘ramdisk’ in config
Loading Kernel Image … OK
kernel loaded at 0x00080000, end = 0x001ac100
images.os.start = 0x0, images.os.end = 0x12c8bb
images.os.load = 0x80000, load_end = 0x1ac100
ERROR: new format image overwritten - must RESET the board to recover
resetting …
Command failed, result=-1

3.4 重新规划内存的使用

原来在xprj_uImage.itb中,我们指定Kernel image的load地址是0x80000,也就是说,u-boot在boot kernel之前,需要将kernel Image从itb文件中加载到load地址。但是,我们将itb文件放到0x0地址了,发生了覆盖,u-boot不允许,所以我们需要重新规划一下内存的使用,如下:

1)u-boot要在0x11000000(272M的位置)执行,并被relocated到DDR的底端。

2)kernel要在0x0执行,假设给它分配100M(0x6400000)的代码空间

3)那么,我们可以把itb文件上传到0x6400000处:

sudo ../tools/dfu/dfu bubblegum 0xe406b200 ../tools/actions/splboot.bin 1

sudo ../tools/dfu/dfu bubblegum 0x6400000 ./out/xprj_uImage.itb 0

sudo ../tools/dfu/dfu bubblegum 0x11000000 out/u-boot/u-boot-dtb.bin 1

再次执行bootm,成功了:

[xprj]# bootm 0x6400000

Current stack ends at 0x3ffbc4e0 * kernel: cmdline image address = 0x06400000

Loading kernel from FIT Image at 06400000 …

No configuration specified, trying default…
Found default configuration: ‘conf@bubblegum96’
Using ‘conf@bubblegum96’ configuration
Trying ‘kernel@arm64’ kernel subimage
Description: Unify(TODO) ARM64 Linux kernel
Type: Kernel Image
Compression: uncompressed
Data Start: 0x064000ec
Data Size: 1229056 Bytes = 1.2 MiB
Architecture: AArch64
OS: Linux
Load Address: 0x00080000
Entry Point: 0x00080000
Verifying Hash Integrity … OK
kernel data at 0x064000ec, len = 0x0012c100 (1229056)
* ramdisk: using config ‘conf@bubblegum96’ from image at 0x06400000
* ramdisk: no ‘ramdisk’ in config
* fdt: using config ‘conf@bubblegum96’ from image at 0x06400000

Checking for ‘FDT’/‘FDT Image’ at 06400000

Loading fdt from FIT Image at 06400000 …

Using ‘conf@bubblegum96’ configuration
Trying ‘fdt@bubblegum96’ fdt subimage
Description: Flattened Device Tree blob for Bubblegum-96
Type: Flat Device Tree
Compression: uncompressed
Data Start: 0x0652c2b8
Data Size: 181 Bytes = 181 Bytes
Architecture: AArch64
Verifying Hash Integrity … OK
Can’t get ’load’ property from FIT 0x06400000, node: offset 1229352, name fdt@bubblegum96 (FDT_ERR_NOTFOUND)
Booting using the fdt blob at 0x652c2b8
of_flat_tree at 0x0652c2b8 size 0x000000b5
Initial value for argc=3
Final value for argc=3
Loading Kernel Image … OK
kernel loaded at 0x00080000, end = 0x001ac100
using: FDT

initrd_high = 0x3fffffff, copy_to_ram = 1

ramdisk load start = 0x00000000, ramdisk load end = 0x00000000

device tree at 000000000652c2b8 … 000000000652c36c (len=12469 [0x30B5])

Loading Device Tree to 000000003ffb8000, end 000000003ffbb0b4 … OK
Initial value for argc=3
Final value for argc=3

Transferring control to Linux (at address 80000)…

Starting kernel …

从日志上可以看出:u-boot将kernel image加载到了load address(0x00080000)到0x001ac100的位置;由于我们没有指定FDT的加载地址,u-boot将它加载到了将FDT加载到了memory的高地址(0x3ffb8000)。

3.5 点亮LED,确认kernel执行成功

参考“X-010-UBOOT-使用booti命令启动kernel(Bubblegum-96平台)”有关的说明,插入点亮LED的代码,确认OK。

4. 总结和思考

经过上面的实践,我们得出如下的经验:

1)对uImage中某一个Image来说,u-boot会将它重新load到“load address“,因此,需要确保load address和uImage所在的memory区域不能重叠。

2)对于那些可被指定的Image,u-boot会跳转到”entry point“处执行,例如linux kernel。对ARM64而言,”load address“和”entry address“是相同的。

另外,其实FIT uImage离unify kernel的目标还有一段距离,因为当前还有如下的不足:

1)虽然可以指定多个Image,但只要其中的某一个(或者多个)Image不存在,make uImage就无法执行成功。

2)以ARM64为例,假如kernel Image都是同一个,区别是不同版型的load address和entry point不同,要怎么办?.its的语法并没有照顾到这种场景。

3)u-boot将Image文件从.itb文件解除之后,会重新把它们copy到一个新的地址(load address),这等于凭空多了一次memory copy,这些动作本来可以由bootloader在从存储器中copy的时候一次性完成,这岂不是一种浪费?

希望在后续的实践过程中,逐渐解决上述问题。

5. 参考文档

[1] https://github.com/wowotechX/doc/blob/master/README.bubblegum96

原创文章,转发请注明出处。蜗窝科技,www.wowotech.net。

标签:arm64u-bootubootbootmfituImageitsitb

继续讨论

新讨论请用 GitHub 账号在下方发言——评论会保存在本仓库的 Discussions 里,与站点同寿; 再下方的「历史评论」是原站的只读存档。

评论(8 条,只读存档)

以下为原站的历史评论(只读存档);继续讨论请用上方的评论区。

  • ooonebook

    囧,“以后“X Project”和u-boot有关的image格式,将统一使用FIT uImage。”,没早点看到这篇文章,结果做了FIT和传统uImage的兼容。唉。代码传上去了,要不要回退掉? 然后 “虽然可以指定多个Image,但只要其中的某一个(或者多个)Image不存在,make uImage就无法执行成功。” 所以,我暂时就先建了一个目录its,然后搞个fit_uImage_tiny210.its给tiny210用,不然没法搞。 等wowo找到解决办法了再改哈哈。
    • wowo

      @ooonebook:不用回退。我们这个项目主要是学习linux开发的过程,我们只要知道怎么回事就行了,以后有需求的时候,可以快速使用就ok了。 关于FIT的方式,我这里的表述更多的是指ARM64,对于arm,其实代价蛮大的,先不用也行。 后面可以考虑.its文件动态生成的方式~~
      • ooonebook

        @wowo:哈哈,wowo的表述确实没有怎么照顾arm~可惜手头上没有arm64的板子~ 不过验证过了,arm上确实也是可以用,主要就是its的差异。 还有个问题,为什么ARM64没有zImage?Image比zImage大的多了。我用FIT试了zImage格式的kernel,确实可以用,但是解压不是在uboot里面解压的,还是zImage自解压。
      • ooonebook

        @wowo:动态生成的想法确实很赞,不过感觉要很强的脚本编程的功底吧
        • wowo

          @ooonebook:动态生成也不麻烦,就是几个echo而已~~~~
          • ooonebook

            @wowo:哦哦,误解为是在一个its的基础上通过脚本去改,也对,回头试一下直接echo的方法~
  • ooonebook

    hi,wowo 尝试做了一个自动生成its脚本,在tiny210验证过是可以用的。您有空的时候可否帮忙在bubblegum平台上试一下。 测试步骤如下 (1)build同步一下切换到tiny210分支 (2)config.mk里面改一下对应的配置 BOARD_NAME=bubblegum BOARD_ARCH=arm64 UIMAGE_LOADADDR=0x00080000 UIMAGE_ENTRYADDR=0x00080000 DTB_NAME=actions/s900-bubblegum.dtb (3)执行make kernel-img (4)在out/fit目录下会生成fit_uImage.its xprj_uImage.itb。然后帮忙测试一下这个xprj_uImage.itb在您的bubblegum这个板子上是否可用? 十分感谢~
    • wowo

      @ooonebook:好的,多谢分享~~ 我大概看了一下tiny210分支的build的脚本,已经很完善了,等有空了,我要把tiny210的分支,合并到主分支上:-)