Linux下使用交叉编译移植U-Boot到树莓派
0环境
Linux主机OS:Ubuntu14.04 64位,运行在VMware Workstation 10虚拟机
树莓派版本:raspberry pi 2 B型.
树莓派OS: Debian Jessie Raspbian Jessie
1树莓派的启动过程
树莓派1,2,3的启动过程大致相同,主要分为3个阶段:ROM上的GPU bootloader启动GPU,GPU启动CPU,CPU直接启动内核或通过u-boot启动内核.
由于树莓派涉及到GPU的东西不开源,移植u-boot到树莓派并不是真正意义上的bootloader,但是鉴于u-boot广泛的应用,还是很有学习的必要
树莓派启动过程:
2移植u-boot到Debian Jessie系统
最初想直接移植u-boot到Raspbian,尝试了多次都失败告终.google上u-boot启动raspberry pi大都是基于Debian Jessie,所以先照葫芦画瓢试一把.
移植u-boot到树莓派参考例程
(1)最全面的RPi u-boot例程RPi U-Boot
(2)基于RPi2的例程Booting a Raspberry Pi2, with u-boot and HYP enabled
(3)基于RPi2,提供现成文件的例程Raspberry Pi 2 – Debian Jessie and U-Boot
(4)基于mainline u-boot的例程How to compile mainline u-boot for Raspberry Pi ?
MicroSD卡烧写镜像:debian jessie下载地址
Ubuntu主机上u-boot使用Mainline版本,官网源码 亚马逊下载地址
Ubuntu主机上文件位置如下
家目录(/root)下u-boot-2016.09文件夹是解压后的u-boot
家目录(/root)下script_u-boot文件夹是自己写的环境配置,脚本
u-boot-2016.09文件夹如下,可以先读读README
script_u-boot文件夹内如下图,从左到右是scr配置文件,环境配置文件,生成u-boot.bin文件,生成scr文件
env_gnueabihf_mkimage文件代码如下
#添加树莓派的交叉编译工具链路径(主机是64位) export PATH=$PATH:/root/tools-master/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin #指定编译目标架构为arm,编译器为PATH路径中的交叉编译器 export ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
树莓派交叉编译工具链地址https://github.com/raspberrypi/tools
树莓派交叉编译可以参考Linux主机上实现树莓派的交叉编译及文件传输,远程登陆
在后续操作之前先source一下这个文件使配置生效,关闭终端或者重新登陆Ubuntu需要再次source
用echo查看变量,注意使用tab自动补全路径
make_ubootbin文件代码如下
#从脚本文件夹切换到u-boot文件夹下 cd /root/u-boot-2016.09 #配置适用于树莓派2的u-boot make rpi_2_defconfig #编译 make all #返回脚本文件夹 cd /root/script_u-boot 切换路径是因为执行这个脚本是在script_u-boot文件夹,而make命令执行Makefile是在u-boot-2016.09文件夹,最后切回路径方便后续的source 这里make rpi_2_defconfig是针对树莓派2板,其它版本树莓派的make config参考前文的移植u-boot到树莓派参考例程(1)(4) 执行make_ubootbin无报错 在u-boot-2016.09文件夹下生成了u-boot.bin 把debian jessie的SD卡通过读卡器插到电脑,注意先选中虚拟机的Ubuntu系统,Ubuntu会自动读取(mount)SD卡 rootfs(根文件系统)分区: firmware(debian jessie下的启动分区): 关于启动分区config.txt bootcode.bin cmdline.txt start.elf kernel7.img等文件,参考前文的树莓派启动过程 至此可以把u-boot.bin拷到sd卡的firmware(对于debian jessie系统) 然后在config.txt添加 kernel=u-boot.bin
指定用u-boot.bin启动内核kernel7,config.txt是内核的配置文件,类似电脑的BIOS配置
配置内核的方法:
一种方法是在u-boot阶段手动输入命令,而mainline版本的u-boot不支持usb输入,尝试过例程(1)中的Stephen Warren版本,也无法输入(问题还有待调查)
另一种是把u-boot中输入的命令写到一个脚本文件,通过mkimage命令将这个脚本生成.scr镜像,然后放到启动分区,u-boot会自动读取脚本来启动内核,这样更简单更容易修改,但是不利于调试错误信息
用第一种方法可以拔出SD卡,在树莓派上配置内核启动,注意在u-boot阶段只能通过HDMI外接显示屏或者串口来查看输出信息.关于串口可以参考RPi Serial Connection
用第二种方法是在Ubuntu主机上生成boot.scr镜像,先写一个配置文件:在script_u-boot文件夹下新建configure_scr_file,内容如下
#设置环境为树莓派2 setenv machid 0x00000c42 #设置打印信息,允许HDMI,允许串口,设置根文件系统路径和类型 setenv bootargs "earlyprintk console=tty0 console=ttyAMA0 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait noinitrd" #保存环境配置 saveenv #载入内核镜像到MMC0的第一分区 fatload mmc 0:1 ${kernel_addr_r} kernel7.img #启动内核 bootz ${kernel_addr_r}
以上命令的语法都是u-boot软件规定,关于命令的细节可以参考RPi U-Boot 官方文档U-Bootdoc
然后新建一个脚本make_ubootscr生成scr镜像,make_ubootscr内容如下
#生成boot.scr镜像文件 mkimage -A arm -O linux -T script -C none -a 0x00000000 -e 0x00000000 -n "RPi2 Boot Script" -d /path/to/script /boot/firmware/boot.scr
/path/to/script是configure_scr_file的路径,替换后如下
mkimage -A arm -O linux -T script -C none -a 0x00000000 -e 0x00000000 -n "RPi2 Boot Script" -d /root/script_u-boot/configure_scr_file /boot/firmware/boot.scr
source报错,提示未安装mkimage
命令找不到通常是未安装软件,或者没添加路径,mkimage应该是包含在u-boot软件中的,由于之前用过树莓派交叉编译工具链的经验,在u-boot-2016.09文件夹的tools文件夹找到了mkimage程序
更通用的是用find命令查找
find 查找路径 -name 文件名
看来是没有添加mkimage的路径到环境变量,只需在env_gnueabihf_mkimage添加路径然后source
env_gnueabihf_mkimage修改如下
export PATH=$PATH:/root/tools-master/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin:/root/u-boot-2016.09/tools export ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
提示路径不存在
这时就需要了解这条mkimage命令的具体含义了,参考mkimage - Generate image for U-Boot
/boot/firmware/boot.scr是生成boot.scr文件的路径,如果在树莓派上直接操作这个路径就是启动分区,但是我是在Ubuntu主机操作,SD卡是挂载到Ubuntu主机的路径被改变了
查看块设备可以用命令
lsblk
sdb就是SD卡,sdb1是firmware启动分区,sdb2是rootfs文件系统分区
事实上插入SD卡时Ubuntu自动把SD卡mount到了主机的/media路径,所以前面才能对u-boot.bin直接复制粘贴操作
但是想把SD卡的第一分区挂载到其它路径,比如主机的/mnt文件夹下,应该
mount /dev/sdb1 /mnt
注意设备的实际路径和挂载后路径的区别,/dev/xxx才是实际的设备路径
在debian jessie的树莓派上查看SD卡路径如下
这是因为debian jessie没有自动挂载功能
可以把boot.scr直接生成到firmware下(先在Ubuntu插好SD卡)
mkimage -A arm -O linux -T script -C none -a 0x00000000 -e 0x00000000 -n "RPi2 Boot Script" -d /root/script_u-boot/configure_scr_file /media/boot/firmware/boot.scr
更推荐生成在其它目录(比如u-boot-2016.09文件夹)再拷到SD卡,最终改为如下,-n是生成的文件名
mkimage -A arm -O linux -T script -C none -a 0x00000000 -e 0x00000000 -n boot.scr -d /root/script_u-boot/configure_scr_file /root/u-boot-2016.09/boot.scr
成功生成boot.scr
在把u-boot.bin boot.scr拷到SD卡的firmware以后,确认config.txt添加了kernel=u-boot.bin就可以拔出SD卡启动树莓派2了
启动过程如下
进入登陆界面
登陆名(login):root
密码(password):debian
登录成功,至此在debian jessie上的u-boot移植完成
在主机上交叉编译生成boot.bin,也可以不添加环境变量ARCH,CROSS_COMPILE,直接在make语句指定编译器
make_ubootbin可以改为如下
cd /root/u-boot-2016.09 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- rpi_2_defconfig make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4 cd /root/script_u-boot
-j4是采用四核处理器四线程编译,取决于主机CPU WIN7下查看CPU核心数
3移植u-boot到Raspbian Jessie系统
有了前面的尝试,后面的就水到渠成了
如果直接把刚才生成的u-boot.bin boot.scr拷到raspbian,在config.txt添加kernel=u-boot.bin
启动后停留在starting kernel...
信息显示kernel7已经通过boot.scr读取了,说明问题出在启动内核之后的部分
对比一下debian jessie和raspbian jessie的分区,文件系统都一样,就是启动分区有差别
debian jessie的启动分区
raspbian jessie的启动分区
发现raspbian多了一个kernel.img,几个.dtb文件,overlay里面也是.dtb文件
参考RPi U-Boot后感觉需要加载dtb(Device Tree binary)
修改boot.scr的配置文件(configure_scr_file)的内容如下
setenv machid 0x00000c42 #添加变量fdtfile的值为bcm2709-rpi-2-b.dtb setenv fdtfile bcm2709-rpi-2-b.dtb setenv bootargs "earlyprintk console=tty0 console=ttyAMA0 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait noinitrd" saveenv fatload mmc 0:1 ${kernel_addr_r} kernel7.img #载入fdtfile的值 fatload mmc 0:1 ${fdt_addr_r} ${fdtfile} bootz ${kernel_addr_r} - ${fdt_addr_r}
这里添加bcm2709-rpi-2-b.dtb是因为使用树莓派2,如果是其它版本酌情修改
然后source生成boot.scr
source make_ubootbin
将新的boot.scr拷到boot分区,u-boot.bin和之前完全相同,config.txt添加kernel=u-boot.bin
主机上拔出SD卡,启动树莓派
自动登录进入桌面
至此u-boot在raspbian jessie上移植完成。