1.U-Boot简介

Linux系统要启动就必须需要一个bootloader程序,也就是说芯片上电后先运行一段bootloader程序,这段bootloader程序会先初始化DDR等外设,然后将Linux内核从flash(NAND/NOR FLASH/SD/MMC等)拷贝到DDR中,最后启动Linux内核

bootloader和Linux内核的关系跟PC上的BIOS和Windows的关系一样,bootloader就相当于BIOS。目前有很多现成的bootloader软件可用,比如U-Boot、vivi、RedBoot等,其中以U-Boot使用最为广泛

uboot(Universal Boot Loader),是一个遵循GPL协议的开源软件,是一个裸机代码,可以看作是一个裸机综合例程。

⏩ uboot官网代码

uboot官网上下载的是最原始的uboot源码。uboot官网下载地址如下:

https://www.denx.de/wiki/U-Boot/

U-Boot 浅析_uboot

⏩ 半导体厂商uboot代码

移植uboot时一般不会直接用 uboot 官方的源码的,官方的源码是给半导体厂商准备的,半导体厂商会根据自家的芯片,维护自己芯片对应的uboot。NXP维护的的uboot地址:

https://github.com/Freescale/u-boot-fslc

U-Boot 浅析_bootloader_02

⏩ 开发板厂商uboot代码

开发板厂商做的开发板需要修改芯片厂商官方的uboot,使其支持开发板厂商生产的评估板。本文使用的正点原子i.MX6ULL开发板的uboot下载地址:

http://www.openedv.com/docs/boards/arm-linux/zdyz-i.mx6ull.html

2.U-Boot源码分析

这里使用开发板厂商提供的uboot源码( uboot-imx-2016.03-2.1.0-g8b546e4.tar.bz2)来对uboot工程目录进行分析:以EMMC版的核心板为例,以下是uboot的目录,左侧为未编译的源码,右侧为编译后的源码(编译方法见本文下一小节)

U-Boot 浅析_bootloader_03

需要关注或了解的文件夹或文件如下:

⏩ arch文件夹:存放与架构有关的文件,这里只关注arch/arm文件夹即可

  • mach开头的文件夹跟具体的设备有关
  • cpu文件夹里是和cpu架构有关的

⏩ board文件夹:和具体的板子有关的,打开freescale文件夹,freescale芯片的板子都在此文件夹下

  • mx6ul开头的,表示使用IMX6UL芯片的板子
  • mx6ull开头的,表示使用IMX6ULL芯片的板子
  • mx6ullevk是NCP官方的IMX6ULL开发板

⏩ configs文件夹:存放uboot配置文件,一般半导体或开发板厂商会制作好一个配置文件,供用户在此基础上进行修改,配置文件统一命名为“xxx_defconfig”,xxx表示开发板名字

使用"make xxx_defconfig"命令,即可配置uboot

⏩ .u-boot.xxx_cmd文件:是一系列编译生成的命令文件

#该变量的作用:拷贝一份u-boot-nodtb.bin文件,并重命名为u-boot.bin
cmd_u-boot.bin := cp u-boot-nodtb.bin u-boot.bin
#用到了arm-linux-gnueabihf-objcopy来将ELF格式的u-boot文件转换为二进制的u-boot-nodtb.bin
cmd_u-boot-nodtb.bin := arm-linux-gnueabihf-objcopy --gap-fill=0xff 
-j .text......-O binary u-boot u-boot-nodtb.bin
#用到了arm-linux-gnueabihf-ld.bfd链接工具,将各个built-in.o文件链接在一起形成u-boot文件
cmd_u-boot := arm-linux-gnueabihf-ld.bfd ......-Map u-boot.map
#用到了工具tools/mkimage,IVT/DCD等数据保存在了文件mximage.cfg.cfgtmp中
#tools/mkimage工具就是读取IVT/DCD等数据并添加到u-boot.bin头部,并生成u-boot.imx
cmd_u-boot.imx := ./tools/mkimage -n board/freescale/mx6ull_alientek_emmc/imximage.cfg.cfgtmp 
-T imximage -e 0x87800000 -d u-boot.bin u-boot.imx

