BeagleBone Black 从零到一 (2 MLO、U-Boot) 转
文章原址:jexbat.com/categories/BeagleBone/
什么是 U-Boot
熟悉嵌入式开发的应该都听过它,U-boot 就是启动系统前的一段引导程序,虽然是引导程序,但是功能非常强大。
这一篇主要讲解如何从无到有运行 U-Boot,关于 U-Boot 引导 Linux 的部分放在另外一篇文章讲解。
U-Boot 之前的版本以版本号命名如:0.1.0, 0.2.0 这几年改为了以时间和日期命名:U-Boot 2016.03。
使用 git 获得 U-Boot 的源码:
1 |
git clone git://git.denx.de/u-boot.git |
目前我使用的是 2016.02 的版本。
MLO 及其启动过程
上一篇文章,我们了解了 BeagleBone 有个 SPL 过程,就在这个时候读取 MLO 文件,MLO 文件其实是个精简版的 U-Boot,也是由 U-Boot 生成,但是功能有限,只初始化了部分资源如 DDR,然后启动 U-Boot。
MLO 文件是如何编译出来的
分析 MLO 的编译过程之前需要知道编译原理和 Makefile 等相关知识。
我们先找找 Makefile 看看能不能找到什么。建议使用 Sublime 编辑器。用全局查找功能查找 MLO 关键字。
找到 u-boot/scripts/Makefile.spl 文件 117行:
u-boot/scripts/Makefile.spl
1 |
MLO MLO.byteswap: $(obj)/u-boot-spl.bin FORCE |
可以看到 MLO 文件是由 u-boot-spl.bin 文件通过 mkimage 命令生成的。
再查到 u-boot/Makefile 文件 1310 行:
u-boot/Makefile
1 |
spl/u-boot-spl.bin: spl/u-boot-spl |
u-boot-spl.bin 文件是还是由 u-boot/scripts/Makefile.spl 文件生成。
文件 u-boot/scripts/Makefile.spl 168 行 定义了 u-boot-spl.bin 的生成:
u-boot/scripts/Makefile.spl
1 |
ifeq ($(CONFIG_SPL_OF_CONTROL),y) |
因为 SPL_BIN 在 第32行 定义为 u-boot-spl:
u-boot/scripts/Makefile.spl
1 |
ifeq ($(CONFIG_TPL_BUILD),y) |
由 168 行 上面的定义可以知道 u-boot-spl.bin 和 u-boot-spl-nodtb.bin 有关系。
接着查找到第223行:
u-boot/scripts/Makefile.spl
1 |
$(obj)/$(SPL_BIN)-nodtb.bin: $(obj)/$(SPL_BIN) FORCE |
u-boot-spl-nodtb.bin 是通过 objcopy 命令由 u-boot-spl 生成。
再看第246行:
u-boot/scripts/Makefile.spl
1 |
$(obj)/$(SPL_BIN): $(u-boot-spl-init) $(u-boot-spl-main) $(obj)/u-boot-spl.lds FORCE |
所以u-boot-spl 是由 u-boot-spl.lds 链接文件生成的 ,但是目录下面有几个u-boot-spl.lds文件,到底是哪个 lds 文件呢,上面是 $(obj)/u-boot-spl.lds, obj 在 1310 行 编译 u-boot-spl.bin 的时候赋值为 obj=spl,所以我们需要看 u-boot/spl/u-boot-spl.lds 这个文件,但是如果你之前没有编译过这个文件是没有的。这个文件是如何生成的呢?我们稍后再看,先看 lds 文件的内容:
u-boot/spl/u-boot-spl.lds
1 |
MEMORY { .sram : ORIGIN = 0x402F0400, LENGTH = (0x4030B800 - 0x402F0400) }
|
链接文件里面说明了内存布局,arch/arm/cpu/armv7/start.o 代码段都放在 SRAM 中,所以 arch/arm/cpu/armv7/start.S 就是我们要找的东西了。
lds 链接文件的生成
u-boot/spl/u-boot-spl.lds 这个文件的生成在 u-boot/scripts/Makefile.spl 有解释:
u-boot/scripts/Makefile.spl
1 |
$(obj)/u-boot-spl.lds: $(LDSCRIPT) FORCE |
LDSCRIPT 的定义:
u-boot/scripts/Makefile.spl
1 |
# Linker Script |
可见 Makefile.spl 文件中先是判断有没有指定的 lds 文件,如果没有指定的,就查找 board 文件夹中目标板目录下面有没有 lds 文件,如果没有就查找相应的 cpu 目录,因为我们目标器件是 am335x,所以发现有 u-boot/arch/arm/cpu/armv7/am33xx/u-boot-spl.lds 再通过 cpp_lds 命令编译成,cpp_lds 是一组命令的集合,具体定义还是在 Makefile.spl 文件中,我们查看 u-boot/arch/arm/cpu/armv7/am33xx/u-boot-spl.lds 也发现 MLO 文件代码是在 start.S 文件中。
MLO 程序分析
查看 start.S 分析下 MLO 程序具体的执行流程,MLO 的 makefile 会根据 CONFIG_SPL_BUILD 编译不同的源文件,同样的在源码内也通过 CONFIG_SPL_BUILD 控制不同的代码执行,前面一部分 MLO 文件和 U-Boot 是类似的,进入到 _main 函数中两个程序的功能就开始出现差异了:
1 |
reset //(arch/arm/cpu/armv7/start.S) |
当 U-Boot 重定位好代码、向量表之后,运行 board_init_r 函数,此函数会调用 init_sequence_r 列表里面的函数初始化各种外设驱动,最后在 main_loop() 函数中运行,U-Boot 有个 bootdelay 延时启动,如果不手动停止 U-Boot 会自动运行 bootcmd 包含的命令。
内核引导这部分放在另外一篇文章详细讲解。
U-Boot 编译
编译 U-Boot
编译 U-Boot 前我们需要安装交叉编译器:
1 |
# sudo apt-get install gcc-arm-linux-gnueabihf |
下载 U-Boot 源码:
1 |
# git clone git://git.denx.de/u-boot.git |
因为 U-Boot 官方已经支持了 Beaglebone Black 所以配置文件也已经自带了,编译输入如下命令:
1 |
# make distclean |
片刻后会生成 MLO 和 u-boot.img 文件。
配置 U-Boot 参数
有两种方式可以配置 U-Boot 的一些参数,分别是 uEnv.txt 和 boot.src 文件。
U-Boot 启动的时候会在启动分区寻找这两个文件。
boot.scr: This file is a U-Boot script. It contains instructions for U-Boot. Using these instruction, the kernel is loaded into memory, and (optionally) a ramdisk is loaded. boot.scr can also pass parameters to the kernel. This file is a compiled script, and cannot be edited directly. In some cases, boot.scr loads further instructions and configuration parameters from a text file.
uEnv.txt: A file with additional boot parameters. This file can be read by boot.scr, or by the boot sequence if there is no script file. uEnv.txt is a regular text file that can be edited. This file should have Unix line ending, so a compatible program must be used when editing this file.
U-Boot 启动的时候如果不打断会调用 bootcmd 包含的命令来执行,通常 bootcmd 会调用 bootscript 脚本也就是boot.scr 里面的命令进行执行, boot.scr 通常也会先读取 uEnv.txt 确定额外参数,因为 boot.src 文件必须通过 boot.cmd 文件编译而来, uEnv.txt 则是可以任意编辑,这样可配置性就大大提高了。如果没有 boot.src 文件,U-Boot 有默认配置的 bootcmd 命令。
在 Beagelbone Black 中我们不需要额外的 boot.scr 文件,用默认的命令即可,默认的命令为:
1 |
#define CONFIG_BOOTCOMMAND \ |
run distro_bootcmd 最终会调用 run mmcboot 命令加载 uEnv.txt 文件,并且会运行 uEnv.txt 文件里面 uenvcmd 指代的命令。
uEnv.txt 从网络启动例子:
1 |
console=ttyO0,115200n8 |
制作 U-Boot 的 SD 启动卡
制作 SD 启动卡之前首先需要为 SD 卡分区, ROM Code 启动的时候如果是从 MMC 设备加载启动代码,ROM Code 会从第一个活动分区寻找名为 “MLO” 的文件,并且此分区必须为 FAT文件系统。所以制作 U-Boot 的启动卡只需要一个带有 MLO 和 U-Boot 镜像的 FAT 格式的 SD 卡,如果需要启动 Linux 内核还需要别的分区,我们以后再讲。
有两种方式可以制作包含 U-Boot 的可启动的 SD 卡,一种是用 RAW Mode 的方式,还有一种是用 FTA 的方式。
RAW Mode 和烧写方式在这篇文章里面有讲:解析 BeagleBone Black 官方镜像。
FTA 模式下只要建立一个 FTA 分区再把 MLO 和 uboot.img 文件拷贝进去即可。
我是使用的 USB 读卡器,插入后 Linux /dev/ 目录会显示 /dev/sd* 设备,我这里多出两个设备分别显示 /dev/sdb 和 /dev/sdb1 ,其中 /dev/sdb 表示一整个物理磁盘, /dev/sdb1 表示的是具体的分区。
使用命令 sudo fdisk /dev/sdb 管理磁盘:
a : toggle a bootable flag(设置或取消启动表示)
b : edit bsd disklabel(编辑 bsd disklabel)
c : toggle the dos compatibility flag
d : delete a partition (删除一个分区)
l : list known partition types (列出已知的分区类型)
m : print this menu (打印次列表)
n : add a new partition (增加一个新分区)
o : create a new empty DOS partition table (建立一个新的空 DOS 分区表)
p : print the partition table (打印分区表)
q : quit without saving changes (不保存退出)
s : create a new empty Sun disklabel
t : change a partition’s system id
u : change display/entry units
v : verify the partition table (验证分区表)
w : write table to disk and exit (把分区表写入磁盘)
x : extra functionality (experts only) (额外的功能)
新建启动分区:
1 |
Command (m for help): p Disk /dev/sdb: 7746 MB, 7746879488 bytes |
建立好新的分区之后需要命名并格式化:
1 |
# sudo mkfs.vfat -F 32 -n boot /dev/sdb1 |
格式化之后挂载磁盘并把 MLO 文件和 u-boot.img 文件拷贝进去:
1 |
# sudo mount /dev/sdb1 /media/jg/boot |
接着把 SD 卡插入 Beaglebone Black 并且按着 S2 按钮上电,从串口打印出的信息我们可以看到 U-Boot 已经可以正常启动了:
1 |
U-Boot SPL 2016.03-rc2-00084-g595af9d (Feb 29 2016 - 22:21:20) |
启动之后,前面一段打印信息是 MLO 程序打印出来的,读取 U-Boot 之后开始运行完整的 U-Boot,之后程序扫描各个设备读取 boot.scr 和 uEnv.txt 文件,接着再读取是否有 Linux 内核可以运行。
参考资料
- Beaglebone Black——制作自己的SD启动卡
- U-Boot on BeagleBone Black
- AM335x U-Boot User’s Guide
- Pandaboard bootload(uboot) 启动流程探究
- u-boot启动流程
BeagleBone Black 从零到一 (2 MLO、U-Boot) 转的更多相关文章
- am335x uboot2016.05 (MLO u-boot.img)执行流程
am335x的cpu上电后,执行流程:ROM->MLO(SPL)->u-boot.img 第一级bootloader:引导加载程序,板子上电后会自动执行这些代码,如启动方式(SDcard. ...
- BeagleBone Black的内核移植-从零开始制作镜像
很多年前做的针对BeagleBone Black开发板的镜像制作,因为当时涉及到非标准化的,所以把基本的kernel.uboot和跟文件系统rootfs都做了一遍,文中只做移植,不作定制化的修改. 如 ...
- Beaglebone Black教程BeagleBone Black安装最新系统映像
Beaglebone Black教程BeagleBone Black安装最新系统映像 BeagleBone Black安装最新系统映像 Beaglebone Black虽然已经预装了Debian操作系 ...
- Create a Bootable MicroSD Card
http://gumstix.org/create-a-bootable-microsd-card.html Create a Bootable MicroSD Card Beginners Note ...
- springboot系列一、springboot产生背景及介绍
一.为什么用Springboot 长期以来 Java 的开发一直让人所诟病: ·Java 项目开发复杂度极其高: · Java 项目的维护非常困难: · 在云时代如何实现项目的快速部署以及快速启动: ...
- 适合 Java 新手的开源项目集合——在 GitHub 学编程
作者:HelloGitHub--老荀 当今互联网份额最大的编程语言是哪一个?是 Java!这两年一直有听说 Java 要不行了.在走下坡路了.没错,Java 的确在走下坡路,未来的事情的确不好说,但是 ...
- Beaglebone Black – 连接 GY-91 MPU9250+BMP280 九轴传感器(2)
这次用 SPI.BBB 有两套 SPI 接口可用,两套都是默认 disable,需要用 overlay 方式启用,即: echo BB-SPIDEV0 > /sys/devices/bone_c ...
- Beaglebone Black–I2C 接 BMP280 获取当前温度
我有两个含温度传感的模块,一个是AOSONG 奥松电子的 AM2320 温度湿度,另一个是九轴里面的 Bosch BMP280.由于 AM2320 用 I2C MODBUS,直接用 I2C Tools ...
- 菜鸟学Struts2——零配置(Convention )
又是周末,继续Struts2的学习,之前学习了,Struts的原理,Actions以及Results,今天对对Struts的Convention Plugin进行学习,如下图: Struts Conv ...
随机推荐
- Swift 中 insetBy(dx: CGFloat, dy: CGFloat) -> CGRect 用法详解
insetBy(dx: CGFloat, dy: CGFloat) -> CGRect 点击头文件进去 可以发现它是返回的一个CGRect insetBy方法是CGRect 的一个方法 dx后面 ...
- selenium之 chromedriver与chrome版本映射表(更新至v2.33)
看到网上基本没有最新的chromedriver与chrome的对应关系表,便兴起整理了一份如下,希望对大家有用: chromedriver版本 支持的Chrome版本 v2.33 v60-62 v2. ...
- LeetCode(103): 二叉树的锯齿形层次遍历
Medium! 题目描述: 给定一个二叉树,返回其节点值的锯齿形层次遍历.(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行). 例如:给定二叉树 [3,9,20,null,nul ...
- 调皮的HR
如图:笔试题 # -*- coding: utf- -*- """ Created on Thu Apr :: @author: weilong "" ...
- python 之 列表与字典
1.4 列表与字典 列表与字典,这两种类型,都是各种类型的集合,以列表为例,如果列表中包含列表,就形成嵌套. 这两种类型几乎是所有python脚本的主要工作组件 . 这种结构信息是可变的可修改的.不像 ...
- 滴水穿石-01JAVA和C#的区别
排名不分先后,想到哪写到哪 1:数组的定义格式不同 java定义: 方式1: ] ; 方式2: ] ; C#中只有方式1 java有两种,C#只有一种 2:继承的实现关键字不同,同时java中实现接口 ...
- MySQL 复制表到另一个表
1.复制表结构及数据到新表 create table 新表 select * from 旧表 2.只复制表结构到新表 方法1:(低版本的mysql不支持,mysql4.0.25 不支持,mysql5已 ...
- 部署Asp.net core & Nginx,通过nginx转发
部署Asp.net core & Nginx,通过nginx转发 CentOS 7 x64 1.vs2017 建立Asp.net core项目,并发布到目录 2.通过FTP工具,将程序copy ...
- cqoi2018
题解: 很多模板题 第一次写莫队还比较顺利 除了把排序的cmp写错..(还第一次遇到) 这题分块也可以 先预处理出g[i][j]代表前i个块,颜色为j的有多少种 f[i][j]表示i-j的块能构成多少 ...
- java中String和StringBuffer的区别
前言 String和StringBuffer本质上都是修饰字符串的只是含义不同 StringBuffer叫做字符串缓冲区 首先看下string类的例子 public class Work1 { pub ...