BeagleBone Black 从零到一 (2 MLO、U-Boot)
来源:互联网 发布:剑三长歌脸型数据 编辑:程序博客网 时间:2024/05/29 18:52
文章原址: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行
:
12
MLO MLO.byteswap: $(obj)/u-boot-spl.bin FORCE$(call if_changed,mkimage)
可以看到 MLO 文件是由 u-boot-spl.bin
文件通过 mkimage
命令生成的。
再查到 u-boot/Makefile
文件 1310 行
:
1234
spl/u-boot-spl.bin: spl/u-boot-spl@:spl/u-boot-spl: tools prepare $(if $(CONFIG_OF_SEPARATE),dts/dt.dtb)$(Q)$(MAKE) obj=spl -f $(srctree)/scripts/Makefile.spl all
u-boot-spl.bin
文件是还是由 u-boot/scripts/Makefile.spl
文件生成。
文件 u-boot/scripts/Makefile.spl
168 行
定义了u-boot-spl.bin
的生成:
1234567891011
ifeq ($(CONFIG_SPL_OF_CONTROL),y)$(obj)/$(SPL_BIN)-dtb.bin: $(obj)/$(SPL_BIN)-nodtb.bin $(obj)/$(SPL_BIN)-pad.bin \$(obj)/$(SPL_BIN).dtb FORCE$(call if_changed,cat)$(obj)/$(SPL_BIN).bin: $(obj)/$(SPL_BIN)-dtb.bin FORCE$(call if_changed,copy)else$(obj)/$(SPL_BIN).bin: $(obj)/$(SPL_BIN)-nodtb.bin FORCE$(call if_changed,copy)endif
因为 SPL_BIN
在 第32行
定义为 u-boot-spl
:
12345
ifeq ($(CONFIG_TPL_BUILD),y)SPL_BIN := u-boot-tplelseSPL_BIN := u-boot-splendif
由 168 行
上面的定义可以知道 u-boot-spl.bin
和 u-boot-spl-nodtb.bin
有关系。
接着查找到第223行:
12
$(obj)/$(SPL_BIN)-nodtb.bin: $(obj)/$(SPL_BIN) FORCE$(call if_changed,objcopy)
u-boot-spl-nodtb.bin
是通过 objcopy 命令由 u-boot-spl
生成。
再看第246行:
u-boot/scripts/Makefile.spl12
$(obj)/$(SPL_BIN): $(u-boot-spl-init) $(u-boot-spl-main) $(obj)/u-boot-spl.lds FORCE$(call if_changed,u-boot-spl)
所以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 文件的内容:
123456789101112131415161718192021222324252627282930313233343536
MEMORY { .sram : ORIGIN = 0x402F0400, LENGTH = (0x4030B800 - 0x402F0400) }MEMORY { .sdram : ORIGIN = 0x80a00000, LENGTH = 0x80000 }OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")OUTPUT_ARCH(arm)ENTRY(_start)SECTIONS{ .text : { __start = .; *(.vectors) arch/arm/cpu/armv7/start.o (.text) *(.text*) } >.sram . = ALIGN(4); .rodata : { *(SORT_BY_ALIGNMENT(.rodata*)) } >.sram . = ALIGN(4); .data : { *(SORT_BY_ALIGNMENT(.data*)) } >.sram .u_boot_list : { KEEP(*(SORT(.u_boot_list*))); } >.sram . = ALIGN(4); __image_copy_end = .; .end : { *(.__end) } >.sram .bss : { . = ALIGN(4); __bss_start = .; *(.bss*) . = ALIGN(4); __bss_end = .; } >.sdram}
链接文件里面说明了内存布局,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
有解释:
12
$(obj)/u-boot-spl.lds: $(LDSCRIPT) FORCE$(call if_changed_dep,cpp_lds)
LDSCRIPT
的定义:
123456789101112131415161718
# Linker Scriptifdef CONFIG_SPL_LDSCRIPT# need to strip off double quotesLDSCRIPT := $(addprefix $(srctree)/,$(CONFIG_SPL_LDSCRIPT:"%"=%))endififeq ($(wildcard $(LDSCRIPT)),)LDSCRIPT := $(srctree)/board/$(BOARDDIR)/u-boot-spl.ldsendififeq ($(wildcard $(LDSCRIPT)),)LDSCRIPT := $(srctree)/$(CPUDIR)/u-boot-spl.ldsendififeq ($(wildcard $(LDSCRIPT)),)LDSCRIPT := $(srctree)/arch/$(ARCH)/cpu/u-boot-spl.ldsendififeq ($(wildcard $(LDSCRIPT)),)$(error could not find linker script)endif
可见 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
函数中两个程序的功能就开始出现差异了:
123456789101112131415161718192021222324252627282930313233343536373839404142
reset //(arch/arm/cpu/armv7/start.S)save_boot_params_ret //(arch/arm/cpu/armv7/start.S) |- disable interrupts |- cpu_init_cp15 //(arch/arm/cpu/armv7/start.S) | |- Invalidate L1 I/D | |- disable MMU stuff and caches |- cpu_init_crit //(arch/arm/cpu/armv7/start.S) | |- lowlevel_init //(arch/arm/cpu/armv7/lowlevel_init.S) | |- Setup a temporary stack | |- Set up global data | |- s_init //(arch/arm/cpu/armv7/am33xx/board.c) | |- watchdog_disable | |- set_uart_mux_conf | |- setup_clocks_for_console | |- uart_soft_reset |- _main //(arch/arm/lib/crt0.S) |(MLO)如果是 MLO 文件 |- board_init_f //(arch/arm/cpu/armv7/am33xx/board.c) | |- board_early_init_f //(arch/arm/cpu/armv7/am33xx/board.c) | | |- prcm_init | | |- set_mux_conf_regs | |- sdram_init //(board/ti/am335x/board.c) 初始化 DDR |- spl_relocate_stack_gd |- board_init_r //(common/spl/spl.c) |- ... |- spl_load_image //根据不同的启动方式加载 u-boot 镜像, |- jump_to_image_no_args //进入u-boot代码运行 |(U-Boot)如果是U-Boot 镜像 |- board_init_f //(common/board_f.c) | |- ... | |- initcall_run_list(init_sequence_f) | |- ... | |- relocate_code //(arch/arm/lib/relocate.S) 代码重定位 |- relocate_vectors //(arch/arm/lib/relocate.S) 向量表重定义 |- Set up final (full) environment |- board_init_r //(common/board_r.c) |- initcall_run_list(init_sequence_r)//初始化各种外设 |- main_loop()
当 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
因为 U-Boot 官方已经支持了 Beaglebone Black 所以配置文件也已经自带了,编译输入如下命令:
123
片刻后会生成 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
文件,用默认的命令即可,默认的命令为:
123
#define CONFIG_BOOTCOMMAND \"run findfdt; " \"run distro_bootcmd"
run distro_bootcmd
最终会调用 run mmcboot
命令加载 uEnv.txt
文件,并且会运行uEnv.txt
文件里面 uenvcmd
指代的命令。
uEnv.txt
从网络启动例子:
1234567
console=ttyO0,115200n8ipaddr=192.168.23.2serverip=192.168.23.1rootpath=/exports/rootfsnetargs=setenv bootargs console=${console} ${optargs} root=/dev/nfs nfsroot=${serverip}:${rootpath},${nfsopts} rw ip=${ipaddr}:${serverip}:192.168.23.1:255.255.255.0:beaglebone:eth0:none:192.168.23.1netboot=echo Booting from network ...; tftp ${loadaddr} ${bootfile}; tftp ${fdtaddr} ${fdtfile}; run netargs; bootz ${loadaddr} - ${fdtaddr}uenvcmd=run netboot
制作 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) (额外的功能)
新建启动分区:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
Command (m for help): pDisk /dev/sdb: 7746 MB, 7746879488 bytes24 heads, 20 sectors/track, 31522 cylinders, total 15130624 sectorsUnits = sectors of 1 * 512 = 512 bytesSector size (logical/physical): 512 bytes / 512 bytesI/O size (minimum/optimal): 512 bytes / 512 bytesDisk identifier: 0x00000000 Device Boot Start End Blocks Id System/dev/sdb1 * 2048 15130623 7564288 c W95 FAT32 (LBA)Command (m for help): mCommand action a toggle a bootable flag b edit 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 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)Command (m for help): dSelected partition 1Command (m for help): pDisk /dev/sdb: 7746 MB, 7746879488 bytes24 heads, 20 sectors/track, 31522 cylinders, total 15130624 sectorsUnits = sectors of 1 * 512 = 512 bytesSector size (logical/physical): 512 bytes / 512 bytesI/O size (minimum/optimal): 512 bytes / 512 bytesDisk identifier: 0x00000000 Device Boot Start End Blocks Id SystemCommand (m for help): nPartition type: p primary (0 primary, 0 extended, 4 free) e extendedSelect (default p): pPartition number (1-4, default 1): Using default value 1First sector (2048-15130623, default 2048): Using default value 2048Last sector, +sectors or +size{K,M,G} (2048-15130623, default 15130623): Using default value 15130623Command (m for help): pDisk /dev/sdb: 7746 MB, 7746879488 bytes24 heads, 20 sectors/track, 31522 cylinders, total 15130624 sectorsUnits = sectors of 1 * 512 = 512 bytesSector size (logical/physical): 512 bytes / 512 bytesI/O size (minimum/optimal): 512 bytes / 512 bytesDisk identifier: 0x00000000 Device Boot Start End Blocks Id System/dev/sdb1 2048 15130623 7564288 83 LinuxCommand (m for help): tSelected partition 1Hex code (type L to list codes): cChanged system type of partition 1 to c (W95 FAT32 (LBA))Command (m for help): aPartition number (1-4): 1Command (m for help): pDisk /dev/sdb: 7746 MB, 7746879488 bytes24 heads, 20 sectors/track, 31522 cylinders, total 15130624 sectorsUnits = sectors of 1 * 512 = 512 bytesSector size (logical/physical): 512 bytes / 512 bytesI/O size (minimum/optimal): 512 bytes / 512 bytesDisk identifier: 0x00000000 Device Boot Start End Blocks Id System/dev/sdb1 * 2048 15130623 7564288 c W95 FAT32 (LBA)Command (m for help): wThe partition table has been altered!Calling ioctl() to re-read partition table.WARNING: If you have created or modified any DOS 6.xpartitions, please see the fdisk manual page for additionalinformation.Syncing disks.
建立好新的分区之后需要命名并格式化:
1
# sudo mkfs.vfat -F 32 -n boot /dev/sdb1
格式化之后挂载磁盘并把 MLO
文件和 u-boot.img
文件拷贝进去:
123456789
# sudo mount /dev/sdb1 /media/jg/boot # sudo cp MLO /media/jg/boot/MLO# ls /media/jg/boot MLO# sudo cp u-boot.img /media/jg/boot/u-boot.img# ls /media/jg/boot MLO u-boot.img# sync # sudo umount /media/jg/boot
接着把 SD 卡插入 Beaglebone Black 并且按着 S2 按钮上电,从串口打印出的信息我们可以看到 U-Boot 已经可以正常启动了:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
U-Boot SPL 2016.03-rc2-00084-g595af9d (Feb 29 2016 - 22:21:20)Trying to boot from MMCCard doesn't support part_switchMMC partition switch failed*** Warning - MMC partition switch failed, using default environmentreading u-boot.imgreading u-boot.imgU-Boot 2016.03-rc2-00084-g595af9d (Feb 29 2016 - 22:21:20 +0800) Watchdog enabledI2C: readyDRAM: 512 MiBMMC: OMAP SD/MMC: 0, OMAP SD/MMC: 1*** Warning - bad CRC, using default environmentNet: <ethaddr> not set. Validating first E-fuse MACcpsw, usb_etherPress SPACE to abort autoboot in 2 secondsswitch to partitions #0, OKmmc0 is current deviceScanning mmc 0:1...switch to partitions #0, OKmmc0 is current deviceSD/MMC found on device 0reading boot.scr** Unable to read file boot.scr **reading uEnv.txt** Unable to read file uEnv.txt **** File not found /boot/zImage **switch to partitions #0, OKmmc1(part 0) is current deviceScanning mmc 1:1...switch to partitions #0, OKmmc1(part 0) is current deviceSD/MMC found on device 1reading boot.scr** Unable to read file boot.scr **reading uEnv.txt** Unable to read file uEnv.txt **** File not found /boot/zImage **## Error: "bootcmd_nand0" not definedcpsw Waiting for PHY auto negotiation to complete......... TIMEOUT !BOOTP broadcast 1BOOTP broadcast 2BOOTP broadcast 3BOOTP broadcast 4
启动之后,前面一段打印信息是 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)
- BeagleBone Black 从零到一 (2 MLO、U-Boot)
- Beaglebone Black——理论篇beaglebone black启动——从串口获得SPL、U-BOOT,TFTP服务器获得内核,NFS服务器挂载根文件系统
- Beaglebone Black——实践篇beaglebone black启动——从串口获得SPL、U-BOOT,TFTP服务器获得内核,NFS服务器挂载根文件系统
- Beaglebone Black——嵌入式linux系统u-boot编译
- Beaglebone Black——u-boot环境变量解析
- 基于 Beaglebone Black嵌入式linux系统u-boot编译 启动
- BeagleBone Black (ubuntu)(u-boot)使用串口
- boot ubuntu on beaglebone black
- 配置u-boot 參數,構造NFS啓動Beaglebone Black板的操作系統
- BeagleBone Black USB一线通(2)
- beaglebone black 2G emmc 无盘符
- ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)
- ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)
- beaglebone black EZSDK linux从EMMC中启动一
- beaglebone black EZSDK linux从EMMC中启动一
- beaglebone black从SD卡启动Android和安兔兔跑分评测
- Beaglebone black日记
- tomcat优化
- 阿里云ECS服务器Linux环境下配置php运行环境(安装配置篇)
- mybatis原理之mapper实现
- CSDN Markdown语法
- Android sqlite本地数据库
- BeagleBone Black 从零到一 (2 MLO、U-Boot)
- 2017 计蒜之道初赛第六场
- 图片修饰导航实现
- 用库函数sort的cmp函数排数组的时候如果数组里面有longlong的数 cmp参数应该传longlong
- npm WARN deprecated minimatch@0.3.0: Please update to minimatch 3.0.2 or higher to avoid a RegExp Do
- 记一次kafka消费能力优化
- 异常处理
- java语言基础|关于子类和父类的构造方法
- Hadoop 相关概念