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

接下来我们以野火LubanCat板卡为例,使用RockChip提供的基于U-boot v2017深度定制的版本(称为next-dev),介绍U-boot的使用,

将板卡Debug串口与电脑连接,在上电后,U-boot启动kernel之前按下键盘的ctrl+c键:进入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
U-Boot 2017.09-gdde42ec6a2-211221 #jiawen (Jun 01 2022 - 14:07:06 +0800)

Model: Rockchip RK3568 Evaluation Board
PreSerial: 2, raw, 0xfe660000
DRAM:  4 GiB
Sysmem: init
Relocation Offset: ed34b000
Relocation fdt: eb9f87e8 - eb9fecd0
CR: M/C/I
Using default environment

Hotkey: ctrl+c
dwmmc@fe2b0000: 1, dwmmc@fe2c0000: 2, sdhci@fe310000: 0
Bootdev(atags): mmc 0
MMC0: HS200, 200Mhz
PartType: EFI
DM: v1
boot mode: None
FIT: no signed, no conf required
DTB: rk-kernel.dtb
HASH(c): OK
I2c0 speed: 100000Hz
vsel-gpios- not found! Error: -2
vdd_cpu 1025000 uV
PMIC:  RK8090 (on=0x40, off=0x00)
vdd_logic init 900000 uV
vdd_gpu init 900000 uV
vdd_npu init 900000 uV
io-domain: OK
Could not find baseparameter partition
Model: EmbedFire LubanCat2
Rockchip UBOOT DRM driver version: v1.0.1
VOP have 2 active VP
vp0 have layer nr:3[0 2 4 ], primary plane: 4
vp1 have layer nr:3[1 3 5 ], primary plane: 5
vp2 have layer nr:0[], primary plane: 0
Using display timing dts
dsi@fe060000:  detailed mode clock 59603 kHz, flags[8000000a]
    H: 0720 0730 0736 0756
    V: 1280 1290 1294 1314
bus_format: 100e
VOP update mode to: 720x1280p0, type: MIPI0 for VP0
VOP VP0 enable Smart0[654x270->654x270@33x505] fmt[2] addr[0xedf04000]
final DSI-Link bandwidth: 396 Mbps x 4
xfer: num: 2, addr: 0x50
xfer: num: 2, addr: 0x50
Monitor has basic audio support
Could not find baseparameter partition
mode:1920x1080
hdmi@fe0a0000:  detailed mode clock 148500 kHz, flags[5]
    H: 1920 2008 2052 2200
    V: 1080 1084 1089 1125
bus_format: 2025
VOP update mode to: 1920x1080p0, type: HDMI0 for VP1
VOP VP1 enable Smart1[654x270->654x270@633x405] fmt[2] addr[0xedf04000]
CEA mode used vic=16
final pixclk = 148500000 tmdsclk = 148500000
PHY powered down in 0 iterations
PHY PLL locked 1 iterations
PHY powered down in 1 iterations
PHY PLL locked 1 iterations
sink has audio support
hdmi_set_clk_regenerator: fs=48000Hz ftdms=148.500MHz N=6144 cts=148500
CLK: (sync kernel. arm: enter 816000 KHz, init 816000 KHz, kernel 0N/A)
    apll 1416000 KHz
    dpll 780000 KHz
    gpll 1188000 KHz
    cpll 1000000 KHz
    npll 1200000 KHz
    vpll 742000 KHz
    hpll 59000 KHz
    ppll 200000 KHz
    armclk 1416000 KHz
    aclk_bus 150000 KHz
    pclk_bus 100000 KHz
    aclk_top_high 500000 KHz
    aclk_top_low 400000 KHz
    hclk_top 150000 KHz
    pclk_top 100000 KHz
    aclk_perimid 300000 KHz
    hclk_perimid 150000 KHz
    pclk_pmu 100000 KHz
Net:   eth0: ethernet@fe2a0000, eth1: ethernet@fe010000
Hit key to stop autoboot('CTRL+C'):  0
=> <INTERRUPT>

可以看出U-boot打印出了板子的一些基本信息,包括CPU、内存等信息。 还包括了在板卡初始化过程中的一些提示信息,如屏幕显示和时钟频率等。

3.3. U-boot快捷键

我们除了使用快捷按键进入U-Boot命令行模式,next-dev还提供了其他的串口组合快捷键,常用的如下

  • ctrl+c:进入 U-Boot 命令行模式;

  • ctrl+d:进入 loader 烧写模式;

  • ctrl+b:进入 maskrom 烧写模式;

