1 u-boot介绍
U-Boot是一种通用的Bootloader, U-Boot可以方便地移植到其他硬件平台上,其源代码也值得开
发者们研究学习。
最早,DENX软件工程中心的Wolfgang Denk基于8xxrom的源码创建了PPCBOOT工程,并且不断添加处理器的支持。后来,Sysgo Gmbh把ppcboot移植到ARM平台上,创建了ARMboot工程。然后以ppcboot工程和armboot工程为基础,创建了U-Boot工程。
现在U-Boot已经能够支持PowerPC、ARM、X86、MIPS体系结构的上百种开发板,已经成为功能最多、灵活性最强并且开发最积极的开放源码Bootloader。目前仍然由DENX的Wolfgang Denk维护。
U-Boot的源码包可以从sourceforge网站下载,还可以订阅该网站活跃的U-Boot Users邮件论坛,这个邮件论坛对于U-Boot的开发和使用都很有帮助。
U-Boot软件包下载网站:http://sourceforge.net/project/u-boot。
U-Boot邮件列表网站:http://lists.sourceforge.net/lists/listinfo/u-boot-users/。
DENX相关的网站:http://www.denx.de/re/DPLG.html。
本文以u-boot1.13为例来对u-boot进行分析
2 u-boot源代码目录结构
- board 存放电路板相关的目录文件
- common 通用的多功能函数实现
- cpu 存放CPU相关的目录文件
- disk 硬盘接口驱动程序
- doc 开发使用文档
- drivers 通用驱动驱动程序
- dtt 数字温度测量器或者传感器的驱动
- examples 例子程序.
- fs 文件系统相关代码
- include 头文件
- lib_arm 存放对ARM体系结构通用的库文件,主要用于实现ARM平台通用的函数
- lib_generic 通用库函数的实现
- lib_i386 存放对i386体系结构通用的库文件
- lib_m68k 存放对m86k体系结构通用的库文件
-lib_microblaze 存放对microblaze体系结构通用的库文件
- lib_mips 存放对MIPS体系结构通用的库文件
- lib_nios 存放对NIOS体系结构通用的库文件
- lib_nios2 存放对NIOS2体系结构通用的库文件
- lib_ppc 存放对Power PC体系结构通用的库文件
- net 网络相关代码
- post 开机自检的代码
- rtc RTC驱动
- tools 存放制作S-Record 或者 U-Boot格式的映像等工具
- Makefile 生成u-boot镜像的Makefile文件
- mkconfig 用来生成各个板子的配置文件
- config.mk 被Makefile所包含,存放编译选项和规则
除了这些目录外,在根目录下还有其他的一些文件, 同时该目录下还有个README的文件,我们可以通过这个文件来熟悉u-boot。
移植过程中重点关注的是board, cpu, 以及Makefile等与平台相关的目录和文件。
3 u-boot源代码编译
U-Boot的源码是通过GCC和Makefile组织编译的。顶层目录下的Makefile首先可以设置开发板的定义,然后递归地调用各级子目录下的Makefile,最后把编译过的程序链接成U-Boot映像。
当我们拿到u-boot的代码后我们就可以尝试给我们自己的板子编译一个u-boot的镜像,而根目录下的Makefile就是用来生成u-boot镜像的。 但在编译之前我们需要为我们的特定板子产生一个描述这块板子的配置文件,然后才能指导Makefile如何去编译能跑在这块板子上的u-boot镜像。
以后的文章中我们都以smdk2410的板子和linux内核为例来分析。
3.1 特定板子的配置文件的生成
实际上配置文件的生成也是通过根目录下的Makefile来完成的, 我们以smdk2410为例, 我们来看Makefile中的片断:
/Makefile:
smdk2410_config : unconfig //smdk2410板子
@./mkconfig $(@:_config=) arm arm920t smdk2410 NULL s3c24x0 //后面是传给mkconfig的参数
如果要生成配置文件,只要打入命令:
make smdk2410_config
这样系统就会调用当前目录下的mkconfig脚本在./include下生成一个叫config.mk的配置文件。文件内容就是我们提供的参数。
其中参数的意思如下:
arm: CPU的架构
arm920t: CPU的类型,
smdk2410: 开发板的型号
NULL: 开发者或经销商(verdor)
s3c24x0: 片上系统(SOC)
详细的参数信息,和如何生成config.mk的内容可看mkconfig脚本,这里就不介绍了。
这样配置后硬件平台依赖的目录文件也就确定下来了,smdk2410平台相关的目录:
board/smdk2410/
cpu/arm920t/
cpu/arm920t/s3c24x0/
lib_arm/
include/asm-arm/
同时还有一个重要的文件:
include/configs/smdk2410.h
这个要我们自己添加,用来定义开发板的配置选项或者参数(具体参数参见README)
我们在移植的时候也按这种步骤添加代码就行了。
3.2 u-boot镜像生成
我们先来大致了解下Makefile文件:
/Makefile:
ifeq (include/config.mk,$(wildcard include/config.mk))
# load ARCH, BOARD, and CPU configuration
include include/config.mk //引用上面我们生成的配置文件,获得ARCH, BOARD等变量
export ARCH CPU BOARD VENDOR SOC //全局可见
# load other configuration
include $(TOPDIR)/config.mk //引用顶层配置文件,获得编译选项等信息
……
ifeq ($(ARCH),arm)
CROSS_COMPILE = arm-linux- //定义交叉编译器
endif
……
export CROSS_COMPILE //全局可见
……
#########################################################################
# U-Boot objects....order is important (i.e. start must be first)
#定义目标文件,顺序很重要,它反映了代码在镜像中的位置(执行顺序)
OBJS = cpu/$(CPU)/start.o
ifeq ($(CPU),i386)
OBJS += cpu/$(CPU)/start16.o
OBJS += cpu/$(CPU)/reset.o
endif
ifeq ($(CPU),ppc4xx)
OBJS += cpu/$(CPU)/resetvec.o
endif
ifeq ($(CPU),mpc83xx)
OBJS += cpu/$(CPU)/resetvec.o
endif
ifeq ($(CPU),mpc85xx)
OBJS += cpu/$(CPU)/resetvec.o
endif
LIBS = lib_generic/libgeneric.a //定义要依赖的库
……
……
ALL = u-boot.srec u-boot.bin System.map
all: $(ALL) //U-Boot映像编译的依赖关系
u-boot.hex: u-boot
$(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@
u-boot.srec: u-boot
$(OBJCOPY) ${OBJCFLAGS} -O srec $< $@
u-boot.bin: u-boot
$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
u-boot.img: u-boot.bin
./tools/mkimage -A $(ARCH) -T firmware -C none /
-a $(TEXT_BASE) -e 0 /
-n $(shell sed -n -e 's/.*U_BOOT_VERSION//p' include/version.h | /
sed -e 's/"[ ]*$$/ for $(BOARD) board"/') /
-d $< $@
u-boot.dis: u-boot
$(OBJDUMP) -d $< > $@
u-boot: depend $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT)
UNDEF_SYM=`$(OBJDUMP) -x $(LIBS) |sed -n -e 's/.*/(__u_boot_cmd_.*/)/-u/1/p'|sort|uniq`;/
$(LD) $(LDFLAGS) $$UNDEF_SYM $(OBJS) /
--start-group $(LIBS) --end-group $(PLATFORM_LIBS) /
-Map u-boot.map -o u-boot
Makefile缺省的编译目标为all,包括u-boot.srec、u-boot.bin、System.map。u-boot.srec和u-boot.bin又依赖于U-Boot。U-Boot就是通过ld命令按照u-boot.map地址表把目标文件组装成u-boot。这些分析应该可以为阅读代码提供了一个线索。
因此如果要生成u-boot的镜像, 我们就可以通过这个命令来完成:
make all
这将生成如下几个文件:
u-boot.bin : 原始的二进制镜像
u-boot: ELF二进制格式的镜像
u-boot.srec: 是motorola S-Record格式的文件。
U-Boot的3种映像格式都可以烧写到Flash中,但需要看加载器能否识别这些格式。一般u-boot.bin最为常用,直接按照二进制格式下载,并且按照绝对地址烧写到Flash中就可以了。U-Boot和u-boot.srec格式映像都自带定位信息。
总结: 由分析可知, 编译u-boot由两个阶段完成:
1. 为特定的板子生成配置文件
2. 编译u-boot使之产生镜像。