U-boot启动流程[三]

世界杯365软件 🗓 2026-02-23 06:17:23 ✍ admin 👁 6295 👍 489
U-boot启动流程[三]

aarch64-linux-gnu-objcopy -O binary -R .note -R .note.gnu.build-id -R .comment -S vmlinux Image

该命令会执行以下操作:

a –O binary:将输出二进制镜像,即会去掉elf头

b –R .note:-R选项表示去掉镜像中指定的section,如这里会去掉.note、.note.gnu.build-id和.comment段

c –S:去掉符号表和重定位信息,它与-R选项的功能类似,都是为了减小镜像的size

因此,执行该命令后生成的Image镜像是去掉elf头,去掉.note等无用的section,以及strip过的二进制镜像。它可以被uboot的booti命令直接启动。但若要使用bootm启动,则还需要将其进一步封装为后面介绍的uimage或bootimg镜像

(3 – 7)以Image为源文件,调用不同的压缩算法,对镜像进行压缩。若调用gzip命令,则可将其压缩为我们熟悉的zImage镜像。与Image一样,压缩后的镜像也是可以被booti直接启动,且经过封装以后可以被bootm启动的

1.2 设备树

设备树是设备树dts源文件经过编译后生成的,其目标文件为二进制格式的dtb文件。其示例编译命令如下:

dtc -I dts -O dtb -o example.dtb example.dts

(1) –I:指定输入文件格式

(2)–O:指定输出文件格式

(3)–o:指定输出文件名

设备树还支持dtb overlay机制,即可以向设备提供一个基础dtb和多个dtbo镜像,并在启动前将它们merge为最终的dtb。下面用一个例子来说明:

(1)基础dts文件base.dts内容如下:

/dts-v1/;

/ {

foo: foonode {

foo-property;

};

};

(2)dtbo源文件overlay.dts内容如下:

/dts-v1/;

/plugin/;

/ {

fragment@1 {

target = <&foo>;

__overlay__ {

overlay-1-property;

bar: barnode {

bar-property;

};

};

};

};

(3)分别使用以下命令编译dtb和dtbo

dtc -@ -I dts -O dtb -o base.dtb base.dts

dtc -@ -I dts -O dtb -o overlay.dtbo overlay.dts

(4)将dtbo merge到base dtb上

a 通过fit镜像包含和定义一个overlay,这种情况uboot会自动解析fit参数并执行merge操作

b 手动加载和apply overlay

(5)手动merge流程

a 设置base dtb和dtbo的地址

setenv fdtaddr 0x87f00000

setenv fdtovaddr 0x87fc0000

b 加载base dtb和dtbo

load ${devtype} ${bootpart} ${fdtaddr} ${bootdir}/base.dtb

load ${devtype} ${bootpart} ${fdtovaddr} ${bootdir}/overlay.dtbo

c 将base dtb设置为工作dtb

fdtaddr $fdtaddr

d 增大dtb的size,以使其可以容纳所有overlay

fdt resize 8192

e apply dtb overlay

fdt apply $fdtovadd

1.3 根文件系统

linux可以支持多种形式的根文件系统,如initrd、initramfs、基于磁盘的根文件系统等。站在启动镜像的角度看其实它们都是制作好的文件系统镜像,内核可以从特定的位置获取并挂载它们。以下是它们在启动时的基本特性:

(1)initrd

它是一种内存文件系统,需要由bootloader预先加载到内存中,并将其内存地址传递给内核。如uboot将initrd加载到地址$initrd_addr处,则bootm参数如下:

bootm $kernel_addr $initrd_addr $fdt_addr

(2)initramfs

initramfs也是一种内存文件系统,但与initrd不同,它是与内核打包在一起的。因此不需要通过额外的参数

(3)磁盘rootfs

磁盘根文件系统会被刷写到flash、mmc或disk的分区中,在内核启动时可在bootargs添加下面格式的参数,以指定根文件系统的位置

root=/dev/xxx

因此,以上这些rootfs只有initrd是需要uboot独立加载的,故只有当rootfs为initrd时,uboot镜像打包流程才需要在镜像打包时为其单独考虑

2 Uboot支持的镜像格式2.1 Legacy uimage格式

uboot最先支持legacy uimage格式的镜像,它是在内核镜像基础上添加一个64字节header生成的。该header信息用于指定镜像的一些属性,如内核的类型、压缩算法类型、加载地址、运行地址、crc完整性校验值等。其格式如下:

