U-Boot启动过程和代码分析
2019-12-30葛耿育
葛耿育,秦 中
(遵义师范学院信息工程学院,贵州遵义563006)
BootLoader在嵌入式系统应用中的功能类似于PC机中的BIOS程序,初始化硬件设备并加载嵌入式操作系统到内存中运行[1-3]。常见的嵌入式Boot-Loader有 Blob、vivi、Bios-lt、Redboot、ARMboot、Bootldr以及U-Boot等,其中较为通用和流行的是U-Boot。本文分析最新版的官方源代码架构,解析其代码执行流程和移植编译方法,用以辅助嵌入式系统课程的教学和供学习者参考。
1 官方代码下载和说明
U-Boot(Universal Boot loader)项目最初由德国一名嵌入式软件工程师WolfgangDenk为8xxROM和PPCBoot等项目编写代码逐渐演变而来,通过开源项目开发团队共同完善和维护该项目,目前已经支持多种CPU架构的系统移植功能[4,5]。
官网提供源代码下载网址ftp://ftp.denx.de/pub/u-boot/,提供从第一版本u-boot-0.2.0到当前最新uboot-2019-04版本的代码压缩包下载链接,部分代码压缩包如图1所示。最初的版本号使用阿拉伯数字的主次版本号分类,从2008年8月之后改用年月日期的形式来进行分类,分别如图1的左右两边显示。
图1 官方源代码下载界面
2 目录架构分析
本文选用截止发稿日期的最新版u-boot-2019.4版本作为源代码分析,在Windows下解压之后的目录架构如图2所示,U-Boot官方代码、目录架构和编译软件的风格参考了Linux内核的方式,因此很多目录和文件名和Linux官方内核源代码目录架构很相似,在Linux操作系统下的目录相当于是Windows操作系统下的文件夹。主目录下/api目录存放关于外部应用程序编写的api接口程序、/arch目录存放涉及具体CPU架构相关的代码(包括ARC/ARM/m68k/MIPS/PowerPC/RISC-V/x86等 CPU 架构)、/board目录存放依赖于开发板的相关代码、/cmd目录存放u-boot命令实现的代码文件、/common目录存放和架构无关的通用函数代码文件、/configs目录存放关于开发板的默认配置文件、/disk目录存放磁盘分区及驱动处理代码文件、/doc目录存放一些简要的文档说明、/drivers目录存放通用的驱动程序例如接口协议代码实现等、/dts目录存放 Makefile编译的文件设备树、/env是环境变量相关的文件、/examples目录是独立运行应用程序的案例代码、/fs目录是各种文件系统实现的代码文件、/include目录存放需要被包含的头文件、/lib目录存放所有硬件架构相关的通用库函数文件、/Licenses目录存放各种注册码文件、/net目录存放网络相关的代码文件、/post目录存放上电自检的代码文件、/scripts各种脚本和Makefile文件、/test目录存放各种测试单元文件、/tools目录存放编译生成镜像文件的工具。
图2 代码目录架构
在主目录下,还有其他几个比较重要的文件,MAINTAINERS是代码维护者的说明信息、Makefile是自动化编译工程的编译规则文件、Kconfig为系统编译前配置界面提供源文件、Kbuild是基于 GNU make实现的内核构建系统并进行部分功能扩展,此外还有一个经常被初学者忽视的README文件。很多嵌入式系统学习者会在购买的开发板附带资料或网络论坛查看U-Boot有关的知识,由于网上这方面内容较少且知识老旧,因此很多人对代码分析、移植工作和编译镜像无从下手。最好的办法是参考该官方目录下的README文件说明,该文件在Windows操作系统下使用 sourceinsight工具打开后共4995行文本信息,从多个方面和角度对U-Boot项目进行说明解释,因而非常重要。
3 代码执行过程
在Windows操作系统下解压u-boot-2019.04最新版的代码文件压缩包后发现,代码文件共76.7MB,包含1607个目录,共14850个文件如图3所示,大部分文件代码通过C语言编程实现,小部分偏向硬件底层的代码通过汇编语言实现,其他的有脚本和文本信息。如此庞大的项目很难找到第一个执行的代码文件以及之后顺序执行的代码文件。
图3 u-boot-2019.04版文件属性
通过查看README文件的第218至298行之间的文本信息中得知,U-Boot的启动第一个代码文件是基于特定CPU架构的汇编程序start.S,在类似/arch/XXX/cpu/YYY/start.S的路径,其中XXX泛指不同CPU的厂商或架构名,YYY代表CPU的具体型号或指令集代号,该文件主要功能是初始化CPU硬件相关的工作,后缀名.S代表汇编代码中嵌入了C语言的预处理相关代码。start.S接下来按照先后顺序调用lowlevel.S文件中的lowlevel_init()函数、board_f.c文件中的board_init_r()函数以及board_r.c文件中的board_init_r()函数。后两个C语言文件都是独立于CPU架构的通用代码,存放在/common目录中,最后调用/common目录下 main.c文件中的main_loop()函数。当运行过程中上位机(宿主机或PC机)截住则执行uboot命令行模式下的命令,称为交互模式,可以通过串口或者网络刷机,如果在bootdelay延时时间内没有截住,则执行自启动模式,调用autoboot.c文件中的相应函数最终加载OS镜像到内存中运行,整个引导程序过程结束。
4 编译生成镜像文件
U-Boot项目代码中已经包括了很多经典 CPU架构的流行开发板,这些开发板是各个半导体公司在封装SOC处理器时作为测试使用的样例开发板,涵盖了比较完整的外围设备和接口模块,只需要进行简单的配置即可编译生成可执行文件。README文件第3374至3482行之间的文本信息中得知,将U-Boot官方代码建立成可执行二进制文件,所有文件操作需要在 Linux操作系统下实施。首先进入uboot根目录cd/u-boot/,需要进行配置,执行make NAME_defconfig,其中NAME是具体开发板的代号名称。之后执行make all,就会生成uboot.bin文件,移植到相应的NAME型号开发板中即可运行工作,并加载嵌入式操作系统如Linux等到内存中运行[6,7]。
图4 嵌入式开发板实物图
在对于市场上大部分的嵌入式开发板都是根据半导体厂商样例开发板修改而来,因此功能模块和各个主要模块芯片接口协议相同,可以兼容通用。例如图 4所示的基于 Cortex A8内核的三星公司S5pv210处理器的核心开发板,包含 Nandflash、SDRAM、USB接口、网卡接口、RS232串口等音视频接口等[8-10],对于此类的开发板进行U-Boot的移植步骤为:
(1)在官网下载uboot源代码压缩包
(2)在Linux系统下解压该压缩包
(3)下载交叉编译工具 arm-none-linux-gnueabigcc
(4)在源代码根目录下打开Makefile将CROSS-_COMPILE的值改为(3)中的名称
(5)在/board/samsung/目录下找一个和s5pv210处理器相似的s5pc110板级文件夹,在此基础上修改,复制/board/samsung/s5pc110/并重命名为v210,修改/board/samsung/v210/Makefile中s5pc110.o改成v210.o。
(6)将/include/configs/s5pc110.h复制一份,并改成/include/configs/v210.h,将内容#define CONFIG_SYS_PROMPT“S5PC110#”双引号内容改成“v210#”;将#define CONFIG_IDENT_STRING for S5PC110改成 for v210;配置boards.cfg在s5pc110后加入一行v210 arm armv7 v210 Samsung s5pv210。
(7)编译u-boot,依次执行命令make distclean、makev210_config以及make,则生成uboot.bin文件。5 README文件内容分布
表1 README文件内容分布
在U-Boot代码目录中具有很多重要的分类目录和相关代码文件,通过分析发现,对于用户和开发者而言,最重要的文件就是README文本文件,通过该文件可以了解该项目的所有说明信息,文本具体的内容分类按照行号范围如表1所示。
6 总结
本文通过参考 U-Boot官方源代码目录中的README文件,提取出关于整个项目代码的分层架构说明、代码的执行过程以及建立裸机可以运行的二进制镜像文件方法,对于开发者和学习人员提供一个参考,在教学和实验过程中起到很好的示范效果[11,12]。