3. U-boot的介绍

3.1. U-boot简介

U-boot是从FADSROM、8xxROM、PPCBOOT逐步发展演化而来的。U-boot发展至今,已经可以实现非常多的功能, 在操作系统方面,它不仅支持嵌入式Linux系统的引导,还支持NetBSD,VxWorks, QNX, RTEMS, ARTOS, LynxOS, Android等嵌入式操作系统的引导。在CPU架构方面, U-boot支持PowerPC、MIPS、x86、ARM、NIOS、XScale等诸多常用系列的处理器。

一般来说BootLoader必须提供系统上电时的初始化代码,在系统上电时初始化相关环境后, BootLoader需要引导完整的操作系统,然后将控制器交给操作系统。 简单来说BootLoader是一段小程序,它在系统上电时执行,通过这段小程序可以将硬件 设备进行初始化,如CPU、SDRAM、Flash、串口、网络等,初始化完毕后调用操作系统内核。

3.2. 启动U-boot

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

接下来我们以野火LubanCat板卡为例,使用算能提供的基于U-boot深度定制的版本,介绍U-boot的使用,

将板卡Debug串口与电脑连接,在上电后,U-boot启动kernel之前按下键盘的回车键:进入U-Boot命令行模式。如下所示

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
U-Boot 2021.10 (Aug 05 2024 - 04:00:50 +0000) cvitek_cv181x

DRAM:  510 MiB
gd->relocaddr=0x951c7000. offset=0x14fc7000
set_rtc_register_for_power
MMC:   cv-emmc@4300000: 0, cv-sd@4310000: 1, wifi-sd@4320000: 2
Loading Environment from MMC... mmc0 : finished tuning, code:23
OK
In:    serial
Out:   serial
Err:   serial
Net:
Warning: ethernet@4070000 (eth0) using random MAC address - 32:50:0c:18:80:d8
eth0: ethernet@4070000
Hit any key to stop autoboot:  0
cv181x_c906#
cv181x_c906#

可以看出U-boot打印出了板子的一些基本信息,包括CPU、内存等信息。 还包括了在板卡初始化过程中的一些提示信息,如网口随机生成的mac地址。

3.3. U-boot命令

当不清楚U-boot支持什么命令时, 可输入 help? 可查看U-boot支持的命令列表,如下所示

 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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
