u-boot初识
对于嵌入式系统的启动流程大概如下:
上电 --》 bootloader 启动 --》 Linux内核 --》 挂载根文件系统 --》 启动应用程序
一般来说,kernel是uboot从flash读到SDRAM中,然后再启动的。有时候uboot会通过cmdline传递一些参数给内核,比如我们工作中,uboot启动后会读取机顶盒中的配置分区,
然后把相应的值通过cmdline传给kernel,kernel再利用这些值设置相关的属性,供应用程序读取使用。
但是在启动内核之前,其实uboot也会做很多的工作,比如:
(1)读/写 flash的功能:开发过程中,有时候要重新烧写一个kernel,或者用tftp升级一些分区什么的,就要有写flash的功能
(2)初始化时钟、初始化串口、初始化SDRAM和关看门狗等的硬件初始化
(3)或者通过bootcmd自启动一些东西,比如开机logo、启动内核等等
1、uboot配置过程分析
(1)
当执行make xxxx_config进行配置的时候,会执行Makefile的xxxx_config目标,例如:
xxxx_config : unconfig @$(MKCONFIG) $(@:_config=) arm arm920t #其中$(MKCONFIG)=./mkconfig,也就是执行当前目录的mkconfig文件,@代表目标名,_config等于空,所以xxxx_config被替换成xxxx 所以,可以看成执行脚本并传递了几个参数,./mkconfig xxxx arm arm920t
(2)
mkconfig脚本会创建一些平台相关的mk文件和.h有文件之类的东西,比如
#平台相关的参数
echo "ARCH = $2" > config.mk echo "CPU = $3" >> config.mk echo "BOARK= $4" >> config.mk
#生成平台对应的头文件 echo "/* Automatically generated - do not edit */" >>config.h echo "#include <configs/$1.h>" >>config.h
2、uboot的编译过程
编译的过程主要也是看Makefile文件:
(1)
ifeq ($(OBJTREE)/include/config.mk,$(wildcard $(OBJTREE)/include/config.mk)) #//就是配置的时候生成的文件,提供一些平台相关的参数,比如ARCH等 ifeq ($(ARCH),arm) CROSS_COMPILE = arm-linux- #//定义交叉编译工具 endif endif export CROSS_COMPILE # load other configuration include $(TOPDIR)/config.mk #//顶层的目录也有一个config.mk文件 OBJS = cpu/$(CPU)/start.o #//我们看到下面有很多的lib库文件,是模块目录里面的文件编译出来的一个.a文件 LIBS = lib_generic/libgeneric.a LIBS += board/$(BOARDDIR)/lib$(BOARD).a LIBS += cpu/$(CPU)/lib$(CPU).a ifdef SOC LIBS += cpu/$(CPU)/$(SOC)/lib$(SOC).a endif LIBS += lib_$(ARCH)/lib$(ARCH).a LIBS += fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a \ fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a LIBS += net/libnet.a LIBS += disk/libdisk.a LIBS += rtc/librtc.a LIBS += dtt/libdtt.a LIBS += drivers/libdrivers.a LIBS += drivers/nand/libnand.a LIBS += drivers/nand_legacy/libnand_legacy.a LIBS += drivers/sk98lin/libsk98lin.a LIBS += post/libpost.a post/cpu/libcpu.a LIBS += common/libcommon.a #//下面就是编译uboot执行的第一个目标all ALL = $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND) all: $(ALL) $(obj)u-boot.srec: $(obj)u-boot $(OBJCOPY) ${OBJCFLAGS} -O srec $< $@ $(obj)u-boot.bin: $(obj)u-boot $(OBJCOPY) ${OBJCFLAGS} -O binary $< $@ $(obj)u-boot.img: $(obj)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' $(VERSION_FILE) | \ sed -e 's/"[ ]*$$/ for $(BOARD) board"/') \ -d $< $@ $(obj)u-boot: depend version $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT) UNDEF_SYM=`$(OBJDUMP) -x $(LIBS) |sed -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\ cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \ --start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \ -Map u-boot.map -o u-boot
(2)
第(1)步的最后面是编译过程中,一个链接的过程,其中会用到u-boot.lds,链接的时候会用到前面定义的OBJS和各种LIBS
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = 0x00000000;
. = ALIGN(4);
.text :
{
cpu/arm920t/start.o (.text)
*(.text)
}
. = ALIGN(4);
.rodata : { *(.rodata) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
.got : { *(.got) }
. = .;
__u_boot_cmd_start = .;
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;
. = ALIGN(4);
__bss_start = .;
.bss : { *(.bss) }
_end = .;
}