U-Boot
源代码
主要
https://source.denx.de/u-boot/u-boot
备用
https://github.com/u-boot/u-boot.git
说明
通用引导加载器。通常用于加载Linux。
常用编译命令参数如下(适用于截止编辑时的最新版u-boot):
项目 | 类型 | 说明 | 备注 |
---|---|---|---|
menuconfig | Makefile目标 | 使用菜单配置u-boot | 必须先加载某个默认配置再使用菜单配置。默认配置在configs目录,可使用make 默认配置名 加载。
|
all | Makefile目标 | 构建 | 这是默认目标,也可省略不带任何目标 |
ARCH | 环境变量/Makefile变量 | 指定架构 | 可在arch目录中查看支持的架构,如32位arm则可指定ARCH=arm |
CROSS_COMPILE | 环境变量/Makefile变量 | 指定交叉编译工具链前缀 | 如若要使用arm-none-eabi-gcc则可指定CROSS_COMPILE=arm-none-eabi- |
环境变量(Env)
注意:若未特殊说明,此说明仅适用于截至编辑时的u-boot,不包括旧版u-boot。
Env表示环境变量,很多u-boot的操作及脚本都靠环境变量调控。
默认环境变量主要有以下方式生成:
- Kconfig配置生成。
- 直接文件生成。
默认情况下使用Kconfig配置生成默认Env,默认环境变量具体定义的头文件/目录/机制如下:
- include/env_default.h文件:定义默认的环境变量与Kconfig配置的关系。
- include/configs目录:各个SOC厂商的配置头文件,一般使用
CFG_EXTRA_ENV_SETTINGS
宏定义在厂商头文件定义厂商自己的环境变量。
直接使用文件生成默认Env的机制如下:
- 厂商的配置文件:默认目录为
board/<vendor>/<board>/
,文件名可以由CONFIG_ENV_SOURCE_FILE
或SYS_BOARD
指定,后缀名为.env。 - 外部的配置文件:使用
CONFIG_USE_DEFAULT_ENV_FILE
使能,使用CONFIG_DEFAULT_ENV_FILE
指定位置。注意:若启用外部的配置文件将导致Kconfig中的相关选项不可用,直接完全由用户管理。
启动介质
注意:若未特殊说明,此说明仅适用于截至编辑时的u-boot,不包括旧版u-boot。
u-boot可从多种存储介质上启动,具体支持的启动方式根据硬件方案的不同而不同,本章只描述本人常用的方式。
SD卡/TF卡
采用MMC接口,常见于各种开发板。
通常会有一个完整的镜像,采用MBR磁盘分区或者GPT磁盘分区,包含一个FAT分区(方便在Windows更新相关文件)及若干个其他分区,U-boot的启动脚本与Linux内核放在FAT分区。
可使用以下方式烧录镜像:
- dd:在Linux或其他(类)unix中可使用dd命令直接将镜像写入SD卡/TF卡。
- win32diskimager:在windows下可使用此工具写入镜像文件。
对于本人而言,除了开发板厂商提供的方式,本人还可使用Buildroot产生镜像。
分区
分区采用MBR磁盘分区或者GPT磁盘分区,编辑同pc机一样,有广泛的工具可供使用。
由于磁盘镜像一般都是尽量做小,故烧录后的rootfs可能不是很大,则对于大容量SD卡/TF卡则需要调整rootfs分区。
对于采用ext2/ext3/ext4的rootfs分区而言,可采用以下步骤调整分区:
- 调整分区表:采用各种通用工具调整rootfs的分区表(Linux下可采用fdisk),扩大分区大小。调整完成后最好进行一次重启。
- 调整文件系统:当分区表调整完成后只是分区大小发生改变,文件系统中的信息并未发生改变,故应当使用resize2fs命令将文件系统调整为分区大小。
数据加载
对于传统的u-boot启动过程而言,所有数据都需要加载到内存中才能继续操作(如启动等)。
可使用mmc命令读取SD卡/TF卡数据,但一般不使用此命令加载数据。
SD卡/TF卡一般采用了MBR磁盘分区或者GPT磁盘分区,并且使用常用的文件系统(如fat、ext2、ext4),各种文件也是放在文件系统中的.
因此更加常用的是采用文件系统相关命令加载数据到内存,常用的的命令如下:
文件系统 | 数据加载命令 | 说明 |
---|---|---|
fat32 | fatload | 从fat文件系统加载数据,如启动脚本、Linux内核、设备树dtb、环境变量文件等 |
ext2 | ext2load | 从ext2文件系统加载数据。 |
ext4 | ext4load | 从ext4文件系统加载数据。 |
- | load | 从文件系统中加载数据。这是一个通用版本,可方便脚本的编写。 |
移植提示
如需操作mmc设备,需要在 > Command line interface > Device access commands
使能 CONFIG_CMD_MMC
以启用mmc命令。
如需操作fat文件系统 ,需要在> Command line interface > Filesystem commands使能CONFIG_CMD_FAT启用相关命令。
如需操作ext2文件系统 ,需要在> Command line interface > Filesystem commands使能CONFIG_CMD_EXT2启用相关命令。
如需操作ext4文件系统 ,需要在> Command line interface > Filesystem commands使能CONFIG_CMD_EXT4启用相关命令。
如需使用通用方式操作文件系统,需要在> Command line interface > Filesystem commands使能CONFIG_CMD_FS_GENERIC启用相关命令。
SPI Nor Flash
采用SPI接口。若未说明,本人一般使用容量大于等于16MBytes的Nor Flash。
Nor Flash的烧录方式根据SOC的不同而不同,具体如下:
- 对于全志SOC而言,可进入FEL模式采用Xfel烧录。
由于Nor Flash容量较小,一般分区使用固定分区,即没有任何分区表与磁盘信息存储在介质上,直接在代码或配置(如设备树dts)中写死分区信息数据。
分区
MTD设备的分区使用环境变量决定,具体如下:
环境变量名称 | u-boot中的注释 | 说明 |
---|---|---|
partition | 'partition' - keeps current partition identifier
* * partition := <part-id> * <part-id> := <dev-id>,part_num |
相当于其它分区表的激活分区。
dev-id同mtdids中的dev-id。 |
mtdids | 'mtdids' - linux kernel mtd device id <-> u-boot device id mapping
* * mtdids=<idmap>[,<idmap>,...] * * <idmap> := <dev-id>=<mtd-id> * <dev-id> := 'nand'|'nor'|'onenand'|'spi-nand'<dev-num> * <dev-num> := mtd device number, 0... * <mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name) |
mtd设备id列表。
dev-id的格式是固定(如第一个nor flash的dev-id为nor0)。 此环境变量相当于将mtd设备与linux中的标签对应,使得mtdparts可以直接传给Linux内核。 |
mtdparts | 'mtdparts' - partition list
* * mtdparts=[mtdparts=]<mtd-def>[;<mtd-def>...] * * <mtd-def> := <mtd-id>:<part-def>[,<part-def>...] * <mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name) * <part-def> := <size>[@<offset>][<name>][<ro-flag>] * <size> := standard linux memsize OR '-' to denote all remaining space * <offset> := partition start offset within the device * <name> := '(' NAME ')' * <ro-flag> := when set to 'ro' makes partition read-only (not used, passed to kernel) |
mtd设备分区表。 |
u-boot的mtd分区信息可以通过内核命令行传给启用了命令行传MTD分区参数的Linux内核,但更加常见的是使用设备树dts传MTD分区参数给Linux内核。
u-boot中mtd分区的例子如下:
/*
* Examples:
*
* 1 NOR Flash, with 1 single writable partition:
* mtdids=nor0=edb7312-nor
* mtdparts=[mtdparts=]edb7312-nor:-
*
* 1 NOR Flash with 2 partitions, 1 NAND with one
* mtdids=nor0=edb7312-nor,nand0=edb7312-nand
* mtdparts=[mtdparts=]edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home)
*
*/
默认分区信息的Kconfig在启用mtdparts命令时可填写,如下:
Kconfig项 | 环境变量项 |
---|---|
CONFIG_MTDIDS_DEFAULT | mtdids |
CONFIG_MTDPARTS_DEFAULT | mtdparts |
全志SOC
默认情况下(u-boot在全志SOC默认设置),采用以下分区:
起始地址 | 大小(字节) | 名称 | 说明 |
---|---|---|---|
0 | 0xF0000(960KBytes) | u-boot | u-boot二进制代码所在位置 |
0xF0000 | 0x10000(64KBytes) | u-boot-env | u-boot的env数据,可保存一些u-boot使用的环境变量,可保存修改后的启动行为。 |
0x100000 | - | - | 剩余位置,可继续划分分区。 |
数据加载
对于传统的u-boot启动过程而言,所有数据都需要加载到内存中才能继续操作(如启动等)。
一般使用mtd命令加载mtd设备或mtd分区数据到内存中,一般通过偏移加大小确定数据位置。
由于SPI Nor Flash一般不包含传统分区表,如需使用文件系统也是特殊的文件系统,所以一般不使用文件系统相关命令加载数据。
移植提示
SPI Nor Flash使用条件:
- SOC支持从SPI Nor Flash启动。
- u-boot已经移植有对应SOC的spi驱动。
配置SPI Nor Flash的支持如下:
- 配置Kconfig。
启用属于MTD设备的SPI Nor Flash Kconfig路径: > Device Drivers > MTD Support > SPI Flash Support 选中CONFIG_SPI_FLASH并CONFIG_BOOTDEV_SPI_FLASH且选中需要支持的Nor Flash。 启用SPI驱动设备(只需要选中对应SOC的驱动) Kconfig路径:> Device Drivers > SPI Support
- 配置设备树(同Linux一样)。
/*以下代码主要用于启用spi0上的flash*/ &spi0 { flash@0 { compatible = "jedec,spi-nor"; reg = <0>; spi-max-frequency = <40000000>; }; };
若u-boot需要使用spl则需要在spl中启用spi nor flash支持(具体方法根据芯片及板子的不同而不同),粗略配置如下:
- 配置Kconfig。
启用属于MTD设备的SPI Nor Flash的SPL支持 Kconfig路径: > Device Drivers > MTD Support > SPI Flash Support 选中CONFIG_SPL_SPI_FLASH_MTD。 在SPL中选中MTD支持 Kconfig路径: > SPL configuration options 选中SPI FLASH相关选项。
有些spi nor flash的jedec id可能不在u-boot的支持列表中,可能需要手动向drivers/mtd/spi/spi-nor-ids.c中添加需要支持的id。
如需操作mtd设备,需要在 > Command line interface > Device access commands
使能CONFIG_CMD_MTD
以启用mtd命令。
如需使用mtd分区,需要在> Command line interface > Filesystem commands
使能CONFIG_CMD_MTDPARTS
以启用mtdparts命令。
SPI Nand Flash
采用SPI接口。若未说明,本人一般使用容量大于等于128MBytes的Nand Flash。
SPI Nand Flash的绝大多数操作均可参考SPI Nor Flash,在u-boot也属于mtd设备,只是相关子项需要选择Nand Flash。
一般情况下,SPI Nand Flash的容量可以做得比SPI Nor Flash大,对于32MBytes以上(不含32MBytes)的SPI存储需求,可使用SPI Nand Flash,另外SPI Nand Flash不支持XIP技术,如需此技术则不可使用SPI Nand Flash。
启动设置
注意:若未特殊说明,此说明仅适用于截至编辑时的u-boot,不包括旧版u-boot。
启动设置的Kconfig菜单在> Boot options ,实际主要通过环境变量影响启动行为(若使用外部文件作为默认环境变量可能使设置无效)。
所有的启动过程其实都是使用u-boot脚本,将对应的脚本内容写入对应的环境变量即可启动,常用的启动相关环境变量如下:
环境变量 | Kconfig项 | 说明 |
---|---|---|
bootargs | CONFIG_BOOTARGS | Linux内核命令行参数,但现在更加常用的是使用设备树dts传参。 |
bootcmd | CONFIG_BOOTCOMMAND | 启动脚本,当使用自动启动时自动执行此环境变量中的命令。 |
preboot | CONFIG_PREBOOT | 在自动启动前运行的脚本,主要推荐用途:在bootcmd中修改此值实现在下一次启动时执行不同的行为(比如重启进入其他模式)。
个人认为的用途:提前初始化一些硬件,这样bootcmd不变,只改变preboot。 |
默认情况下,尝试启动失败(而非执行应用失败)会进入shell,这样其实可以测试一些命令及脚本(使用run命令调用)。
传统启动过程
传统启动过程在此wiki中指直接使用u-boot传统方式(写脚本到环境变量加载数据然后启动)启动的过程 ,通常这不是默认的,且基本上都是针对各个具体硬件定制的。
具体指将数据加载在内存中后采用以下命令启动的过程:
- bootm:启动应用。可启动各种u-boot支持的镜像,一般用于启动Linux uImage.
- bootz:启动Linux zImage。
传统启动时环境变量bootcmd是自定义的,也不用考虑内存驻留问题,当启动到内核时将控制权交给内核,因此可将几乎所有内存给内核使用,某些特殊启动模式下需要保留一部分内存。
通用发行版(distro)启动过程
发行版启动过程(参考见源代码doc/develop/distro.rst)主要提供一个通用的启动Linux发行版的方式,通常这是默认的值之一,这无需对u-boot进行任何定制。
实现时环境变量bootcmd=run distro_bootcmd
。
发行版启动主要有以下方式:
- U-Boot's "syslinux" (disk)
- "pxe boot" (network)
简单来说就是分磁盘启动与网络pxe启动,网络pxe启动在嵌入式上的应用较少因此不予赘述,磁盘启动主要有以下条件:
- 磁盘采用通用分区表(如MBR、GPT等,具体可通过Kconfig配置)。
- 分区采用通用文件系统(如ext2/3/4 、FAT等,具体可通过Kconfig配置)。
- 分区上存在菜单文件 extlinux.conf(具体可为/extlinux/extlinux.conf或者/boot/extlinux/extlinux.conf等)或者u-boot脚本文件(具体可为/boot/boot.scr等,具体可通过Kconfig配置)。
- 厂商提供了必要的环境变量以提供内存布局, 具体如下:
环境变量 | 含义 |
---|---|
fdt_addr | 设备树dtb地址(在ROM中),仅当可以直接通过地址访问的系统需要,其余系统不能使用此环境变量。 |
fdt_addr_r | 设备树dtb内存地址。 |
fdtoverlay_addr_r | 设备树dtb overlay内存地址。 |
fdtfile | 设备树dtb设备树文件名,有些情况下会自动设置此值。 |
ramdisk_addr_r | ramdisk内存地址,推荐放在高地址。 |
kernel_addr_r | 内核内存地址。 |
kernel_comp_addr_r | 内核压缩文件内存地址,若使用booti命令则需要此值。 |
kernel_comp_size | 内核压缩文件大小,若使用booti命令则需要此值。 |
scriptaddr | U-Boot脚本加载内存地址。若启用了u-boot脚本,则在此处执行脚本。 |
pxefile_addr_r | extlinux.conf菜单加载内存地址。 |
实际菜单文件 extlinux.conf写法同pxe启动时菜单写法(参考见源代码doc/README.pxe),菜单示例如下:
One example extlinux.conf generated by the Fedora installer is::
# extlinux.conf generated by anaconda
ui menu.c32
menu autoboot Welcome to Fedora. Automatic boot in # second{,s}. Press a key for options.
menu title Fedora Boot Options.
menu hidden
timeout 50
#totaltimeout 9000
default Fedora (3.17.0-0.rc4.git2.1.fc22.armv7hl+lpae) 22 (Rawhide)
label Fedora (3.17.0-0.rc4.git2.1.fc22.armv7hl) 22 (Rawhide)
kernel /boot/vmlinuz-3.17.0-0.rc4.git2.1.fc22.armv7hl
append ro root=UUID=8eac677f-8ea8-4270-8479-d5ddbb797450 console=ttyS0,115200n8 LANG=en_US.UTF-8 drm.debug=0xf
fdtdir /boot/dtb-3.17.0-0.rc4.git2.1.fc22.armv7hl
initrd /boot/initramfs-3.17.0-0.rc4.git2.1.fc22.armv7hl.img
label Fedora (3.17.0-0.rc4.git2.1.fc22.armv7hl+lpae) 22 (Rawhide)
kernel /boot/vmlinuz-3.17.0-0.rc4.git2.1.fc22.armv7hl+lpae
append ro root=UUID=8eac677f-8ea8-4270-8479-d5ddbb797450 console=ttyS0,115200n8 LANG=en_US.UTF-8 drm.debug=0xf
fdtdir /boot/dtb-3.17.0-0.rc4.git2.1.fc22.armv7hl+lpae
initrd /boot/initramfs-3.17.0-0.rc4.git2.1.fc22.armv7hl+lpae.img
label Fedora-0-rescue-8f6ba7b039524e0eb957d2c9203f04bc (0-rescue-8f6ba7b039524e0eb957d2c9203f04bc)
kernel /boot/vmlinuz-0-rescue-8f6ba7b039524e0eb957d2c9203f04bc
initrd /boot/initramfs-0-rescue-8f6ba7b039524e0eb957d2c9203f04bc.img
append ro root=UUID=8eac677f-8ea8-4270-8479-d5ddbb797450 console=ttyS0,115200n8
fdtdir /boot/dtb-3.16.0-0.rc6.git1.1.fc22.armv7hl+lpae
One example of hand-crafted extlinux.conf::
menu title Select kernel
timeout 100
label Arch with uart devicetree overlay
kernel /arch/Image.gz
initrd /arch/initramfs-linux.img
fdt /dtbs/arch/board.dtb
fdtoverlays /dtbs/arch/overlay/uart0-gpio0-1.dtbo
append console=ttyS0,115200 console=tty1 rw root=UUID=fc0d0284-ca84-4194-bf8a-4b9da8d66908
label Arch with uart devicetree overlay but with Boot Loader Specification keys
kernel /arch/Image.gz
initrd /arch/initramfs-linux.img
devicetree /dtbs/arch/board.dtb
devicetree-overlay /dtbs/arch/overlay/uart0-gpio0-1.dtbo
append console=ttyS0,115200 console=tty1 rw root=UUID=fc0d0284-ca84-4194-bf8a-4b9da8d66908
Another hand-crafted network boot configuration file is::
TIMEOUT 100
MENU TITLE TFTP boot options
LABEL jetson-tk1-emmc
MENU LABEL ../zImage root on Jetson TK1 eMMC
LINUX ../zImage
FDTDIR ../
APPEND console=ttyS0,115200n8 console=tty1 loglevel=8 rootwait rw earlyprintk root=PARTUUID=80a5a8e9-c744-491a-93c1-4f4194fd690b
LABEL venice2-emmc
MENU LABEL ../zImage root on Venice2 eMMC
LINUX ../zImage
FDTDIR ../
APPEND console=ttyS0,115200n8 console=tty1 loglevel=8 rootwait rw earlyprintk root=PARTUUID=5f71e06f-be08-48ed-b1ef-ee4800cc860f
LABEL sdcard
MENU LABEL ../zImage, root on 2GB sdcard
LINUX ../zImage
FDTDIR ../
APPEND console=ttyS0,115200n8 console=tty1 loglevel=8 rootwait rw earlyprintk root=PARTUUID=b2f82cda-2535-4779-b467-094a210fbae7
LABEL fedora-installer-fk
MENU LABEL Fedora installer w/ Fedora kernel
LINUX fedora-installer/vmlinuz
INITRD fedora-installer/initrd.img.orig
FDTDIR fedora-installer/dtb
APPEND loglevel=8 ip=dhcp inst.repo=http://10.0.0.2/mirrors/fedora/linux/development/rawhide/armhfp/os/ rd.shell cma=64M
U-Boot标准启动(U-Boot Standard Boot)过程
U-Boot标准启动过程(参考见源代码doc/develop/bootstd.rst)更像是PC上的启动过程,即依次尝试在各个启动设备上使用各种启动方法(包括但不限于 通用发行版(distro)启动过程,如EFI启动管理器或者VBE启动管理器 ),主要提供一个通用的启动方式,通常这是默认的值之一。
此过程需要厂商提供必要的环境变量以提供内存布局,具体如下:
环境变量 | 含义 |
---|---|
fdt_addr | 设备树dtb地址(在ROM中),仅当可以直接通过地址访问的系统需要,其余系统不能使用此环境变量。 |
fdt_addr_r | 设备树dtb内存地址。 |
fdtoverlay_addr_r | 设备树dtb overlay内存地址。 |
fdtfile | 设备树dtb设备树文件名,有些情况下会自动设置此值。 |
ramdisk_addr_r | ramdisk内存地址,推荐放在高地址。 |
kernel_addr_r | 内核内存地址。 |
kernel_comp_addr_r | 内核压缩文件内存地址,若使用booti命令则需要此值。 |
kernel_comp_size | 内核压缩文件大小,若使用booti命令则需要此值。 |
scriptaddr | 脚本(菜单)加载内存地址。若启用了u-boot脚本,则在此处执行脚本。 |
pxefile_addr_r | PXE文件加载内存地址。 |
script_offset_f | U-Boot脚本在Flash上的偏移,用于加载SPI Flash上的启动脚本。 |
script_size_f | U-Boot脚本的大小,配合script_offset_f使用。 |
devtype | 启动设备类型。由bootmeth使用。 |
devnum | 启动设备编号。由bootmeth使用。 |
distro_bootpart | 启动分区编号。由bootmeth使用。 |
prefix | 脚本目录。由bootmeth使用。 |
mmc_bootdev | 启动设备编号(仅限全志SOC)。由bootmeth使用。 |
U-Boot标准启动过程主要使用以下命令:
- bootdev
- bootmeth
- bootflow
在u-boot脚本或者shell中可使用以下命令启动 U-Boot标准启动过程:
#启用CONFIG_BOOTSTD_FULL时使用
bootflow scan -lb
#未启用CONFIG_BOOTSTD_FULL时使用
bootflow scan
将环境变量bootcmd设置为bootflow scan
(未启用CONFIG_BOOTSTD_FULL)或者bootflow scan -lb
(启用CONFIG_BOOTSTD_FULL)即可启用U-Boot标准启动过程。
官方资料
网站:https://www.denx.de/project/u-boot/