?       - alias for 'help'
android_print_hdr- print android image header
atags   - Dump all atags
base    - print or set address offset
bdinfo  - print Board Info structure
bidram_dump- Dump bidram layout
boot    - boot default, i.e., run 'bootcmd'
boot_android- Execute the Android Bootloader flow.
boot_fit- Boot FIT Image from memory or boot/recovery partition
bootavb - Execute the Android avb a/b boot flow.
bootd   - boot default, i.e., run 'bootcmd'
booti   - boot arm64 Linux Image image from memory
bootm   - boot application image from memory
bootp   - boot image via network using BOOTP/TFTP protocol
bootrkp - Boot Linux Image from rockchip image type
bootz   - boot Linux zImage image from memory
cmp     - memory compare
coninfo - print console devices and information
cp      - memory copy
crc32   - checksum calculation
crypto_sum- crypto checksum engine
dhcp    - boot image via network using DHCP/TFTP protocol
dm      - Driver model low level access
download- enter rockusb/bootrom download mode
dtimg   - manipulate dtb/dtbo Android image
dump_irqs- Dump IRQs
dump_resource- dump resource list
echo    - echo args to console
editenv - edit environment variable
env     - environment handling commands
exit    - exit script
ext2load- load binary file from a Ext2 filesystem
ext2ls  - list files in a directory (default /)
ext4load- load binary file from a Ext4 filesystem
ext4ls  - list files in a directory (default /)
ext4size- determine a file's size
false   - do nothing, unsuccessfully
fastboot- use USB or UDP Fastboot protocol
fatinfo - print information about filesystem
fatload - load binary file from a dos filesystem
fatls   - list files in a directory (default /)
fatsize - determine a file's size
fatwrite- write file into a dos filesystem
fdt     - flattened device tree utility commands
fstype  - Look up a filesystem type
go      - start application at address 'addr'
gpt     - GUID Partition Table
help    - print command description/usage
iomem   - Show iomem data by device compatible(high priority) or node name
lcdputs - print string on video framebuffer
load    - load binary file from a filesystem
loop    - infinite loop on address range
ls      - list files in a directory (default /)
md      - memory display
mdio    - MDIO utility commands
mii     - MII utility commands
mm      - memory modify (auto-incrementing address)
mmc     - MMC sub system
mmcinfo - display MMC info
mtd     - MTD utils
mtd_blk - MTD Block device sub-system
mw      - memory write (fill)
nand    - NAND sub-system
nboot   - boot from NAND device
nfs     - boot image via network using NFS protocol
nm      - memory modify (constant address)
part    - disk partition related commands
ping    - send ICMP ECHO_REQUEST to network host
printenv- print environment variables
pxe     - commands to get and boot from pxe files
rbrom   - Perform RESET of the CPU
reboot  - Perform RESET of the CPU, alias of 'reset'
reset   - Perform RESET of the CPU
rkimgtest- Test if storage media have rockchip image
rockchip_show_bmp- load and display bmp from resource partition
rockchip_show_logo- load and display log from resource partition
rockusb - Use the rockusb Protocol
run     - run commands in an environment variable
save    - save file to a filesystem
saveenv - save environment variables to persistent storage
setcurs - set cursor position within screen
setenv  - set environment variables
showvar - print local hushshell variables
size    - determine a file's size
source  - run script from memory
sysboot - command to get and boot from syslinux files
sysmem_dump- Dump sysmem layout
sysmem_search- Search a available sysmem region
test    - minimal test like /bin/sh
tftp    - download image via network using TFTP protocol
tftpbootm- tftpbootm aosp/uImage/FIT image via network using TFTP protocol
tftpflash- flash image via network using TFTP protocol
tftpput - TFTP put command, for uploading files to a server
true    - do nothing, successfully
ums     - Use the UMS [USB Mass Storage]
usb     - USB sub-system
usbboot - boot from USB device
version - print monitor, compiler and linker version

可看到U-boot支持很多的命令,功能十分强大,与linux类似,在执行某条U-boot命令时, 可使用 tab 自动补全命令,在没有命令名冲突的情况下可以使用命令的前几个字母作为命令的输入, 例如想要执行 reset 命令,输入 resre 即可。

当需要具体使用哪个命令时,可使用 “help 命令”“? 命令” 的方式查看具体命令的使用说明。以 “help printenv” 为例,

1
2
3
4
5
6
7
8
=> help printenv
printenv - print environment variables

Usage:
printenv [-a]
    - print [all] values of all environment variables
printenv name ...
    - print value of environment variable 'name'

可以看到printenv命令的说明以及使用方法。

关于U-boot命令的使用可参考U-boot官方链接: http://www.denx.de/wiki/DULG/Manual 5.9. uboot Command Line Interface 部分。

3.3.1. U-boot常见命令

U-boot命令众多,下面介绍常用的U-boot命令,详细的U-boot命令使用方式请使用 help [命令] 查看。

常见命令

命令

说明

举例

help

列出当前U-boot所有支持的命令

help [命令]

查看指定命令的帮助

help printenv

reset

重启U-boot

printenv

打印所有环境参数的值

printenv [参数名]

查看指定的环境参数值

printenv bootdelay

setenv

设置/修改/删除环境参数的值

setenv bootdelay 3

saveenv

保存环境参数

ping

检测网络是否连通

ping 192.168.0.1

md

查看内存地址上的值

md.b 0x81800000 10

以字节查看0x81800000后0x10个数据

mw

用于修改内存地址上的值

mw.b 0x81800000 ff 10

以字节修改0x81800000后0x10个数据为ff

echo

打印信息,与linux下的echo类似

run

在执行某条环境参数命令

run bootcmd,执行bootcmd

bootz

在内存中引导内核启动

ls

查看文件系统中目录下的文件

load

从文件系统中加载二进制文件到内存

以上为用户较为常用使用的部分命令,具体的使用方式可使用 help [命令] 查看。

3.3.2. mmc命令

mmc命令能够对如sd卡以及emmc类的存储介质进行操作,以下进行简单说明, 对于mmc命令不熟悉可使用 help mmc 查看相关命令的帮助,常用功能如下所示