typedef struct image_header {

uint32_t ih_magic; /* Image Header Magic Number */

uint32_t ih_hcrc; /* Image Header CRC Checksum */

uint32_t ih_time; /* Image Creation Timestamp */

uint32_t ih_size; /* Image Data Size */

uint32_t ih_load; /* Data Load Address */

uint32_t ih_ep; /* Entry Point Address */

uint32_t ih_dcrc; /* Image Data CRC Checksum */

uint8_t ih_os; /* Operating System */

uint8_t ih_arch; /* CPU architecture */

uint8_t ih_type; /* Image Type */

uint8_t ih_comp; /* Compression Type */

uint8_t ih_name[IH_NMLEN]; /* Image Name */

} image_header_t;

uboot的bootm命令会解析镜像头中的信息,并根据这些信息执行镜像校验、解压和启动等流程。以下是创建uImage的命令示例:

mkimage -A arm64 -O linux -C none -T kernel -a 0x80008000 -e 0x80008040 -n Linux_Image -d zImage uImage

但是它也有着一些缺点,如:

(1)加载流程比较繁琐,如需要分别加载内核、initrd和dtb

(2)启动参数较多,需要分别制定内核、initrd和dtb的地址

(3)在支持secure boot的系统中对secure boot的支持不足

为此,uboot又定义了一种新的镜像格式fit uimage,用于解决上述问

2.2 Fit uimage格式

Fit uimage是使用devicetree语法来定义uimage镜像描述信息以及启动时的各种属性,这些信息被写入一个后缀名为its的源文件中。以下是一个its文件的示例

/dts-v1/;

/ {

description = "Various kernels, ramdisks and FDT blobs";

#address-cells = <1>;

images {

kernel-1 {

description = "vanilla-2.6.23"; (1)

data = /incbin/("./vmlinux.bin.gz"); (2)

type = "kernel"; (3)

arch = "ppc"; (4)

os = "linux"; (5)

compression = "gzip"; (6)

load = <00000000>; (7)

entry = <00000000>; (8)

hash-1 {

algo = "md5"; (9)

};

hash-2 {

algo = "sha1";

};

};

kernel-2 {

description = "2.6.23-denx";

data = /incbin/("./2.6.23-denx.bin.gz");

type = "kernel";

arch = "ppc";

os = "linux";

compression = "gzip";

load = <00000000>;

entry = <00000000>;

hash-1 {

algo = "sha1";

};

};

kernel-3 {

description = "2.4.25-denx";

data = /incbin/("./2.4.25-denx.bin.gz");

type = "kernel";

arch = "ppc";

os = "linux";

compression = "gzip";

load = <00000000>;

entry = <00000000>;

hash-1 {

algo = "md5";

};

};

ramdisk-1 {

description = "eldk-4.2-ramdisk";

data = /incbin/("./eldk-4.2-ramdisk");

type = "ramdisk";

arch = "ppc";

os = "linux";

compression = "gzip";

load = <00000000>;

entry = <00000000>;

hash-1 {

algo = "sha1";

};

};

ramdisk-2 {

description = "eldk-3.1-ramdisk";

data = /incbin/("./eldk-3.1-ramdisk");

type = "ramdisk";

arch = "ppc";

os = "linux";

compression = "gzip";

load = <00000000>;

entry = <00000000>;

hash-1 {

algo = "crc32";

};

};

fdt-1 {

description = "tqm5200-fdt";

data = /incbin/("./tqm5200.dtb");

type = "flat_dt";

arch = "ppc";

compression = "none";

hash-1 {

algo = "crc32";

};

};

fdt-2 {

description = "tqm5200s-fdt";

data = /incbin/("./tqm5200s.dtb");

type = "flat_dt";

arch = "ppc";

compression = "none";

load = <00700000>;

hash-1 {

algo = "sha1";

};

};

};

configurations {

default = "config-1";

config-1 {

description = "tqm5200 vanilla-2.6.23 configuration";

kernel = "kernel-1";

ramdisk = "ramdisk-1";

fdt = "fdt-1";

};

config-2 {

description = "tqm5200s denx-2.6.23 configuration";

kernel = "kernel-2";

ramdisk = "ramdisk-1";

fdt = "fdt-2";

};

config-3 {

description = "tqm5200s denx-2.4.25 configuration";

kernel = "kernel-3";

ramdisk = "ramdisk-2";

};

};

};

它包含images和configurations两个顶级节点,images指定该its文件会包含哪些镜像,以及这些镜像的属性信息。configurations用于定义一系列镜像组合信息,如在本例中包含了config-1、config-2和config-3三种镜像组合方式。Its使用default属性指定启动时默认采用的配置信息,若启动时不希望使用默认配置,则可通过在启动参数中动态指定配置序号。下面我们通过kernel-1节点看下image属性的含义:

