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

作者:wowo 发布于:2016-9-9 22:18 分类:X Project

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

标签: arm64 u-boot uboot bootm fit uImage its itb

评论:

ooonebook
2016-09-15 19:05
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
2016-09-16 21:36
@ooonebook:好的,多谢分享~~
我大概看了一下tiny210分支的build的脚本,已经很完善了,等有空了,我要把tiny210的分支,合并到主分支上:-)
ooonebook
2016-09-10 17:29
囧,“以后“X Project”和u-boot有关的image格式,将统一使用FIT uImage。”,没早点看到这篇文章,结果做了FIT和传统uImage的兼容。唉。代码传上去了,要不要回退掉?
然后
“虽然可以指定多个Image,但只要其中的某一个(或者多个)Image不存在,make uImage就无法执行成功。”
所以,我暂时就先建了一个目录its,然后搞个fit_uImage_tiny210.its给tiny210用,不然没法搞。
等wowo找到解决办法了再改哈哈。
wowo
2016-09-10 21:10
@ooonebook:不用回退。我们这个项目主要是学习linux开发的过程,我们只要知道怎么回事就行了,以后有需求的时候,可以快速使用就ok了。
关于FIT的方式,我这里的表述更多的是指ARM64,对于arm,其实代价蛮大的,先不用也行。
后面可以考虑.its文件动态生成的方式~~
ooonebook
2016-09-10 22:25
@wowo:哈哈,wowo的表述确实没有怎么照顾arm~可惜手头上没有arm64的板子~
不过验证过了,arm上确实也是可以用,主要就是its的差异。
还有个问题,为什么ARM64没有zImage?Image比zImage大的多了。我用FIT试了zImage格式的kernel,确实可以用,但是解压不是在uboot里面解压的,还是zImage自解压。
ooonebook
2016-09-10 22:25
@wowo:动态生成的想法确实很赞,不过感觉要很强的脚本编程的功底吧
wowo
2016-09-11 21:02
@ooonebook:动态生成也不麻烦,就是几个echo而已~~~~
ooonebook
2016-09-12 10:54
@wowo:哦哦,误解为是在一个its的基础上通过脚本去改,也对,回头试一下直接echo的方法~

发表评论:

Copyright @ 2013-2015 蜗窝科技 All rights reserved. Powered by emlog