mmc命令功能

命令

说明

mmc list

查看板子上mmc设备

mmc dev

查看/切换当前默认mmc设备

mmc info

查看当前mmc设备信息

mmc part

查看当前mmc设备分区

mmc read

读取当前mmc设备数据

mmc write

写入当前mmc设备数据

mmc erase

擦除当前mmc设备数据

3.3.2.1. 查看mmc设备

使用 mmc list 查看板卡相关设备,示例板卡板载emmc,可看到打印信息如下。

1
2
3
cv-emmc@4300000: 0 (eMMC)
cv-sd@4310000: 1
wifi-sd@4320000: 2

使用 mmc dev index 切换当前mmc设备,index为设备号,根据**mmc list**的结果,可知eMMC的设备号为0

1
2
3
4
=> mmc dev 0
mmc0 : finished tuning, code:23
switch to partitions #0, OK
mmc0(part 0) is current device

使用 mmc info 查看当前mmc设备的信息。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
=> mmc info
Device: cv-emmc@4300000
Manufacturer ID: 15
OEM: 100
Name: 8GTF4
Bus Speed: 200000000
Mode: HS200 (200MHz)
Rd Block Len: 512
MMC version 5.1
High Capacity: Yes
Capacity: 7.3 GiB
Bus Width: 4-bit
Erase Group Size: 512 KiB
HC WP Group Size: 8 MiB
User Capacity: 7.3 GiB WRREL
Boot Capacity: 4 MiB ENH
RPMB Capacity: 512 KiB ENH
Boot area 0 is not write protected
Boot area 1 is not write protected

3.3.2.2. 查看分区信息

使用 mmc part 列出当前mmc设备分区

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#如果是emmc
=> mmc part
## Unknown partition table type 0

#如果是SD
=> mmc part
mmc1 : finished tuning, code:64

Partition Map for MMC device 0  --   Partition Type: DOS

Part    Start Sector    Num Sectors     UUID            Type
  1     1               32768           c4f4da32-01     0c Boot
  2     32769           1521264         c4f4da32-02     83

emmc的分区无法识别,而sd的分区可以正常识别,原因在于emmc分区使用cmdline partition方式管理分区,而sd通过gpt分区表。

3.3.3. 文件系统操作命令

U-boot能够对ext2/3/4以及fat文件系统设备进行访问, 可使用fstype命令判断存储介质分区使用的是什么类型的文件系统。 以mmc介质为例,判断后两个分区的文件系统类型

1
2
3
4
5
6
7
8
9
#如果是emmc
=> fstype mmc 0:6
** No partition table - mmc 0 **
Couldn't find partition mmc 0:6


#如果是sd
=> fstype mmc 0:2
ext4

emmc的第6个分区是文件系统,但是cmdline方式无法识别,而sd第2个分区是文件系统,gpt分区表方式可以识别。

3.3.3.1. ext4格式文件系统

由于emmc分区无法识别,以下使用sd进行测试。

ext4文件系统的命令使用方式和FAT使用方式相似,仅命令名不同, U-boot提供的ext文件系统命令如下

ext4格式文件系统命令

命令

说明

ext4ls

查看存储设备的ext4分区里的内容

ext4load

从ext4分区里读出文件到指定的内存地址

ext4write

把内存上的数据存储到ext4分区的一个文件里

3.3.3.1.1. ext4文件系统操作

下面以将/etc/apt/sources.list的内容读取到内存实例,简单说明U-boot对ext4文件系统操作。

1.查看/etc/apt目录中的文件内容,

1
2
3
4
5
6
7
8
9
=> ext4ls mmc 0:2 /etc/apt/
<DIR>       4096 .
<DIR>       4096 ..
            464 sources.list
<DIR>       4096 apt.conf.d
<DIR>       4096 auth.conf.d
<DIR>       4096 preferences.d
<DIR>       4096 sources.list.d
<DIR>       4096 trusted.gpg.d

2.将/etc/apt/sources.list 文件读取到内存地址0x8000 0000处

1
2
=> ext4load mmc 0:2  0x81800000  /etc/apt/sources.list
464 bytes read in 701 ms (0 Bytes/s)