3.4. 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 即可。

错误

默认不支持使用saveenv命令保存环境变量,因为可能会覆盖原有的默认env配置导致系统无法启动,如果要修改环境变量,请修改uboot源码。

当需要具体使用哪个命令时,可使用 “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.4.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 0x80000000 10

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

mw

用于修改内存地址上的值

mw.b 0x80000000 ff 10

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

echo

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

run

在执行某条环境参数命令

run bootcmd,执行bootcmd

bootz

在内存中引导内核启动

ls

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

load

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

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

3.4.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.4.2.1. 查看mmc设备

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

1
2
3
dwmmc@fe2b0000: 1
dwmmc@fe2c0000: 2
sdhci@fe310000: 0 (eMMC)

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

1
2
3
=> mmc dev 0
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
=> mmc info
Device: sdhci@fe310000
Manufacturer ID: e9
OEM: 10f
Name: K93SK
Timing Interface: HS200
Tran Speed: 200000000
Rd Block Len: 512
MMC version 5.1
High Capacity: Yes
Capacity: 7.3 GiB
Bus Width: 8-bit
Erase Group Size: 512 KiB
HC WP Group Size: 8 MiB
User Capacity: 7.3 GiB
Boot Capacity: 4 MiB ENH
RPMB Capacity: 4 MiB ENH

3.4.2.2. 查看分区信息

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
=> mmc part

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

Part    Start LBA       End LBA         Name
        Attributes
        Type GUID
        Partition GUID
  1     0x00004000      0x00005fff      "uboot"
        attrs:  0x0000000000000000
        type:   030f0000-0000-440a-8000-5a0500003c68
        guid:   54040000-0000-4235-8000-6d5c00004fb3
  2     0x00006000      0x00045fff      "boot"
        attrs:  0x0000000000000004
        type:   b0440000-0000-4d43-8000-788400007a88
        guid:   346f0000-0000-4136-8000-17bb00007f36
  3     0x00046000      0x00e9ffbf      "rootfs"
        attrs:  0x0000000000000000
        type:   3d410000-0000-4b71-8000-4d7e00004948
        guid:   614e0000-0000-4b53-8000-1d28000054a9

3.4.3. 文件系统操作命令

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

1
2
3
4
=> fstype mmc 0:2
ext4
=> fstype mmc 0:3
ext4

文件系统为ext4的第三个分区对应rootfs根文件系统。

知道了文件系统的类型即可使用相对应的命令对分区内容进行操作了。

3.4.3.1. ext4格式文件系统

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

ext4格式文件系统命令

命令

说明

ext4ls

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

ext4load

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

ext4write

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

3.4.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:3 /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:3  0x80000000  /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 0x80000000 0x80
80000000: 64 65 62 20 68 74 74 70 3a 2f 2f 6d 69 72 72 6f    deb http://mirro
80000010: 72 73 2e 75 73 74 63 2e 65 64 75 2e 63 6e 2f 64    rs.ustc.edu.cn/d
80000020: 65 62 69 61 6e 20 62 75 73 74 65 72 20 6d 61 69    ebian buster mai
80000030: 6e 20 63 6f 6e 74 72 69 62 20 6e 6f 6e 2d 66 72    n contrib non-fr
80000040: 65 65 0a 64 65 62 2d 73 72 63 20 68 74 74 70 3a    ee.deb-src http:
80000050: 2f 2f 6d 69 72 72 6f 72 73 2e 75 73 74 63 2e 65    //mirrors.ustc.e
80000060: 64 75 2e 63 6e 2f 64 65 62 69 61 6e 20 62 75 73    du.cn/debian bus
80000070: 74 65 72 20 6d 61 69 6e 20 63 6f 6e 74 72 69 62    ter main contrib

3.5. U-boot启动内核过程

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

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

1
2
=> printenv bootcmd
bootcmd=boot_android ${devtype} ${devnum};boot_fit;bootrkp;run distro_bootcmd;

如果我们的烧录了Debian或Buildroot镜像的话,会执行bootrkp,通过rk定义的启动流程来启动内核。 具体内容可参考RK官方文档 《U-Boot v2017(next-dev) 开发指南》 2.4启动流程

