一、U-Boot 目录简介
U-Boot 源代码目录结构清晰,进入 U-Boot 源代码目录,可以看到如图1 的目录。
图1 U-Boot 根目录内容
在该目录中,重要的子目录说明如表1所列。
目 录 | 说 明 |
board | 存放了 U-Boot 所支持的开发板的相关代码,目前支持几十个不同体系架构的开发板,如 evb4510、pxa255_idp、omap2420h4 等 |
common | U-Boot 命令实现代码目录 |
cpu | 包含了不同处理器相关的代码,按照不同的处理器进行分类,如 arm920t、 arm926ejs、i386、nios2 等 |
drivers | U-Boot 所支持外设的驱动程序。按照不同类型驱动进行分类如 spi、mtd、net 等等 |
fs | U-Boot 所支持的文件系统的代码。目前 U-Boot 支持 cramfs、ext2、fat、fdos、jffs2、reiserfs |
include | U-Boot 头文件目录,里面还包含各种不同处理器的相关头文件等,以 asm-体系架构这样的目录出现。另外,不同开发板的配置文件也在这个目录下:include/configs/开发板.h |
lib_xxx | 不同体系架构的一些库文件目录 |
net | U-Boot 所支持网络协议相关代码,如 bootp、nfs 等 |
tools | U-Boot 工具源代码目录。其中的一些小工具如 mkimage 就非常实用 |
二、U-Boot 启动简介
U-Boot 的启动可以分为第一个阶段和第二个阶段。第一阶段的代码主要用汇编语言写成,主要工作是初始化部分硬件(初始化内存、调试串口等)、搬移代码(从非易失储存器卡中把 U-boot 复制到 SDRAM)、准备 C 代码的执行环境;第二阶段代码主要用 C 语言写成,主要任务是初始化硬件、环境变量、部份驱动等,最后进入命令提示符。
下面对 U-Boot 的这两个启动阶段分别介绍:
1. 第一阶段
对于所有的处理器来说, U-Boot 的最初启动代码都在 cpu 目录下。对ARM926EJ-S 内核处理器来说,其最初始启动代码在 cpu/arm926ejs/目录下。该目录下有 start.S 文件。start.S 文件的代码是用汇编代码写成。所有使用ARM926EJ-S 内核的处理器都是由该文件代码启动的。
start.S 文件的执行流程如图2所示。
图2 第一阶段的执行流程
start.S 首先要初始化部分硬件,主要是要初始化 RAM(不同处理器需要初始化的硬件可能会有很大不一样),为下一步“复制第二阶段的代码到 RAM”做好准备。
U-Boot 第二阶段的代码必须要在 RAM 中执行,所以在第一阶段必须要把第二阶段的代码复制到 RAM 中。对不同的开发板而言,U-Boot 有各种不同的安装方式:有时安装在 Nor Flash、有的安装在 NAND Flash、有的安装在 SD/TF 卡等。为方便起见,这里只考虑 U-boot安装在 Nor Flash 和 NAND Flash 的情况:
-
U-Boot 安装在 Nor Flash
早期的 ARM 低端处理器大多只能从 0 地址启动。而 Nor Flash 支持直接的地址随机读取,所以 Nor Flash 的内部存储器的首地址安排为 0 地址,同时 U-Boot 也在 Nor Flash 的 0地址开始安装。
当处理器上电复位后,就在 Nor Flash 的 0 地址执行 U-boot 的第一阶段代码。在该段代码中,需要以_armboot_start 地址为起始,以 U-Boot 固件大小为长度,把 Nor Flash 上 U-Boot 第二阶段的代码复制到 RAM 的指定地址。
-
U-Boot 安装在 NAND Flash
由于 NAND Flash 容量大、价钱便宜,现在越来越多的 ARM 高端处理器支持从 NAND Flash 启动。这为 U-Boot 安装在 NAND Flash 提供了可能。
如果 U-Boot 安装在 NAND Flash 的首地址,并且处理器设置为 NAND Flash 方式启动(处理器的指定引脚输入高/低电平),那么当处理器上电复位后,将在 NAND Flash 的首地址把 U-Boot 前面的一段代码(大小一般为 4K)复制到 RAM 的指定地址,然后执行这段代码。 U-Boot 的第一阶段代码因此被执行。在该段代码中,会初始化 NAND Flash 控制器然后把整个 U-Boot 代码(自然包含了第二阶段代码)复制到 RAM 的指定地址。
2. 第二阶段
当第一阶段启动完成后,就会启动 start_armboot()函数,进入第二阶段的启动。
start_armboot()函数实现在 lib_arm/board.c 文件。 start_armboot()函数的执行流程如图3所示。
图3 start_armboot()函数的执行流程
U-Boot 的环境变量可以保存在 Nor Flash、NAND Flash、TF/SD、EEPROM 等设备中。U-Boot 在启动时会根据预先的设定在指定的设备的指定位置读取环境变量。如果环境变量不存在,U-Boot 则使用默认的环境。
U-Boot 的 start_armboot()函数在最后会执行 main_loop()函数。在 main_loop()函数中,会根据用户的响应而决定进入 U-Boot 命令行终端或根据 bootcmd 环境变量启动内核。
三、U-Boot 的驱动
U-Boot 使用了多种设备,每种设备都必须有相应的驱动程序支持。U-Boot 的驱动程序代码在 drivers 目录下,该目录下的内容如图4所示。 drivers 目录下的每个子目录都是包含一种类型设备的驱动代码。
图4 U-Boot 支持的设备驱动
U-Boot 的驱动代码力求简洁、够用。但部分驱动程序是从 Linux 移植过来的,如 MTD驱动。
四、U-Boot 的命令
U-Boot 的命令实现大多在 common 目录下。在该目录下命令的代码文件都是以“cmd_”开头的,如图5所示。每一个文件都是一个命令实现的代码文件,而且文件名和命令名称是相关的,例如 cmd_nand.c 是实现 nand 命令的文件。
图5 common 目录下的命令代码文件
U-Boot 的每个命令都是用一个 cmd_tbl_s 类型的结构体描述的,该结构体的定义如程序清单1所示。
程序清单1 cmd_tbl_s 结构的定义
struct cmd_tbl_s {
char *name; /* Command Name */
int maxargs; /* maximum number of arguments */
int repeatable; /* autorepeat allowed? */
int (*cmd)(struct cmd_tbl_s *, int, int, char *[]); /* Implementation function */
char *usage; /* Usage message (short) */
};
下面介绍 cmd_tbl_s 结构的部分成员:
name 成员为命令的名称。用户在 U-Boot shell 输入命令名称后,U-Boot 是通过该名称找到实现命令的 cmd_tbl_s 结构的。
maxargs 成员为命令的最大参数个数。
cmd 成员为命令实现命令的函数。
usage 成员为命令使用的帮助信息。
实现每个命令的 cmd_tbl_s 结构都静态编译到 U-Boot 固件的“.u_boot_cmd”数据段,从而形成数组,该数组的首元素指针为__u_boot_cmd_start。
五、U-Boot 的平台相关代码
U-Boot 的源码树里,与开发板相关的代码都在 board 目录下,图6所示。
图6 board目录的部分内容
在该目录里,大部分的子目录都是包含一款开发板的支持代码。当然也有部分处理器是同一厂商的开发板的安排在同一子目录,例如 freescales 目录下包含了飞思卡尔处理器的各种开发板的支持代码,如图7所示。
图7 freescales目录下的内容
其中 mx28_evk 目录存放 EPC-28x 的支持代码。进入 mx28_evk 目录可以看到有两个代码文件:lowlevel_init.S 和 mx28_evk.c。大多的数开发板支持代码文件的目录都有lowlevel_init.S 文件。该文件是用汇编代码写成,主要用于 U-Boot 启动的第一阶段时,初始化部份硬件的操作。mx28_evk.c 文件主要作用是初始化 i.MX28xx 处理器的部件 GPIO,以及实现对开发板上部份功能部件的复位操作(如网卡 PHY 芯片的复位)。
六、U-Boot 的配置文件
U-Boot 并不像 Linux 内核源码一样可以通过 make menuconfig 实现可视化的配置界面。所有开发板的配置文件都在<include/configs/>目录下,其中该目录下的 mx28_evk.h 文件就是EPC-28x 的配置文件。针对各开发板的配置工作只能在各自的配置文件中直接修改。
在配置文件中,所有配置选项都是以“config_”开头的宏。部分经常要修改的选项的说明如下:
- CONFIG_SYS_PROMPT
该选项是定义 U-Boot 的命令行提示符。该选项的设置示例如下:
#define CONFIG_SYS_PROMPT "MX28 U-Boot > "
那么当 U-Boot 进入命令行终端后,提示符如下:
MX28 U-Boot >
- CONFIG_BOOTDELAY
bootdelay 环境变量的默认值。该选项的设置示例如下:
#define CONFIG_BOOTDELAY 0
这表示 bootdelay 环境变量的默认值为 0 秒。
- CONFIG_BOOTCOMMAND
该选项是 bootcmd 环境变量的默认值。该选项的设置示例如下:
#define CONFIG_BOOTCOMMAND "run nand_boot"
这表示 U-Boot 启动后,若不进入 U-Boot 命令行终端,将默认执行“run nand_boot”命令。
- UBOOT_IMAGE_SIZE
该项是表示 U-Boot 固件的大小。在 U-Boot 启动的第一阶段会把 U-Boot 的第二阶段代码复制到 RAM 里面,若 U-Boot 是安装在 TF/SD 卡或 NAND Flash,复制代码的长度由UBOOT_IMAGE_SIZE 的值指定。所以当 U-Boot 固件的体积变量大时,则需要调整该值的
大小。
该项的设置示例如下:
#define UBOOT_IMAGE_SIZE 0x50000
该设置表示 U-Boot 的固件大小为 320K。
- MTDPARTS_DEFAULT
该项是设置 NAND Flash 的默认分区表。该项的设置示例如下:
#define MTDPARTS_DEFAULT "mtdparts=nandflash0:12m(bootloder)," \
"512k(reserve)," \
"512k(reserve)," \
"2m(bmp)," \
"512k(reserve)," \
"64m(rootfs)," \
"-(opt)"
该设置的 NAND Flash 分区表如图8所示,其中“-”符号表示使用剩余的空间。
图8 NAND FLASH 分区和说明
- CONFIG_EXTRA_ENV_SETTINGS
该项是设置自定义的默认环境变量。该选项的设置示例如下:
#define CONFIG_EXTRA_ENV_SETTINGS \
"kernel=uImage\0" \
"kernelsize=0x300000\0" \
"rootfs=rootfs.ubifs\0" \
"showbitmap=0\0" \
"kerneladdr=" "0x00200000\0" \
"kerneladdr2=" "0x00700000\0" \
省略„„
当 U-Boot 启动后,若在指定的非易性储存器中找不到环境变量,就使用该选项设置的默认自定义环境。
七、U-Boot Tools
U-Boot 提供了一些有用的小工具,在 U-Boot 源代码的 tools 目录下。这些工具都是在主机上使用的。编译完毕,可以将这些小工具复制到系统目录如/usr/bin 目录下,以方便使用。
其中的 mkimage 工具,在编译内核的时候需要用到,务必复制到系统/usr/bin 目录下(如使用 ZLG 网官提供的 ubuntu,不需这一步),或者将 U-Boot 的 tools 目录添加到系统目录中。该工具可以生成 U-Boot 格式的文件,以配合 U-Boot 使用。