什么是Uboot
U-Boot 本质上是运行在裸机环境下的 Bootloader 程序,但它本身已经具备操作系统级别的模块化结构(命令系统、驱动模型等)。Uboot最主要的工作就是初始化DDR,因为Linux是运行在DDR里面的,一般Linux镜像、设备树存放在SD、EMMC、NAND、SPI FLASH等外置存储区域。Uboot的主要目的就是为系统的启动做准备。
Uboot不仅仅能启动Linux,也可以启动其它系统,比如vsworks等等。Linux不仅仅能通过Uboot启动,也可以通过其他bootloader启动。Uboot是一个通用的Bootloader,支持多种架构。
编译烧录后效果
根据正点原子教程编译烧录后,将sd卡插入开发板,连接串口,发现终端上出现如下信息:

文件结构分析



arch文件夹
arch文件夹存放着架构相关的文件,我们使用的是arm芯片,所以我们只关心其中的arm文件夹即可。打开arm文件夹,如下图所示

board文件夹
此文件夹中包含了不同的开发板相关的文件,我们后面移植 uboot 到时候就是参考 NXP 官方的开发板,也就是要参考mx6ullevk 这个文件夹来定义我们的板子。
configs文件夹
这个文件夹存放了uboot的配置文件,uboot 是可配置的,但是你要是自己从头开始一个一个项目的配置,那就太麻烦了,因此一般半导体或者开发板厂商都会制作好一个配置文件。我们可以在这个做好的配置文件基础上来添加自己想要的功能,这些半导体厂商或者开发板厂商制作好的配置文件统一命名为“xxx_defconfig”, xxx 表示开发板名字这些 defconfig 文件都存放在 configs 文件夹中。

make mx6ull_14x14_ddr512_emmc_defconfig
.uboot.xxx.cmd文件
这些文件是Makefile运行时生成的构建记录和依赖规则,下面有三个文件,它们分别是:
1 | u-boot ELF可执行文件 |
这三个文件通过.cmd转化。
uboot.xxx文件
| 文件名 | 说明 |
|---|---|
| u-boot | 编译出来的 ELF 格式的 uboot 镜像文件。 |
| u-boot.bin | 编译出来的二进制格式的 uboot 可执行镜像文件 |
| u-boot.cfg | uboot 的另外一种配置文件。 |
| u-boot.imx | u-boot.bin 添加头部信息以后的文件,NXP 的 CPU 专用文件。 |
| u-boot.lds | 链接脚本。 |
| u-boot.map | uboot 映射文件,通过查看此文件可以知道某个函数被链接到了哪个地址上。 |
| u-boot.srec | S-Record 格式的镜像文件。 |
| u-boot.sym | uboot 符号文件。 |
| u-boot-nodtb.bin | 如果CONFIG_OF_SEPARATE=y,由u-boot-nodtb.bin + dtb拼接,不然是简单复制关系 |
UBoot顶层Makefile分析
| 裸机 Makefile | U-Boot 顶层 Makefile |
|---|---|
直接编译 .c/.S |
几乎不编译代码 |
| 写 gcc/ld 命令 | 几乎不写 gcc |
控制 .o → .elf |
控制 构建流程 |
版本号
VERSION 是主版本号, PATCHLEVEL 是补丁版本号, SUBLEVEL 是次版本号,这三个一起构成了 uboot 的版本号,比如当前的 uboot 版本号就是“2016.03”。 EXTRAVERSION 是附加版本信息, NAME 是和名字有关的,一般不使用这两个。
1 | VERSION = 2016 |
MAKEFLAGS
make是支持递归调用的,在Makefile中运行
$(MAKE) -C subdir
则会自动运行subdir中的make。
1 | MAKEFLAGS += -rR --include-dir=$(CURDIR) |
上述代码使用“+=”来给变量 MAKEFLAGS 追加了一些值,“-rR”表示禁止使用内置的隐含规则和变量定义,“–include-dir”指明搜索路径, ”$(CURDIR)”表示当前目录。
命令输出
1 | ifeq ("$(origin V)", "command line") |
先判断V是否来自命令行,若是,则将其赋值给KBUILD_VERBOSE,在判断KBUILD_VERBOSE是不是1,控制是否输出详细命令。
指定编译结果输出路径
make O=…
执行上述语句即可指定编译结果输出路径。
获取主机系统架构
1 | HOSTARCH := $(shell uname -m | \ |
Makefile会获取主机架构和系统,并将信息存入变量中。“|”意为管道,将左边的输出作为右边的输入。
设置目标架构、交叉编译器和配置文件
1 | ifeq ($(HOSTARCH),$(ARCH)) |
对于这个实验,我们应在第三行endif后添加如下语句
1 | ARCH ?= arm |
这样就默认设置了目标架构和目标编译器,并生成了一个.config文件并用export命令将其导出使得子文件夹中的makefile也可以调用。
交叉编译工具变量设置
1 | AS = $(CROSS_COMPILE)as |
ARCH CPU BOARD VENDOR SOC CPUDIR BOARDDIR这几个变量在uboot根目录下的config.mk文件中定义。config.mk中又读取了以下文件。
arch/arm/config.mk
arch/arm/cpu/armv7/config.mk
arch/arm/cpu/armv7/mx6/config.mk (此文件不存在)
board/ freescale/mx6ullevk/config.mk (此文件不存在)
make xxx_defconfig 过程

当敲下命令make xxx_defconfig后,顶层makefile识别出这是一个config类目标,先构建scripts/basic(配置工具),调用kconfig系统,然后读取arch/arm/configs/xxx_defconfig,最后生成.config + include/config/*
make 过程

make默认目标是u-boot.srec、u-boot.bin、u-boot.sym、System.map、u-boot.cfg 和 binary_size_check这几个文件。
依赖关系如下
1 | u-boot.bin |