1. 镜像的描述信息

2. 镜像文件的路径

3. 镜像类型,如kernel、ramdisk或fdt

4. 支持的架构

5. 支持的操作系统

6. 其使用的压缩算法

7. 加载地址

8. 运行地址

9. 完整性校验使用的hash算法

configurations的属性比较简单,就是指定某个配置下使用哪一个kernel、dtb和ramdisk镜像。Fit image除了支持完整性校验外,还可支持hash算法 + 非对称算法的secure boot方案,如以下例子:

kernel {

data = /incbin/("test-kernel.bin");

type = "kernel_noload";

arch = "sandbox";

os = "linux";

compression = "none";

load = <0x4>;

entry = <0x8>;

kernel-version = <1>;

signature {

algo = "sha1,rsa2048"; (1)

key-name-hint = "dev"; (2)

};

};

(1)指定sha1为secure boot签名使用的hash算法,rsa2048为其使用的签名算法(2)可能使用的验签密钥名

与设备树类似,its文件可以通过mkimage和dtc编译生成itb文件。镜像生成方式如下:

mkimage -f xxx.its xxx.itb

xxx.itb文件可以直接传给uboot,并通过bootm命令执行,如xxx.itb被加载到0x80000000,则其命令如下:

bootm 0x80000000

若需要选择非默认的镜像配置,则可通过指定配置序号实现,例如:

bootm 0x80000000#config@2

2.3 Boot image格式

boot image是android定义的启动镜像格式,到目前为止一共定义了三个版本(v0 – v2),其中v0版本包含andr_img_hdr、kernel、ramdisk和second stage,v1版本增加了recovery dtbo/acpio,v2版本又增加了dtb。在这些镜像中second stage是可选的,而recovery dtbo只有在使用recovery分区的非AB系统中才需要,且它们都需要page对齐(通常为2k)。以下是boot image镜像的基本格式:

andr_img_hdr镜像头用于描述这些镜像的信息,如其长度、加载地址等,其定义如下:

struct andr_img_hdr {

/* Must be ANDR_BOOT_MAGIC. */

char magic[ANDR_BOOT_MAGIC_SIZE];

u32 kernel_size; /* size in bytes */

u32 kernel_addr; /* physical load addr */

u32 ramdisk_size; /* size in bytes */

u32 ramdisk_addr; /* physical load addr */

u32 second_size; /* size in bytes */

u32 second_addr; /* physical load addr */

u32 tags_addr; /* physical addr for kernel tags */

u32 page_size; /* flash page size we assume */

u32 header_version;

u32 os_version;

char name[ANDR_BOOT_NAME_SIZE]; /* asciiz product name */

char cmdline[ANDR_BOOT_ARGS_SIZE];

u32 id[8]; /* timestamp / checksum / sha1 / etc */

char extra_cmdline[ANDR_BOOT_EXTRA_ARGS_SIZE];

u32 recovery_dtbo_size; /* size in bytes for recovery DTBO/ACPIO image */

u64 recovery_dtbo_offset; /* offset to recovery dtbo/acpio in boot image */

u32 header_size;

u32 dtb_size; /* size in bytes for DTB image */

u64 dtb_addr; /* physical load address for DTB image */

} __attribute__((packed));

可以使用mkbootimg.py脚本制作boot image镜像,该脚本参数比较简单,就是指定与镜像头中定义的相关参数。例如:

mkbootimg.py \

--base aaa \

--kernel kernel/arch/arm64/boot/Image.gz \

--kernel_offset bbb \

--second kernel/arch/arm64/boot/ccc.dtb \

--second_offset ddd \

--board test_board \

-o boot.img

3 bootm流程

bootm是uboot用于启动操作系统的命令,它的主要流程包括根据镜像头获取镜像信息,解压镜像,以及启动操作系统。以下为其主要执行流程:

上面的流程都比较直观,有兴趣可以对照代码自行分析一下

相关推荐

鹿角有什么功效和作用 【必看】鹿角的食用方法及禁忌
365账户受到限制怎么办

鹿角有什么功效和作用 【必看】鹿角的食用方法及禁忌

🗓 08-28 👁 1559
给宝宝起名字鑫啥意思(鑫磊的名字含义是什么)
世界杯365软件

给宝宝起名字鑫啥意思(鑫磊的名字含义是什么)

🗓 12-02 👁 4794