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/
⏩ 半导体厂商uboot代码
移植uboot时一般不会直接用 uboot 官方的源码的,官方的源码是给半导体厂商准备的,半导体厂商会根据自家的芯片,维护自己芯片对应的uboot。NXP维护的的uboot地址:
https://github.com/Freescale/u-boot-fslc
⏩ 开发板厂商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的目录,左侧为未编译的源码,右侧为编译后的源码(编译方法见本文下一小节)
需要关注或了解的文件夹或文件如下:
⏩ 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内核了
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