U-Boot初体验
1 引言
U-Boot全称是Universal Boot Loader,即通用Bootloader,可以引导多种类型的操作系统,并支持多种架构的CPU。其本身是开源的,遵循GPL协议,可以看作是一个裸机综合程序,在嵌入式Linux领域被广泛使用。最主要的作用是从存储介质中加载Linux内核到内存中,向Linux内核传递启动参数,并启动Linux内核。
更多详细请参考如下链接:
U-Boot – DENX Software Engineering
The U-Boot Documentation — Das U-Boot unknown version documentation
接下来,我会以TI官方提供的用于BeagleBone Black开发板的U-Boot 2015.07为例,开始U-Boot的初体验。
2 U-Boot源码结构
2.1 整体结构
获得源码后,解压进入源码目录,可以发现U-Boot的源码有很多文件夹和文件组成,根目录下的文件组织如下所示:
根目录下除了文件夹以外,上图中红框所标出的两个文件需要特别注意一下,它们是U-Boot图形化配置和编译的支撑性文件。
-
除了根目录下,各个子目录基本也都存在Makefile和KConfig文件。
-
Makefile的作用时定义哪些文件被编译、什么条件下被编译、怎么编译等,子目录下的Makefile被顶层Makefile所包含。
-
分布在各级目录下的KConfig构成了一个分布式的配置数据库,每个Kconfig分别描述了所属目录源文件相关的配置菜单。
-
执行配置命令时,会读取KConfig文件,并在顶层目录下生成.config文件,该文件会在编译时被Makefile调用,由此知道用户的配置情况。
-
关于KConfig和Makefile后面会有专题介绍,敬请期待,这里暂且略过。
2.2 目录解读
U-Boot源码根目录下的文件夹、文件按作用可以分为以下三类:
- 平台依赖类:是与处理器体系结构或开发板硬件直接相关的
- 通用类:包括通用的函数或者驱动程序
- 其它类:包括U-Boot应用程序、工具文件或者文档
2.2.1 平台依赖目录
2.2.1.1 arch目录
arch目录下存放的是和处理器架构相关的文件,如下所示。可以看到很多不同的体系架构目录,我们使用的ARM处理器,仅需要关注图中箭头所指的arm目录即可。
进入arm目录,如下所示,其中cpu目录下也是与架构相关的文件
CPU目录的组织,如下图所示,我们使用的BeagleBone Black是Cortex-A8内核的,属于armv7。另外,cpu目录下有个名为u-boot.lds的链接脚本文件,这个就是ARM架构CPU所使用的链接脚本文件。关于链接脚本,后面的会有专题介绍,敬请期待。
2.2.1.2 board目录
board目录是与具体的开发板相关的目录,打开此文件夹,里面是以不同厂商名字命名的目录,BeagleBone Black所使用的CPU是ti公司的,ti公司的名字赫然在列,如下所示:
进入到ti目录下,有各种使用ti芯片的开发板目录,BeagleBone Black的开发板对应的目录是am335x,如箭头所示。
2.2.1.3 configs目录
configs目录下为U-Boot的配置文件,我们知道U-Boot是支持不同架构、不同CPU、不同开发板、不同功能的程序集合,并且是可以配置的。一般来讲,开发者不会从零开始配置,都是基于半导体或者开发板厂商提前制作好的配置文件进行修改和匹配。毕竟实际产品开发过程中为降低风险和提升效率,硬件设计基本是基于半导体或者开发板厂商提供的Demo开发板进行修改的。
我们拿来学习的BeagleBone Black开发板,虽不是ti官方的开发板,但ti官方也是给予了支持,其对应的配置文件如下所示:
2.2.2 通用目录
2.2.2.1 common目录
common目录下是U-Boot所支持的各种命令的实现文件,基本是每个以cmd_开头的文件对应一个具体的命令实现。
2.2.2.2 disk目录
disk目录下是对磁盘操作命令的支持。
2.2.2.3 fs目录
fs目录下是对各种文件系统的支持,如fat、jiffs、yaffs2、ubifs、ext4等,目前嵌入式系统中常用的是ext4。
2.2.2.4 net目录
net目录下是与网络协议栈相关的代码,如基本的ping命令、TFTP、BOOTP、NFS文件系统等。
2.2.2.5 lib目录
lib目录下是使用的公共库或者utils文件,如gzip、环形缓冲circbuf、crc16校验等
2.2.2.6 drivers目录
drivers目录下全是驱动文件,U-Boot对各种网卡、Flash、串口和USB等的支持都在该目录,如下所示:
2.2.2.7 post目录
post目录下是上电自检相关的文件源码,目前没有使用到。
2.2.2.8 dts目录
设备树文件夹,U-Boot后续的版本也会支持设备树。什么,U-Boot也要使用设备树?是的,你没看错,有些比较新的cpu,其使用的U-Boot就会支持设备树,比如ST的STMP15x系列。我们使用的U-Boot版本暂且不支持。
2.2.3 其它类目录
2.2.3.1 doc目录
doc目录下是一些帮助文档,如下所示:
帮助文档的主题可以从文件的名字中看的出来,这里选择README.kconfig进行查看,内容如下:
Kconfig in U-Boot
=================
This document describes the configuration infrastructure of U-Boot.
The conventional configuration was replaced by Kconfig at v2014.10-rc1 release.
Language Specification
----------------------
Kconfig originates in Linux Kernel.
See the file "Documentation/kbuild/kconfig*.txt" in your Linux Kernel
source directory for a basic specification of Kconfig.
Difference from Linux's Kconfig
-------------------------------
Here are some worth-mentioning configuration targets.
- silentoldconfig
This target updates .config, include/generated/autoconf.h and
include/configs/* as in Linux. In U-Boot, it also does the followings
for the compatibility with the old configuration system:
* create a symbolic link "arch/${ARCH}/include/asm/arch" pointing to
the SoC/CPU specific header directory
* create include/config.h
* create include/autoconf.mk
* create spl/include/autoconf.mk (SPL and TPL only)
* create tpl/include/autoconf.mk (TPL only)
If we could completely switch to Kconfig in a long run
(i.e. remove all the include/configs/*.h), those additional processings
above would be removed.
- defconfig
In U-Boot, "make defconfig" is a shorthand of "make sandbox_defconfig"
- <board>_defconfig
Now it works as in Linux.
The prefixes such as "+S:" in *_defconfig are deprecated.
You can simply remove the prefixes. Do not add them for new boards.
- <board>_config
This does not exist in Linux's Kconfig.
"make <board>_config" works the same as "make <board>_defconfig".
Prior to Kconfig, in U-Boot, "make <board>_config" was used for the
configuration. It is still supported for backward compatibility, so
we do not need to update the distro recipes.
The other configuration targets work as in Linux Kernel.
Migration steps to Kconfig
--------------------------
Prior to Kconfig, the C preprocessor based board configuration had been used
in U-Boot.
Although Kconfig was introduced and some configs have been moved to Kconfig,
many of configs are still defined in C header files. It will take a very
long term to move all of them to Kconfig. In the interim, the two different
configuration infrastructures should coexist.
The configuration files are generated by both Kconfig and the old preprocessor
based configuration as follows:
Configuration files for use in C sources
- include/generated/autoconf.h (generated by Kconfig for Normal)
- include/configs/<board>.h (exists for all boards)
Configuration file for use in makefiles
- include/config/auto.conf (generated by Kconfig)
- include/autoconf.mk (generated by the old config for Normal)
- spl/include/autoconfig.mk (generated by the old config for SPL)
- tpl/include/autoconfig.mk (generated by the old config for TPL)
When adding a new CONFIG macro, it is highly recommended to add it to Kconfig
rather than to a header file.
Conversion from boards.cfg to Kconfig
-------------------------------------
Prior to Kconfig, boards.cfg was a primary database that contained Arch, CPU,
SoC, etc. of all the supported boards. It was deleted when switching to
Kconfig. Each field of boards.cfg was converted as follows:
Status -> "S:" entry of MAINTAINERS
Arch -> CONFIG_SYS_ARCH defined by Kconfig
CPU -> CONFIG_SYS_CPU defined by Kconfig
SoC -> CONFIG_SYS_SOC defined by Kconfig
Vendor -> CONFIG_SYS_VENDOR defined by Kconfig
Board -> CONFIG_SYS_BOARD defined by Kconfig
Target -> File name of defconfig (configs/<target>_defconfig)
Options -> CONFIG_SYS_EXTRA_OPTIONS defined by Kconfig
Maintainers -> "M:" entry of MAINTAINERS
Tips to add/remove boards
-------------------------
When adding a new board, the following steps are generally needed:
[1] Add a header file include/configs/<target>.h
[2] Make sure to define necessary CONFIG_SYS_* in Kconfig:
Define CONFIG_SYS_CPU="cpu" to compile arch/<arch>/cpu/<cpu>
Define CONFIG_SYS_SOC="soc" to compile arch/<arch>/cpu/<cpu>/<soc>
Define CONFIG_SYS_VENDOR="vendor" to compile board/<vendor>/common/*
and board/<vendor>/<board>/*
Define CONFIG_SYS_BOARD="board" to compile board/<board>/*
(or board/<vendor>/<board>/* if CONFIG_SYS_VENDOR is defined)
Define CONFIG_SYS_CONFIG_NAME="target" to include
include/configs/<target>.h
[3] Add a new entry to the board select menu in Kconfig.
The board select menu is located in arch/<arch>/Kconfig or
arch/<arch>/*/Kconfig.
[4] Add a MAINTAINERS file
It is generally placed at board/<board>/MAINTAINERS or
board/<vendor>/<board>/MAINTAINERS
[5] Add configs/<target>_defconfig
When removing an obsolete board, the following steps are generally needed:
[1] Remove configs/<target>_defconfig
[2] Remove include/configs/<target>.h if it is not used by any other boards
[3] Remove board/<vendor>/<board>/* or board/<board>/* if it is not used
by any other boards
[4] Update MAINTAINERS if necessary
[5] Remove the unused entry from the board select menu in Kconfig
[6] Add an entry to doc/README.scrapyard
TODO
----
- The option field of boards.cfg, which was used for the pre-Kconfig
configuration, moved to CONFIG_SYS_EXTRA_OPTIONS verbatim now.
Board maintainers are expected to implement proper Kconfig options
and switch over to them. Eventually CONFIG_SYS_EXTRA_OPTIONS will go away.
CONFIG_SYS_EXTRA_OPTIONS should not be used for new boards.
- In the pre-Kconfig, a single board had multiple entries in the boards.cfg
file with differences in the option fields. The corresponding defconfig
files were auto-generated when switching to Kconfig. Now we have too many
defconfig files compared with the number of the supported boards. It is
recommended to have only one defconfig per board and allow users to select
the config options.
- Move the config macros in header files to Kconfig. When we move at least
macros used in makefiles, we can drop include/autoconfig.mk, which makes
the build scripts much simpler.
接触过旧版本U-Boot的童鞋可能有所了解,以前的U-Boot是不支持KConfig的,从这篇帮助文档可以知道:从v2014.10-rc1才开始向Kernl看齐,引入了KConfig。
2.2.3.2 examples目录
examples目录下是例程,一些独立运行的应用程序,比如helloword,可以借鉴一下。
2.2.3.3 tools目录
tools目录下是一些U-Boot使用的工具,比如mkimage、crc等
2.2.3.4 scripts目录
scripts目录下是一些脚本文件,如下所示:
3 U-Boot编译和启动
3.1 U-Boot编译步骤
(1) 设置交叉编译工具链,确保使用gcc-linaro-4.9-2015.05-x86_64_arm-linux-gnueabihf
(2) 编译之前清除一下,如果之前没有编译过,此步骤可选
make CROSS_COMPILE=arm-linux-gnueabihf- distclean
(3) 配置U-Boot
make CROSS_COMPILE=arm-linux-gnueabihf- O=./BeagleBoneBlack am335x_evm_defconfig
- 通过***O=***选项指定编译输出目录,也可以不指定,则会在源文件目录下产生输出文件,和源文件混杂在一起。为了清晰,指定输出目录为根目录下的BeagleBoneBlack
- TI AM335X系列的开发板会板载一个EEPROM,存储开发板类型。U-Boot会从EEPROM中读取信息,判断开发板类型。故不管是am335x_evm还是AM335x GP EVM或者BeagleBone Black采用的均是am335x_evm_defconfig配置文件。如果是自己制做的硬件,要么在EEPROM中写入数据,要么在U-Boot中将读取EEPROM的代码去掉。
执行结果如下所示,执行结束后,会在U-Boot源码根目录下生成BeagleBoneBlack目录
(4) 编译U-Boot
make CROSS_COMPILE=arm-linux-gnueabihf- O=./BeagleBoneBlack
执行编译命令,编译过程需要一定时间,视电脑性能而定。
编译完成后,进入BeagleBoneBlack目录查看,生成最终可用的MLO和U-Boot.img文件,还有很多中间文件、U-Boot map文件和链接脚本等文件,如下所示:
3.2 U-Boot启动
U-Boot编译好之后,将编译生成u-boot.img和MLO放入到已准备好的SD卡的boot分区,如下所示:
如果SD卡中已经有内核镜像和根文件系统,则会顺势启动整个系统。如果需要停留再U-Boot阶段,按箭头所示,在启动时,按下任意按键,如下所示,则表示U-Boot已经正常启动