⏩ Makefile文件:顶层Makefile文件,Makefile是支持嵌套的,也就是顶层Makefile可以调用子目录中的Makefile文件

⏩ u-boot.xxx文件:一系列文件,其含义如下

  • u-boot:编译出来的ELF格式的uboot镜像文件
  • u-boot.bin:编译出来的二进制格式的uboot可执行镜像文件
  • u-boot.cfg:uboot的另外一种配置文件
  • u-boot.imx:u-boot.bin添加头部信息后的文件
  • u-boot.lds:链接脚本
  • u-boot.map:uboot映射文件,可查看某个函数被链接到哪个地址上了
  • u-boot.srec:S-Record格式的镜像文件
  • u-boot.sym:uboot符合文件
  • u-boot-nodtb.bin:和u-boot.bin一样,u-boot.bin是u-boot-nodtb.bin的复制文件

⏩ .config文件:uboot配置文件,使用命令"make xxx_defconfig"配置uboot后就会自动生成

⏩ README:描述了uboot的详细信息,包括uboot该如何编译、uboot中各文件夹的含义、相应的命令等

3.U-Boot初次编译

本文以正点原子i.MX6ULL阿尔法开发板实验开发板,核心板为512MB(DDR3) + 8GB(EMMC),进行学习实践

⏩ 在Ubuntu中安装ncurses库,以防止编译报错

sudo apt-get install libncurses5-dev

⏩ 创建相应目录,将开发板厂商提供的uboot源码拷贝至此目录中

mkdir /home/andyxi/linux/uboot
cd /home/andyxi/linux/uboot
cp uboot-imx-2016.03-2.1.0-g8b546e4.tar.bz2 .

⏩ 解压uboot源码

tar -vxjf uboot-imx-2016.03-2.1.0-g8b546e4.tar.bz2

⏩ 使用以下命令编译uboot

#ARCH=arm表示设置目标为arm架构,相当于make distclean,清除工程
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
#配置uboot,配置文件为mx6ull_14x14_ddr512_emmc_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_14x14_ddr512_emmc_defconfig
#V=1用于设置编译过程中的信息输出级别,相当于make -j12,即使用12核来编译uboot
make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j12 
#每次编译uboot都需要输入一长串命令
#为了简单起见,建立一个shell脚本文件,将这些命令写到shell脚本里
#执行shell脚本即可完成编译工作
#新建mx6ull_alientek_emmc.sh脚本文件
##########################################################################
#!/bin/bash
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_14x14_ddr512_emmc_defconfig
make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j12 
##########################################################################
#通过命令“./mx6ull_alientek_emmc.sh”编译uboot

4.U-Boot烧写与启动

uboot编译好后就可以烧写到开发板上使用了,这里使正点原子提供的烧写工具imxdownload

⏩ 将imxdownload烧写工具拷贝到文件夹中,并给与可执行权限

chmod 777 imxdownload

⏩ 使用imxdownload软件将bin文件下载到SD卡中

./imxdownload u-boot.bin /dev/sdb

⏩ 烧写成功后,插入SD卡,使用USB线将USB_TTL和电脑相连,打开串口工具后复位开发板。在“Hit any key to stop autoboot”倒计时结束之前,按下键盘上的回车键,就会进入uboot命令行模式;否则uboot就会使用默认参数来启动Linux内核了

U-Boot 浅析_imx6ull_04

5.U-Boot常用命令

进入uboot命令行模式后输入help或 ?,回车后即可查看当前uboot所支持的命令;使用 help cmd 或 ? cmd 命令还可以查看命令的具体用法

⏩ 信息查询命令

bdinfo			#用于查看板子信息
printenv		#用于输出环境变量信息
version			#用于查看uboot版本号

⏩ 环境变量操作命令