而如果我们烧录了Ubuntu镜像的话, bootcmd最终会执行distro_bootcmd,同样可以使用 printenv distro_bootcmd 查看distro_bootcmd的内容如下

1
2
3
4
5
=> printenv distro_bootcmd
distro_bootcmd=for target in ${boot_targets}; do run bootcmd_${target}; done

=> printenv boot_targets
boot_targets=mmc1 mmc0 usb0 pxe dhcp

也就是说distro_bootcmd会执行 bootcmd_mmc1、bootcmd_mmc0 bootcmd_usb0 bootcmd_pxe bootcmd_dhcp 这五个环境参数,

在前面我们知道,mmc1表示的sd卡的存储设备,mmc0表示的emmc设备,也就是说当sd卡插在板子时,若sd卡装有系统则会优先从sd卡内启动。

后面三个启动参数,我们的系统暂不支持。

1
2
3
4
=> printenv bootcmd_mmc0
bootcmd_mmc0=setenv devnum 0; run mmc_boot
=> printenv bootcmd_mmc1
bootcmd_mmc1=setenv devnum 1; run mmc_boot

bootcmd_mmc0与bootcmd_mmc1均设置各自 devnum 环境参数的值,最后运行 mmc_boot 环境参数,mmc_boot内容如下

1
2
=> printenv mmc_boot
mmc_boot=if mmc dev ${devnum}; then setenv devtype mmc; run scan_dev_for_boot_part; fi

在mmc_boot中设置 devtype 环境参数的值,最后运行 scan_dev_for_boot_part 环境参数,其作用是扫描设备中带有启动标志的分区

1
2
=> printenv scan_dev_for_boot_part
scan_dev_for_boot_part=part list ${devtype} ${devnum} -bootable devplist; env exists devplist || setenv devplist 1; for distro_bootpart in ${devplist}; do if fstype ${devtype} ${devnum}:${distro_bootpart} bootfstype; then run scan_dev_for_boot; fi; done

提示

若从U-boot中直接使用printenv查看会显得格式很乱,我们在U-boot源码中查看。

  • include/configs/rk3568_common.h

  • include/configs/rockchip-common.h

  • include/config_distro_bootcmd.h

在源文件config_distro_bootcmd.h中我们可以看到scan_dev_for_boot_part的定义

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
"scan_dev_for_boot_part="   \
  "part list ${devtype} ${devnum} -bootable devplist; "   \
  "env exists devplist || setenv devplist 1; "    \
  "for distro_bootpart in ${devplist}; do "   \
    "if fstype ${devtype} "          \
        "${devnum}:${distro_bootpart} "  \
        "bootfstype; then "      \
      "run scan_dev_for_boot; "   \
    "fi; "    \
  "done\0"     \

上述脚本先判断是否存在带 -bootable 标志的分区,如果存在就记录分区号, 然后运行 scan_dev_for_boot去扫描boot分区是否存在启动所需的文件。

1
2
3
4
5
6
7
8
9
"scan_dev_for_boot="     \
  "echo Scanning ${devtype} "   \
      "${devnum}:${distro_bootpart}...; "  \
  "for prefix in ${boot_prefixes}; do "   \
    "run scan_dev_for_scripts; "   \
    "run scan_dev_for_extlinux; "    \
  "done;"  \
  SCAN_DEV_FOR_EFI  \
  "\0"

scan_dev_for_boot的定义这是依次运行scan_dev_for_scripts、scan_dev_for_extlinux。 如果要改变不同启动方式的顺序,可以修改这一部分。

scan_dev_for_extlinux用于扫描boot分区是否存在extlinux.conf配置文件, 存在的话会读取配置文件进行启动。配置文件里定义了内核、设备树等,还可以图形化选取不同版本内核启动,感兴趣可以去了解一下。

scan_dev_for_scripts用于扫描boot分区是否存在boot.scr文件,存在的话就会按照boot.scr脚本中的启动流程进行启动。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
"scan_dev_for_scripts="   \
  "for script in ${boot_scripts}; do "   \
    "if test -e ${devtype} "   \
        "${devnum}:${distro_bootpart} "   \
        "${prefix}${script}; then "   \
      "echo Found U-Boot script "   \
        "${prefix}${script}; "   \
      "run boot_a_script; "  \
      "echo SCRIPT FAILED: continuing...; " \
    "fi; "    \
  "done\0"    \

"boot_scripts=boot.scr.uimg boot.scr\0" \