3.查看内存0x8000 0000的部分数据内存

1
2
3
4
5
6
7
8
9
=> md.b 0x81800000 0x80
81800000: 64 65 62 20 68 74 74 70 3a 2f 2f 6d 69 72 72 6f  deb http://mirro
81800010: 72 73 2e 75 73 74 63 2e 65 64 75 2e 63 6e 2f 75  rs.ustc.edu.cn/u
81800020: 62 75 6e 74 75 2d 70 6f 72 74 73 2f 20 6a 61 6d  buntu-ports/ jam
81800030: 6d 79 20 6d 61 69 6e 20 6d 75 6c 74 69 76 65 72  my main multiver
81800040: 73 65 20 72 65 73 74 72 69 63 74 65 64 20 75 6e  se restricted un
81800050: 69 76 65 72 73 65 0a 64 65 62 20 68 74 74 70 3a  iverse.deb http:
81800060: 2f 2f 6d 69 72 72 6f 72 73 2e 75 73 74 63 2e 65  //mirrors.ustc.e
81800070: 64 75 2e 63 6e 2f 75 62 75 6e 74 75 2d 70 6f 72  du.cn/ubuntu-por

3.4. U-boot启动内核过程

emmc启动和sd启动有区别,以下分开讲解。

3.4.1. eMMC启动分析

bootcmd与bootargs可以说是U-boot最重要的两个环境参数, U-boot执行完毕之后,如果没有按下回车,则会自动执行bootcmd命环境参数里的内容, 而bootargs则是传递给内核的启动参数。

使用 printenv bootcmd 可查看bootcmd的内容。

1
2
=> printenv bootcmd
bootcmd=cvi_update || run norboot || run nandboot ||run emmcboot

查看cvi_update的环境变量内容:

1
2
=> printenv cvi_update
## Error: "cvi_update" not defined

cvi_update没有定义,只有在SD升级时才会有定义,进行sd刷eMMC。

同样,存储介质不是nor flash和nand因此两者环境变量也没有定义,查看emmcboot的环境变量内容:

1
2
3
4
=> printenv emmcboot
emmcboot=setenv bootargs ${reserved_mem} ${root} ${mtdparts} console=$consoledev,$baudrate $othbootargs;
mmc dev 0 ;mmc read ${uImage_addr} ${BOOT_PART_OFFSET} ${BOOT_PART_SIZE} ;
bootm ${uImage_addr}#config-sg2000_lubancat_riscv_buildroot_emmc;

以上参数说明如下:

  • setenv bootargs …:这部分命令设置了启动参数(bootargs),其中包括 ${reserved_mem}、${root}、${mtdparts} 等变量,这些变量通常包含了系统启动所需的内存分配、根文件系统位置、MTD分区信息、控制台设备和波特率等。

  • mmc dev 0:这个命令选择设备0作为当前MMC设备。

  • mmc read ${uImage_addr} ${BOOT_PART_OFFSET} ${BOOT_PART_SIZE};:这个命令从MMC设备的特定偏移量${BOOT_PART_OFFSET}开始,读取大小为${BOOT_PART_SIZE}的数据,并将其存储到地址${uImage_addr}。

  • bootm ${uImage_addr}#config-sg2000_lubancat_riscv_buildroot_emmc;:使用 bootm 命令启动从 ${uImage_addr} 地址加载的内核映像 (uImage)。

以上作用是从eMMC引导系统,首先设置启动参数,然后选择eMMC设备,加载eMMC特定内容到内存,最后根据加载启动内核。

3.4.2. 手动引导启动(eMMC)

通过以上分析可知,设置bootargs,加载eMMC特定到内存,然后通过bootm命令就可以启动系统,因此,可以在uboot命令行执行以下命令,手动引导启动。

1
2
3
4
setenv bootargs ${reserved_mem} ${root} ${mtdparts} console=$consoledev,$baudrate $othbootargs
mmc dev 0
mmc read ${uImage_addr} ${BOOT_PART_OFFSET} ${BOOT_PART_SIZE}
bootm ${uImage_addr}#config-sg2000_lubancat_riscv_buildroot_emmc

3.4.3. SD启动分析