=> setenv bootdelay 5  			#将环境变量bootdelay改为5
=> saveenv						#保存修改后,uboot倒计时变为5秒
Saving Environment to MMC...	#保存过程提示...
Writing to MMC(0)...done		#保存到MMC(0)中,即SD卡中
################################################################
#有时修改的环境变量值可能会有空格,此时需要用单引号括起来
=> setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw'
=> saveenv			#保存修改
#上面命令相当于设置了"console=...","root=...","rootwait","rw"四组值
################################################################
=> setenv author andyxi		#新建环境变量author,其值为andyxi
=> saveenv					#保存修改
=> setenv author 			#给环境变量author赋空值,即删除该环境变量
=> saveenv					#保存修改

⏩ 内存操作命令

md	#用于显示内存值
nm	#用于修改指定地址的内存值
mm	#用于修改指定地址的内存值,与nm命令的区别是,mm修改内存值时地址会自增
mw	#用于使用一个指定的数据填充一段内存
cp	#拷贝命令,用于将DRAM中的数据从一段内存拷贝到另一段内存中
cmp	#比较命令,用于比较两段内存的数据是否相等

⏩ 网络操作命令

=> setenv ipaddr 192.168.10.50  	#开发板IP地址
=> setenv ethaddr b8:ae:1d:01:00:00	#开发板MAC地址
=> setenv gatewayip 192.168.10.1	#网关地址
=> setenv netmask 255.255.255.0		#子网掩码
=> setenv serverip 192.168.10.100	#服务器IP地址(即Ubuntu主机地址)
=> saveenv	
#######################################################################
ping		#开发板的网络是否能使用
dhcp 		#用于从路由器获取IP地址,前提是开发板与路由器连接
nfs 		#网络文件系统,可以在计算机之间通过网络来分享资源	
tftp		#通过使用TFTP协议网络下载东西到DRAM中

⏩ EMMC和SD卡操作命令

mmc info  		#输出MMC设备信息
mmc read		#读取MMC中的数据
mmc write		#向MMC中写入数据
mmc rescan		#扫描MMC设备
mmc part		#列出MMC设备的分区
mmc dev			#切换MMC设备
mmc list		#列出当前有效的所有MMC设备
......

⏩ FAT格式文件系统操作命令

fatinfo		#用于查询指定MMC设备分区的文件系统信息
fatls		#用于查询FAT格式设备的目录和文件信息
fstype		#用于查看MMC设备某个分区的文件系统格式
fatload		#用于将指定的文件读取到DRAM中
fatwrite	#用于将DRAM中的数据写入到MMC设备中

⏩ NAND操作命令

nand info	#用于打印NAND Flash信息
nand device	#用于切换NAND Flash
nand erase	#用于擦除NAND Flash
nand write	#用于向指定地址写入指定的数据
nand read	#用于从NAND Flash中指定地址读取指定大小的数据到DRAM中

⏩ BOOT操作命令

bootz		#用于启动zImage镜像文件
bootm		#用于启动uImage镜像文件
boot		#用于启动Linux系统的,该命令会读取环境变量bootcmd来启动Linux
bootcmd		#环境变量保存着引导命令(启动的命令集合)
#####################################################################
#例如使用tftp命令从网络启动Linux
tftp 80800000 zImage					#下载zImage
tftp 83000000 imx6ull-14x14-emmc-7-1024x600-c.dtb	#下载设备树
bootz 80800000 - 83000000				#启动Linux
#以上实例可以通过设置bootcmd,保存后直接使用boot命令来实现
setenv bootcmd 'tftp 80800000 zImage;
tftp 83000000 imx6ull-14x14-emmc-7-1024x600-c.dtb;
bootz 80800000 - 83000000'
saveenv
boot

⏩ 其他常用命令

reset 	#复位重启
go		#用于跳到指定的地址处执行应用
run		#用于运行环境变量中定义的命令
		#例如通过“run bootcmd”来运行bootcmd中的启动命令
mtest	#简单的内存读写测试命令,可以测试开发板上的DDR