"boot_a_script="                                                  \
  "load ${devtype} ${devnum}:${distro_bootpart} "           \
    "${scriptaddr} ${prefix}${script}; "              \
  "source ${scriptaddr}\0"                                  \

上述脚本在scan_dev_for_scripts中先去检测我们的boot分区中有没有名称为boot.scr.uimg或boot.scr的启动脚本, 如果检测到的话先输出”Found U-Boot script 脚本路径”这个提示信息,然后运行boot_a_script。如果检测不到的话就跳出。

在我们的鲁班猫板卡boot分区打包时已经编译了boot.scr的源文件并进行打包,所以这里会继续执行boot_a_script

在boot_a_script中读取boot分区中的boot.scr文件并加载到内存中,并使用source运行这个脚本。

boot.scr的源文件储存在SDK目录下的kernel/arch/arm64/boot/dts/rockchip/uEnv/boot.cmd,下面是boot.cmd中的内容

 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
echo [boot.cmd] run boot.cmd scripts ...;

if test -e ${devtype} ${devnum}:${distro_bootpart} /uEnv/uEnv.txt; then

    echo [boot.cmd] load ${devtype} ${devnum}:${distro_bootpart} ${env_addr_r} /uEnv/uEnv.txt ...;
    load ${devtype} ${devnum}:${distro_bootpart} ${env_addr_r} /uEnv/uEnv.txt;

    echo [boot.cmd] Importing environment from ${devtype} ...
    env import -t ${env_addr_r} 0x8000

    setenv bootargs ${bootargs} root=/dev/mmcblk${devnum}p3 ${cmdline}
    printenv bootargs

    echo [boot.cmd] load ${devtype} ${devnum}:${distro_bootpart} ${ramdisk_addr_r} /initrd-${uname_r} ...
    load ${devtype} ${devnum}:${distro_bootpart} ${ramdisk_addr_r} /initrd-${uname_r}

    echo [boot.cmd] loading ${devtype} ${devnum}:${distro_bootpart} ${kernel_addr_r} /Image-${uname_r} ...
    load ${devtype} ${devnum}:${distro_bootpart} ${kernel_addr_r} /Image-${uname_r}

    echo [boot.cmd] loading default rk-kernel.dtb
    load ${devtype} ${devnum}:${distro_bootpart} ${fdt_addr_r} /rk-kernel.dtb

    fdt addr  ${fdt_addr_r}
    fdt set /chosen bootargs

    echo [boot.cmd] dtoverlay from /uEnv/uEnv.txt
    setenv dev_bootpart ${devnum}:${distro_bootpart}
    dtfile ${fdt_addr_r} ${fdt_over_addr}  /uEnv/uEnv.txt ${env_addr_r}

    echo [boot.cmd] [${devtype} ${devnum}:${distro_bootpart}] ...
    echo [boot.cmd] [booti] ...
    booti ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r}
fi

echo [boot.cmd] run boot.cmd scripts failed ...;

# Recompile with:
# mkimage -C none -A arm -T script -d /boot/boot.cmd /boot/boot.scr
  1. 打印提示信息,提示运行到了boot.scr脚本

  2. 判读boot分区中是否存在uEnv/uEnv.txt这个文件,如果存在的话就继续执行下面的脚本

  3. load命令读取uEnv文件到内存,里面保存了自定义的环境变量,如内核,设备树插件等信息

  4. env import命令导入读取到的环境变量

  5. setenv命令设置bootargs环境变量,以便启动内核时向内核传递参数。具体内容是设置了rootfs所在的分区,还将uEnv.txt文件中的cmdline追加到了bootargs

  6. printenv命令打印bootargs环境变量到控制台,便于调试

  7. 从boot分区加载initrd镜像到内存

  8. 从boot分区加载kernel镜像到内存

  9. 从boot分区加载主设备树rk-kernel.dt到内存

  10. fdt命令读取加载的主设备树,并清空/chosen节点中的bootargs的内容,否则会覆盖步骤5设置的bootargs

  11. dtfile命令读取uEnv文件中定义的设备树插件,并合并到主设备树中

  12. 使用booti命令启动内核

经过上面的流程,我们就离开了uboot的工作区域,进入到了内核中。如果以上流程失败,将会继续运行scan_dev_for_extlinux, 解决由于有时设备树插件加载失败等原因导致无法启动的问题。

3.6. 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中使用此操作,会覆盖默认的环境变量。

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