bootcmd与bootargs可以说是U-boot最重要的两个环境参数, U-boot执行完毕之后,如果没有按下回车,则会自动执行bootcmd命环境参数里的内容, 而bootargs则是传递给内核的启动参数。

使用 printenv bootcmd 可查看bootcmd的内容。

1
2
=> printenv bootcmd
bootcmd=run loadenvcmd ; run sdboot || run sdbootauto

查看loadenvcmd的环境变量内容:

1
2
=> printenv loadenvcmd
loadenvcmd=mmc info;load mmc 0:1 ${uImage_addr} uEnv.txt; if test $? -eq 0; then env import ${uImage_addr} - ; fi;

以上是加载uEnv.txt内容到指定内存地址的,然后读取指定地址内容到系统中的环境变量集合中,可用于后续的系统启动和运行所需的配置参数和环境设置(截至作者写本章节时暂未使用uEnv.txt机制)。

1
2
3
=> printenv sdboot
sdboot=setenv bootargs ${reserved_mem} ${root} ${mtdparts} console=$consoledev,$baudrate $othbootargs;echo Boot from SD dev ${sddev} ...;
mmc dev ${sddev} && fatload mmc ${sddev} ${uImage_addr} boot.sd;if test $? -eq 0; then bootm ${uImage_addr}#config-sg2000_lubancat_riscv_ubuntu_sd;fi;

以上参数说明如下:

  • setenv bootargs …:这部分命令设置了启动参数(bootargs),其中包括 ${reserved_mem}、${root}、${mtdparts} 等变量,这些变量通常包含了系统启动所需的内存分配、根文件系统位置、MTD分区信息、控制台设备和波特率等。

  • mmc dev ${sddev}:这个命令选择SD卡设备 ${sddev} 作为当前MMC设备。

  • fatload mmc ${sddev} ${uImage_addr} boot.sd;:这个命令从SD卡的FAT文件系统中加载 boot.sd 文件到内存地址 ${uImage_addr}。

  • if test $? -eq 0;:这部分是一个条件语句,检查上一个命令的退出状态码。$? 是上一个命令的退出状态码,-eq 0 表示成功执行。

  • then bootm ${uImage_addr}#config-sg2000_lubancat_riscv_ubuntu_sd;:如果上一个命令成功执行,则使用 bootm 命令启动从 ${uImage_addr} 地址加载的内核映像 (uImage)。

以上作用是从SD卡引导系统,首先设置启动参数,然后选择SD卡设备,加载boot.sd文件到内存,最后根据加载成功与否决定是否启动内核映像。

3.4.4. 手动引导启动(SD)

通过以上分析可知,设置bootargs,加载boot.sd到${uImage_addr},然后通过bootm命令就可以启动系统,因此,可以在uboot命令行执行以下命令,手动引导启动。

1
2
3
setenv bootargs ${reserved_mem} ${root} ${mtdparts} console=$consoledev,$baudrate $othbootargs
fatload mmc ${sddev} ${uImage_addr} boot.sd
bootm ${uImage_addr}#config-sg2000_lubancat_riscv_ubuntu_sd

3.5. U-boot环境参数介绍

U-boot中环境参数为我们提供一种不修改U-boot源码的情况下, 能够修改kernel启动倒计时、ip地址、以及向内核传递不同的参数等。

在板子上使用 printenv 可查看板子上所有的环境参数, 使用 setenv 添加/修改/删除环境参数,具体说明如下所示

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#设置新的环境参数名为abc,值为100
=> setenv abc 100
=> echo $abc
= 100

#将值修改为200
=> setenv abc 200
=> echo $abc
200

#删除abc环境参数
=> setenv abc
=> echo $abc

默认情况下使用setenv命令修改环境参数重启后就会消失, 若想要掉电保存需要执行 saveenv 将环境参数保存到存储介质。

警告

不建议在uboot中使用此操作,会覆盖默认的环境变量。

如果修改错误可以恢复默认环境变量:

1
2
3
env default -f -a
saveenv
reset

U-boot上有一些官方规定的环境变量,这些环境变量在U-boot有着特殊的作用, 可通过以下链接查看: https://www.denx.de/wiki/view/DULG/UBootEnvVariables