http://wenku.baidu.com/link?url=w0sgGDHlEmfRC0FDRdcLvx0ecmvZ7NsvQ2UtfoHnciux6OCpNAmCDjS1zTUQMIZZ8A0Mx7-lb6TxcA6kjqqvgfEvW6xW51lwvzr4ETbuzfq
/* #date:2012-11-13 #从 make XXX_config --> make -->生成 u-boot.bin文件 #逐步展开分析 #我们以smdk2410为例展开分析. #~^~要真正掌握u-boot的移植,我们有2件事需要去做. #(1)分析makefile、链接脚本等相关的文件,以达到了解u-boot的架构,掌握u-boot的实现过程 #(2)分析u-boot的源码,达到 知其然必知其所以然 的目的. #~~~如果你完全掌握了这2步,那么恭喜你,你已经掌握了u-boot的移植. */ 一、体验过程 1.从u-boot官网下载 u-boot-1.1.6.tar.bz2 源码. 2.解压 tar xvf u-boot-1.1.6.tar.bz2 3.进入u-boot-1.1.6/ 目录 book@book-desktop:/work/system/u-boot-1.1.6$ cd u-boot-1.1.6/ book@book-desktop:/work/system/u-boot-1.1.6$ ls arm_config.mk fs MAKEALL avr32_config.mk i386_config.mk Makefile blackfin_config.mk include microblaze_config.mk board lib_arm mips_config.mk CHANGELOG lib_avr32 mkconfig CHANGELOG-before-U-Boot-1.1.5 lib_blackfin nand_spl common lib_generic net config.mk lib_i386 nios2_config.mk COPYING lib_m68k nios_config.mk cpu lib_microblaze post CREDITS lib_mips ppc_config.mk disk lib_nios README doc lib_nios2 rtc drivers lib_ppc rules.mk dtt m68k_config.mk tools examples MAINTAINERS 4.尝试一下,观察现象 book@book-desktop:/work/system/u-boot-1.1.6$ make System not configured - see README #提示 系统没有配置 -看 README make: *** [all] Error 1 5.按照提示,打开u-boot根目录下的README文档(如果有时间多看看,这里我们选取最重要的信息来分析) (1)以下是从README中截取的内容: Selection of Processor Architecture and Board Type: --------------------------------------------------- For all supported boards there are ready-to-use default configurations available; just type "make_config ". Example: For a TQM823L module type: cd u-boot make TQM823L_config For the Cogent platform, you need to specify the cpu type as well; e.g. "make cogent_mpc8xx_config". And also configure the cogent directory according to the instructions in cogent/README. (2) type "make_config " 这句话得知,我们必须先配置单板. 我们所选的单板为smdk2410,所以 在u-boot-1.1.6/目录下输入 make smdk2410_config 然后输入make就OK了.(当然,前提是你的交叉编译环境必须是正确的.这是必须的). (3)终端上操作过程: book@book-desktop:/work/system/u-boot-1.1.6$ make smdk2410_config Configuring for smdk2410 board... book@book-desktop:/work/system/u-boot-1.1.6$ make . . . . . . arm-linux-objcopy --gap-fill=0xff -O srec u-boot u-boot.srec arm-linux-objcopy --gap-fill=0xff -O binary u-boot u-boot.bin (4)可以看出已经生产 u-boot.bin 文件,我们的目的已经达到了. 目的虽然达到了,但是大家或许会疑惑: a.如果我所需要配置的单板u-boot中不支持,而我们想让它支持,怎么办呢?该如何做? PS:办法是绝对有的,前面不是提示 看 README这份文档吗?好好去看看这份文档吧!这里面都有讲. If the system board that you have is not listed, then you will need to port U-Boot to your hardware platform. To do this, follow these steps: 1. Add a new configuration option for your board to the toplevel "Makefile" and to the "MAKEALL" script, using the existing entries as examples. Note that here and at many other places boards and other names are listed in alphabetical sort order. Please keep this order. /* 1.在顶层目录下的Makefile和MAKEALL下添加 有关"用户单板"配置选项 */ 2. Create a new directory to hold your board specific code. Add any files you need. In your board directory, you will need at least the "Makefile", a ".c ", "flash.c" and "u-boot.lds". /* 2.创建一个新的文件来保存单板的特点代码,至少需要4个文件 Makefile.c flash.c u-boot.lds */ 3. Create a new configuration file "include/configs/.h " for your board /* 3.在include/configs目录下为你的单板创建一个新的配置文件.h */ 3. If you''re porting U-Boot to a new CPU, then also create a new directory to hold your CPU specific code. Add any files you need. /* 3.如果你是移植一个新的CPU,那么也必须创建一个新的文件保存CPU特定的代码,添加你需要的一些文件 */ 4. Run "make_config " with your new name. /* 4.配置单板,在串口终端输入:make_config */ 5. Type "make", and you should get a working "u-boot.srec" file to be installed on your target system. /* 5.输入make,会在目标系统上生成一个可执行文件u-boot.srec */ 6. Debug and solve any problems that might arise. [Of course, this last step is much harder than it sounds.] /* 6.调试和解决任何可能产生的问题 */ b.还有这个过程到底是如何实现的呢? PS:怎么组织实现,见我们第二步.分析makefile及其他相关文件. 二、分析makefile及其他一些相关的文件 1.分析makefile,我们还得从前面的 make smdk2410_config 开始分析. (1)在makefile中搜索smdk2410_config (如果不是smdk2410单板,则需先打补丁,不然是找不到XXX_config这个关键词的) smdk2410_config : unconfig @$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0 a.这里有几个比较纠结,也是关键的地方.变量 unconfig 、 MKCONFIG 在根目录下的makefile中可以搜索到. ①unconfig定义: unconfig: @rm -f $(obj)include/config.h $(obj)include/config.mk \ /* rm -f include/config.h include/config.mk board/*/config.tmp */ $(obj)board/*/config.tmp $(obj)board/*/*/config.tmp /* *0.以smdk为例如果之前执行了make smdk2410_config 就会产生2个文件include/config.h和include/config.mk *1.其实在include/config.h include/config.mk中的内容分别是: * ---------------------------------------------------------------------------------- * |include/config.h : | include/config.mk : | * |/* Automatically generated - do not edit */ | ARCH = arm | * |#include| CPU = arm920t | * | | BOARD = smdk2410 | * | | SOC = s3c24x0 | * ---------------------------------------------------------------------------------- */ PS:所以在配置新的单板时,需要先删除这些文件.进行重新配置 ②MKCONFIG定义: MKCONFIG := $(SRCTREE)/mkconfig b.命令行 @$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0 ①$(@:_config=) 替换为 smdk2410 ②从前面可以看出:命令行 相当于 mkconfig smdk2410 arm arm920t smdk2410 NULL s3c24x0 这样相当于往mkconfig传入了 smdk2410 arm arm920t smdk2410 NULL s3c24x0 等6个参数. (2)分析make smdk2410_config 的实现过程. a.很显然,这条命令先得执行 unconfig 这个先决条件,然后再执行 命令行. b.既然是将6个参数传入SRCTREE目录下的mkconfig ,那么我们就要进入mkconfig进行分析. ===========================================================mkconfig==================================================== /* $1 $2 $3 $4 $5 $6 * smdk2410 arm arm920t smdk2410 NULL s3c24x0 */ APPEND=no # Default: Create new config file BOARD_NAME="" # Name to print in make output while [ $# -gt 0 ] ; do case "$1" in --) shift ; break ;; -a) shift ; APPEND=yes ;; -n) shift ; BOARD_NAME="${1%%_config}" ; shift ;; *) break ;; esac done [ "${BOARD_NAME}" ] || BOARD_NAME="$1" /* BOARD_NAME=smdk2410 */ // [ $# -lt 4 ] && exit 1 /* $#表示参数的个数 lt 表示少于 exit 表示退出 */ // [ $# -gt 6 ] && exit 1 /* gt 表示多于 */ echo "Configuring for ${BOARD_NAME} board..." # # Create link to architecture specific headers /* 创建链接到架构特定的header */ # // ln [OPTION]... [-T] TARGET LINK_NAME -> a link to TARGET with the name LINK_NAME # //option: -s -> make symbolic links instead of hard links // if [ "$SRCTREE" != "$OBJTREE" ] ; then // mkdir -p ${OBJTREE}/include // mkdir -p ${OBJTREE}/include2 // cd ${OBJTREE}/include2 // rm -f asm // ln -s ${SRCTREE}/include/asm-$2 asm // LNPREFIX="../../include2/asm/" // cd ../include // rm -rf asm-$2 // rm -f asm // mkdir asm-$2 // ln -s asm-$2 asm else cd ./include rm -f asm ln -s asm-$2 asm /* asm是编译时临时生成指向某个架构,ln 建立一个链接文件 asm -> asm-arm */ ;include/asm -> asm-arm fi rm -f asm-$2/arch /* rm -fr asm-arm/arch */ // if [ -z "$6" -o "$6" = "NULL" ] ; then // ln -s ${LNPREFIX}arch-$3 asm-$2/arch else ln -s ${LNPREFIX}arch-$6 asm-$2/arch /* LNPREFIX 没有定义, asm-arm/arch->arch-s3c24x0*/ ;include/asm-arm/arch -> arch-s3c24x0 fi if [ "$2" = "arm" ] ; then rm -f asm-$2/proc /* rm -f asm-arm/proc */ ln -s ${LNPREFIX}proc-armv asm-$2/proc /* asm-arm/proc->proc-armv */ ;include/asm-arm/proc -> proc-armv fi # # Create include file for Make # echo "ARCH = $2" > config.mk /* # Create new config file ,猜一下 > 估计表示创建一个(config.mk)文件。并追加 $2 的内容*/ echo "CPU = $3" >> config.mk /* >> 这个符号 估计 只有追加的功能,并不是创建文件. 这估计就是和 > 的区别 。2012-11-15 */ echo "BOARD = $4" >> config.mk // [ "$5" ] && [ "$5" != "NULL" ] && echo "VENDOR = $5" >> config.mk [ "$6" ] && [ "$6" != "NULL" ] && echo "SOC = $6" >> config.mk # # Create board specific header file # // if [ "$APPEND" = "yes" ] # Append to existing config file // then // echo >> config.h else > config.h # Create new config file fi echo "/* Automatically generated - do not edit */" >>config.h echo "#include " >>config.h exit 0 =======================================================编译成功后=============================================================== -------------------------------------------------------------------------------------------------------------------------------| |include/config.h : |include/config.mk : |include/asm -> asm-arm | |/* Automatically generated - do not edit */ | ARCH = arm |include/asm-arm/arch -> arch-s3c24x0| |#include | CPU = arm920t |include/asm-arm/proc -> proc-armv | | | BOARD = smdk2410 | | | | SOC = s3c24x0 | | -------------------------------------------------------------------------------------------------------------------------------| -->在include/下生成了config.h<-- --> include/生成了config.mk <-- -->建立3个链接文件<-- ================================================================================================================================ 2.继续分析makefile. 在终端(我使用的是串口)输入make,分析串口打印出的信息,继续深入. 注意:这里我们来约定几个符号,方便分析makefile及其关联的文件 ①<<==>> 表示: 等价于 ②/* */ 表示: 注释,一般用于说明变量的含义或者其来源. (1)打开makefile: ALL = $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND) <<==>> ALL = u-boot.srec u-boot.bin System.map u-boot-nand.bin all: $(ALL) a.我们需要是u-boot.bin $(obj)u-boot: $(obj)u-boot $(OBJCOPY) ${OBJCFLAGS} -O binary $< $@ /* OBJCOPY = $(CROSS_COMPILE)objcopy OBJCFLAGS += --gap-fill=0xff*/ /* ifeq ($(ARCH),arm) //Makefile中的内容include $(OBJTREE)/include/config.mk CROSS_COMPILE = arm-linux- //Makefile中的内容include $(TOPDIR)/config.mk endif */ <<==>> u-boot: u-boot arm-linux-objcopy --gap-fill=0xff -O binary $< $@ b.那么我们来分析 u-boot $(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) \ //__OBJS := $(subst $(obj),,$(OBJS)) $(LNDIR)=根目录 --start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \ //__LIBS := $(subst $(obj),,$(LIBS)) -Map u-boot.map -o u-boot // -Map 打印一个mapfile /* * LDFLAGS += -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE) $(PLATFORM_LDFLAGS) ->没有定义 PLATFORM_LDFLAGS */ /* * UNDEF_SYM=`$(OBJDUMP) -x $(LIBS) |sed -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\ * -->>定义变量 UNDEF_SYM ` 这个符号是定义字符串变量的时候用的,且成对存在. * * cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \ * -->>进入/根目录 && 执行 链接命令 ;链接哪些文件呢? -> 变量 $(OBJS) 与 $(LIBS) 中的内容 * * --start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \ * -->>--start-group <归档文件> --end-group 这是一种格式. * * -Map u-boot.map -o u-boot * -->>生成一个 .map文件 */ (A)depend /* PS:这个是u-boot的先决条件里面最难的,也是核心部分 2012/11/17 */ |--------关于for...do...done (固定迴圈)的用法--------| depend dep: | | for dir in $(SUBDIRS) ; do $(MAKE) -C $$dir _depend ; done /**/ | | |for var in con1 con2 con3 ... | /* |do | *for dir in $(SUBDIRS) ; <<==>> 列出$(SUBDIRS)中的目录; SUBDIRS = tools examples post post/cpu | 程式段 | *do $(MAKE) -C $$dir _depend ; <<==>> _depend: $(obj).depend |done | *done | | */ |以上面的例子來說,這個 $var 的變數內容在迴圈工作時:| | | <<==>> |--------------------------------rules.mk-----------------------------|第一次迴圈時, $var 的內容為 con1 ; | // tools >> |_depend: $(obj).depend |第二次迴圈時, $var 的內容為 con2 ; | | |第三次迴圈時, $var 的內容為 con3 ; | cd /tools ;make $(obj).depend |$(obj).depend: $(src)Makefile $(TOPDIR)/config.mk $(SRCS) |.... | | @rm -f $@ | | // examples >> | @for f in $(SRCS); do \ | | depend dep: | g=`basename $$f | sed -e 's/\(.*\)\.\w/\1.o/'`; \ | | cd /examples ;make $(obj).depend | $(CC) -M $(HOST_CFLAGS) $(CPPFLAGS) -MQ $(obj)$$g $$f >> $@ ; \| | | done | | // post >> | | | depend dep: |---------------------------------------------------------------------|----------------------------------------------------| cd /post ;make $(obj).depend // post/cpu >> depend dep: cd /post/cpu ;make $(obj).depend /* 可以找一个追溯进去分析一下,收获很大,基本可以把makefile的思路理清 2012/11/17 */ (B)version version: @echo -n "#define U_BOOT_VERSION \"U-Boot " > $(VERSION_FILE); \ /* VERSION_FILE = $(obj)include/version_autogenerated.h */ echo -n "$(U_BOOT_VERSION)" >> $(VERSION_FILE); \ echo -n $(shell $(CONFIG_SHELL) $(TOPDIR)/tools/setlocalversion \ $(TOPDIR)) >> $(VERSION_FILE); \ echo "\"" >> $(VERSION_FILE) (C)$(SUBDIRS) SUBDIRS = tools \ examples \ post \ post/cpu .PHONY : $(SUBDIRS) (D)$(OBJS) /* 这个先决条件也比较重要 */ $(OBJS): $(MAKE) -C cpu/$(CPU) $(if $(REMOTE_BUILD),$@,$(notdir $@)) /* $(if $(REMOTE_BUILD),$@,$(notdir $@)) -> 如果定义了 则表达式为 $@ 否则,表达式为$(notdir $@) */ /* notdir函数用于 从$@路径中 抽取 文件名 */ <<==>> cd cpu/ ; make /* cpu/Makefile: |------------------------------------------------------------------------------| |include $(TOPDIR)/config.mk | | | |LIB = $(obj)lib$(CPU).a | | | |START = start.o | |COBJS = cpu.o interrupts.o | | | |SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) | |OBJS := $(addprefix $(obj),$(COBJS) $(SOBJS)) | |START := $(addprefix $(obj),$(START)) | | | |all: $(obj).depend $(START) $(LIB) | | | |$(LIB): $(OBJS) | | $(AR) $(ARFLAGS) $@ $(OBJS) | | | |######################################################################### | | | |# defines $(obj).depend target | |include $(SRCTREE)/rules.mk | | | |sinclude $(obj).depend | | | |######################################################################### | |------------------------------------------------------------------------------| */ (E)$(LIBS) $(LIBS): $(MAKE) -C $(dir $(subst $(obj),,$@) )/* 删除$(LIBS)所有成员中的$(objs)前缀 ,dir 表示抽出 $(OBJS)中成员的目录,并返回抽出的目录,但不包括成员 2012/11/18 */ /* *举个例子来说明 subst这个函数的功能 格式: $(subst from,to,text) * $(substee,EE,feetonthestreet) ->结果得到这样一串字符串: fEEtonthestrEEt */ /* LIBS的内容就比较多了。 ==================================================================================== LIBS = lib_generic/libgeneric.a LIBS += board/$(BOARDDIR)/lib$(BOARD).a LIBS += cpu/$(CPU)/lib$(CPU).a ifdef SOC // SOC=s3c24x0 在子目录的config.mk中定义了 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 LIBS += $(BOARDLIBS) LIBS := $(addprefix $(obj),$(LIBS)) .PHONY : $(LIBS) ==================================================================================== */ <<==>> for dir in $(LIBS) /* 这里的dir不是shell中的命令 ,注意区分,它代表 $(LIBS)内容 */ do make -C $(LIBS) done /* *现在我随便进入$(LIBS)中的一个成员(我们这里暂且称为成员),比如 LIBS += cpu/$(CPU)/lib$(CPU).a make -C cpu/arm920t/ ====================================./cpu/arm920t/Makefile===================================== include $(TOPDIR)/config.mk LIB = $(obj)lib$(CPU).a START = start.o COBJS = cpu.o interrupts.o SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(COBJS) $(SOBJS)) START := $(addprefix $(obj),$(START)) all: $(obj).depend $(START) $(LIB) $(LIB): $(OBJS) $(AR) $(ARFLAGS) $@ $(OBJS) ######################################################################### # defines $(obj).depend target include $(SRCTREE)/rules.mk sinclude $(obj).depend ######################################################################### $(obj).depend $(START) $(LIB) 这个就是重点 2012/11/18 =============================================================================================== */ (F)$(LDSCRIPT) LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds /* 在config.mk中定义 */ (G)到这里我们的makefile分析基本完成了.但是还有一个文件,我们不得不分析它,那就是rule.mk ,因为这个文件中无处不在! (2)打开rule.mk: /* 这个文件用来设定 自动生成依赖规则 */ #########################################################################|| || _depend: $(obj).depend || ||PS:关于basename的用法: ||/*strip directory and suffix from filenames 去除目录和文件名的后缀 */ $(obj).depend: $(src)Makefile $(TOPDIR)/config.mk $(SRCS) || basename /usr/bin/sort @rm -f $@ || Output "sort". @for f in $(SRCS); do \ || g=`basename $$f | sed -e 's/\(.*\)\.\w/\1.o/'`; \ || basename include/stdio.h .h $(CC) -M $(HOST_CFLAGS) $(CPPFLAGS) -MQ $(obj)$$g $$f >> $@ ; \ || Output "stdio". done || /*CPPFLAGS 命令有点复杂 HOST_CFLAGS没有定义*/ || #########################################################################|| /* *CPPFLAGS变量等于: *-g -Os -fno-strict-aliasing -fno-common -ffixed-r8 -msoft-float -malignment-traps *-D__KERNEL__ *-DTEXT_BASE=0x33F80000 *-I/work/system/u-boot-1.1.6/include *-fno-builtin -ffreestanding -nostdinc -isystem /work/tools/gcc-3.4.5-glibc-2.3.6/lib/gcc/arm-linux/3.4.5/include *-pipe -DCONFIG_ARM -D__ARM__ -march=armv4 -mapcs-32 -Wall -Wstrict-prototypes */ /* *g=`basename $$f | sed -e 's/\(.*\)\.\w/\1.o/'`; \ -->>设置一个变量g , $f 代表$(SRCS)中的内容 管道命令+正则表达式 *$(CC) -M $(HOST_CFLAGS) $(CPPFLAGS) -MQ $(obj)$$g $$f >> $@ ; \ -->>自动生成依赖 , -M / -MQ 并把这个依赖(规则) 写入到 $@(Makefile/config.mk/$(SRCS) )中. *这2行应该是最复杂的.定义了 一系列规矩 */ /* date:2012/11/21 */ 三、分析u-boot源码(最终目的) 标签:_start->reset->start_armboot-> main_loop ->do_bootm_linux 0.分析代码启动流程. (1).start.S: A.汇编代码分析 .globl _start _start: b reset /*0x00000000 */ /* 中断向量地址 */ ldr pc, _undefined_instruction /*0x00000004 */ ldr pc, _software_interrupt /*0x00000008 */ ldr pc, _prefetch_abort /*0x0000000C */ ldr pc, _data_abort /*0x00000010 */ ldr pc, _not_used /*0x00000014 */ ldr pc, _irq /*0x00000018 */ ldr pc, _fiq /*0x0000001C */ reset: /* 1.设置为系统模式(SVC) */ /* 2.关看门狗 */ /* 3.屏蔽所有中断 */ /* 4.设置系统时钟 */ /* bl cpu_init_crit */ cpu_init_crit: /* CPU_init_critical registers - setup important registers - setup memory timing */ /* 1.flush v4 I/D caches */ /* 2.disable MMU stuff and caches */ /* 3.before relocating, we have to setup RAM timing */ /* 4. bl lowlevel_init */ /* bl lowlevel_init */ lowlevel_init: /* 初始化 储存管理器 */ |--------------------------------------------------------------------------------------------------------------------------------------| | ldr r0, =SMRDATA /* 0x33f80430 */ | | ldr r1, _TEXT_BASE /* 0x33f80400 */ | | sub r0, r0, r1 /* r0=0x30 */ | | ldr r1, =BWSCON /* Bus Width Status Controller */ | | add r2, r0, #13*4 /* r2=30+34=0x64 */ | | 0: | | /* write SMRDATA to BWSCON <--> init SDRAM*/ | | ldr r3, [r0], #4 /* [r0]=[0x33f80430] */ | | str r3, [r1], #4 /* [r1]=[0x48000000] */ | | cmp r2, r0 /* r2=0x64 ,r0=0x30 */ | | bne 0b | | | | /* everything is fine now */ | | mov pc, lr | | | | .ltorg | | /* the literal pools origin */ | | | | SMRDATA: | | .word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28)) | | .word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC)) | | .word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC)) | | .word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC)) | | .word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC)) | | .word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC)) | | .word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC)) | | .word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN)) | | .word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN)) | | .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT) | | .word 0x32 | | .word 0x30 | | .word 0x30 | ---------------------------------------------------------------------------------------------------------------------------------------- ======================================================================================================================================== B.代码的重定位: relocate: /* relocate U-Boot to RAM 将程序拷贝到SDRAM的链接地址 */ adr r0, _start /* r0 <- current position of code _start:33f80000 */ ldr r1, _TEXT_BASE /* test if we run from flash or RAM 33f80040 */ cmp r0, r1 /* don't reloc during debug */ beq stack_setup /* beq(Bxx)一类的指令与CPSR密切相关,等于则 跳转 */ ldr r2, _armboot_start /* 33f80044 */ ldr r3, _bss_start /* 33f80048 */ sub r2, r3, r2 /* r2 <- size of armboot */ add r2, r0, r2 /* r2 <- source end address r2=30000004 */ copy_loop: ldmia r0!, {r3-r10} /* copy from source address [r0] */ stmia r1!, {r3-r10} /* copy to target address [r1] */ cmp r0, r2 /* until source end addreee [r2] */ ble copy_loop /* 少于或等于 则 跳转 */ #endif /* CONFIG_SKIP_RELOCATE_UBOOT */ /* Set up the stack */ stack_setup: ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot 33f80000 */ sub r0, r0, #CFG_MALLOC_LEN /* malloc area */ sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */ #ifdef CONFIG_USE_IRQ sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ) #endif sub sp, r0, #12 /* leave 3 words for abort-stack */ clear_bss: ldr r0, _bss_start /* find start of bss segment */ ldr r1, _bss_end /* stop here */ mov r2, #0x00000000 /* clear */ clbss_l:str r2, [r0] /* clear loop... */ add r0, r0, #4 cmp r0, r1 ble clbss_l c.进入u-boot的第二阶段(C语言阶段) ldr pc, _start_armboot /* 开始第二阶段,调用C函数 */ _start_armboot: .word start_armboot =================================================================================================================================== C.C代码分析: start_armboot(基本做一些初始化工作)->main_loop(获取环境变量->运行环境变量) void start_armboot (void) { init_fnc_t **init_fnc_ptr; /* 定义一个 二级 指针! */ char *s; #ifndef CFG_NO_FLASH /* 没有定义 */ ulong size; #endif /* Pointer is writable since we allocated a register for it */ //在使用之前,分配一块内存(结构体) gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));/* _armboot_start=33f80044 -30000 - gd_t(gd_t结构体所占的内存大小),也是为分配一块内存 */ /* compiler optimization barrier needed for GCC >= 3.4 */ __asm__ __volatile__("": : :"memory"); //GCC 优化问题,先不管 memset ((void*)gd, 0, sizeof (gd_t));/* 初始化一块内存,清除gd 所指的内存 */ gd->bd = (bd_t*)((char*)gd - sizeof(bd_t)); /* bd也是一个结构体(bd_info) , */ memset (gd->bd, 0, sizeof (bd_t)); /* 初始化内存块bd_t,一般是清零 */ monitor_flash_len = _bss_start - _armboot_start; /*33f80048 -33f80044 =4 */ /* 下面一个for语句比较有意思 init_sequence指针数组里面有很多成员,成员都是 函数地址*/ for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { //init_sequence 很多相关的初始化都在里面实现! if ((*init_fnc_ptr)() != 0) { hang (); } } #ifndef CFG_NO_FLASH /* configure available FLASH banks */ size = flash_init (); /* *flash初始化.里面的C技巧特别好, 结构体数组 typedef struct {.....}flash_info_t; flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; *初始化flash的 参数 都放在 这个结构体 里面。 */ display_flash_config (size); //显示flash的大小! #endif /* CFG_NO_FLASH */ #ifdef CONFIG_VFD # ifndef PAGE_SIZE # define PAGE_SIZE 4096 # endif /* * reserve memory for VFD display (always full pages) */ /* bss_end is defined in the board-specific linker script */ addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); size = vfd_setmem (addr); gd->fb_base = addr; #endif /* CONFIG_VFD */ #ifdef CONFIG_LCD # ifndef PAGE_SIZE # define PAGE_SIZE 4096 # endif /* * reserve memory for LCD display (always full pages) */ /* bss_end is defined in the board-specific linker script */ addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); /* (33f8004c+(4096-1) ) & ~(4096-1) */ size = lcd_setmem (addr); gd->fb_base = addr; #endif /* CONFIG_LCD */ /* armboot_start is defined in the board-specific linker script */ mem_malloc_init (_armboot_start - CFG_MALLOC_LEN); /* 0x33f80044 - ( 0x10000 + 0x20000 ) */ #if (CONFIG_COMMANDS & CFG_CMD_NAND) /* 全部定义 */ puts ("NAND: "); nand_init(); /* go init the NAND */ /* 这个函数太复杂了,至少现在看来,有兴趣可以去研究研究 */ #endif #ifdef CONFIG_HAS_DATAFLASH AT91F_DataflashInit(); // 比较精辟的 C技巧 dataflash_print_info(); // 比较好的C语言 #endif /* initialize environment */ env_relocate (); /* 这是重点分析的对象! 初始化 环境变量 */ #ifdef CONFIG_VFD /* must do this after the framebuffer is allocated */ drv_vfd_init(); /* 使用这个函数之前 必须先分配 显存 */ #endif /* CONFIG_VFD */ /* IP Address */ gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr"); /* MAC Address */ { int i; ulong reg; char *s, *e; char tmp[64]; i = getenv_r ("ethaddr", tmp, sizeof (tmp)); s = (i > 0) ? tmp : NULL; for (reg = 0; reg < 6; ++reg) { gd->bd->bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0; if (s) s = (*e) ? e + 1 : e; } #ifdef CONFIG_HAS_ETH1 i = getenv_r ("eth1addr", tmp, sizeof (tmp)); s = (i > 0) ? tmp : NULL; for (reg = 0; reg < 6; ++reg) { gd->bd->bi_enet1addr[reg] = s ? simple_strtoul (s, &e, 16) : 0; if (s) s = (*e) ? e + 1 : e; } #endif } devices_init (); /* get the devices list going. */ #ifdef CONFIG_CMC_PU2 load_sernum_ethaddr (); #endif /* CONFIG_CMC_PU2 */ jumptable_init (); console_init_r (); /* fully init console as a device */ #if defined(CONFIG_MISC_INIT_R) /* miscellaneous platform dependent initialisations */ misc_init_r (); #endif /* enable exceptions */ enable_interrupts (); /* Perform network card initialisation if necessary */ #ifdef CONFIG_DRIVER_CS8900 cs8900_get_enetaddr (gd->bd->bi_enetaddr); #endif #if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96) if (getenv ("ethaddr")) { smc_set_mac_addr(gd->bd->bi_enetaddr); } #endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */ /* Initialize from environment */ if ((s = getenv ("loadaddr")) != NULL) { load_addr = simple_strtoul (s, NULL, 16); } #if (CONFIG_COMMANDS & CFG_CMD_NET) if ((s = getenv ("bootfile")) != NULL) { copy_filename (BootFile, s, sizeof (BootFile)); } #endif /* CFG_CMD_NET */ #ifdef BOARD_LATE_INIT board_late_init (); #endif #if (CONFIG_COMMANDS & CFG_CMD_NET) #if defined(CONFIG_NET_MULTI) puts ("Net: "); #endif eth_initialize(gd->bd); #endif /* main_loop() can return to retry autoboot, if so just run it again. */ for (;;) { main_loop (); } /* NOTREACHED - no way out of command loop except booting */ } =================================================================================================== D:main_loop (分析) void main_loop (void) { #ifndef CFG_HUSH_PARSER static char lastcommand[CFG_CBSIZE] = { 0, }; int len; int rc = 1; int flag; #endif #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) char *s; int bootdelay; #endif #ifdef CONFIG_PREBOOT char *p; #endif #ifdef CONFIG_BOOTCOUNT_LIMIT unsigned long bootcount = 0; unsigned long bootlimit = 0; char *bcs; char bcs_set[16]; #endif /* CONFIG_BOOTCOUNT_LIMIT */ #if defined(CONFIG_VFD) && defined(VFD_TEST_LOGO) ulong bmp = 0; /* default bitmap */ extern int trab_vfd (ulong bitmap); #ifdef CONFIG_MODEM_SUPPORT if (do_mdm_init) bmp = 1; /* alternate bitmap */ #endif trab_vfd (bmp); #endif /* CONFIG_VFD && VFD_TEST_LOGO */ #ifdef CONFIG_BOOTCOUNT_LIMIT bootcount = bootcount_load(); bootcount++; bootcount_store (bootcount); sprintf (bcs_set, "%lu", bootcount); setenv ("bootcount", bcs_set); bcs = getenv ("bootlimit"); bootlimit = bcs ? simple_strtoul (bcs, NULL, 10) : 0; #endif /* CONFIG_BOOTCOUNT_LIMIT */ #ifdef CONFIG_MODEM_SUPPORT debug ("DEBUG: main_loop: do_mdm_init=%d\n", do_mdm_init); if (do_mdm_init) { char *str = strdup(getenv("mdm_cmd")); setenv ("preboot", str); /* set or delete definition */ if (str != NULL) free (str); mdm_init(); /* wait for modem connection */ } #endif /* CONFIG_MODEM_SUPPORT */ #ifdef CONFIG_VERSION_VARIABLE { extern char version_string[]; setenv ("ver", version_string); /* set version variable */ } #endif /* CONFIG_VERSION_VARIABLE */ #ifdef CFG_HUSH_PARSER u_boot_hush_start (); #endif #ifdef CONFIG_AUTO_COMPLETE install_auto_complete(); #endif #ifdef CONFIG_PREBOOT if ((p = getenv ("preboot")) != NULL) { # ifdef CONFIG_AUTOBOOT_KEYED int prev = disable_ctrlc(1); /* disable Control C checking */ # endif # ifndef CFG_HUSH_PARSER run_command (p, 0); # else parse_string_outer(p, FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP); # endif # ifdef CONFIG_AUTOBOOT_KEYED disable_ctrlc(prev); /* restore Control C checking */ # endif } #endif /* CONFIG_PREBOOT */ #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) s = getenv ("bootdelay"); bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY; debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay); # ifdef CONFIG_BOOT_RETRY_TIME init_cmd_timeout (); # endif /* CONFIG_BOOT_RETRY_TIME */ #ifdef CONFIG_BOOTCOUNT_LIMIT if (bootlimit && (bootcount > bootlimit)) { printf ("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n", (unsigned)bootlimit); s = getenv ("altbootcmd"); } else #endif /* CONFIG_BOOTCOUNT_LIMIT */ s = getenv ("bootcmd"); debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : " "); if (bootdelay >= 0 && s && !abortboot (bootdelay)) { # ifdef CONFIG_AUTOBOOT_KEYED int prev = disable_ctrlc(1); /* disable Control C checking */ # endif # ifndef CFG_HUSH_PARSER run_command (s, 0); # else parse_string_outer(s, FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP); # endif # ifdef CONFIG_AUTOBOOT_KEYED disable_ctrlc(prev); /* restore Control C checking */ # endif } # ifdef CONFIG_MENUKEY if (menukey == CONFIG_MENUKEY) { s = getenv("menucmd"); if (s) { # ifndef CFG_HUSH_PARSER run_command (s, 0); # else parse_string_outer(s, FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP); # endif } } #endif /* CONFIG_MENUKEY */ #endif /* CONFIG_BOOTDELAY */ #ifdef CONFIG_AMIGAONEG3SE { extern void video_banner(void); video_banner(); } #endif /* * Main Loop for Monitor Command Processing */ #ifdef CFG_HUSH_PARSER parse_file_outer(); /* This point is never reached */ for (;;); #else for (;;) { #ifdef CONFIG_BOOT_RETRY_TIME if (rc >= 0) { /* Saw enough of a valid command to * restart the timeout. */ reset_cmd_timeout(); } #endif len = readline (CFG_PROMPT); flag = 0; /* assume no special flags for now */ if (len > 0) strcpy (lastcommand, console_buffer); else if (len == 0) flag |= CMD_FLAG_REPEAT; #ifdef CONFIG_BOOT_RETRY_TIME else if (len == -2) { /* -2 means timed out, retry autoboot */ puts ("\nTimed out waiting for command\n"); # ifdef CONFIG_RESET_TO_RETRY /* Reinit board to run initialization code again */ do_reset (NULL, 0, 0, NULL); # else return; /* retry autoboot */ # endif } #endif if (len == -1) puts (" \n "); else rc = run_command (lastcommand, flag); if (rc <= 0) { /* invalid command or not repeatable, forget it */ lastcommand[0] = 0; } } #endif /*CFG_HUSH_PARSER*/ } =========================================================================================================== E:2个比较重要的函数 void setenv (char *varname, char *varvalue) { char *argv[4] = { "setenv", varname, varvalue, NULL }; _do_setenv (0, 3, argv); } /* * Look up variable from environment, * return address of storage for that variable, * or NULL if not found */ char *getenv (char *name) { int i, nxt; WATCHDOG_RESET(); //uchar (*env_get_char)(int) = env_get_char_init; by Tusu 2012/11/28 //static uchar env_get_char_init (int index) for (i=0; env_get_char(i) != '\0'; i=nxt+1) { int val; for (nxt=i; env_get_char(nxt) != '\0'; ++nxt) { if (nxt >= CFG_ENV_SIZE) { return (NULL); } } if ((val=envmatch((uchar *)name, i)) < 0) continue; return ((char *)env_get_addr(val)); } return (NULL); } /**************************************************************************** * returns: * 1 - command executed, repeatable * 0 - command executed but not repeatable, interrupted commands are * always considered not repeatable * -1 - not executed (unrecognized, bootd recursion or too many args) * (If cmd is NULL or "" or longer than CFG_CBSIZE-1 it is * considered unrecognized) * * WARNING: * * We must create a temporary copy of the command since the command we get * may be the result from getenv(), which returns a pointer directly to * the environment data, which may change magicly when the command we run * creates or modifies environment variables (like "bootp" does). */ int run_command (const char *cmd, int flag) { cmd_tbl_t *cmdtp; char cmdbuf[CFG_CBSIZE]; /* working copy of cmd */ char *token; /* start of token in cmdbuf */ char *sep; /* end of token (separator) in cmdbuf */ char finaltoken[CFG_CBSIZE]; char *str = cmdbuf; char *argv[CFG_MAXARGS + 1]; /* NULL terminated */ int argc, inquotes; int repeatable = 1; int rc = 0; #ifdef DEBUG_PARSER printf ("[RUN_COMMAND] cmd[%p]=\"", cmd); puts (cmd ? cmd : "NULL"); /* use puts - string may be loooong */ puts ("\"\n"); #endif clear_ctrlc(); /* forget any previous Control C */ if (!cmd || !*cmd) { return -1; /* empty command */ } if (strlen(cmd) >= CFG_CBSIZE) { puts ("## Command too long!\n"); return -1; } strcpy (cmdbuf, cmd); /* Process separators and check for invalid * repeatable commands */ #ifdef DEBUG_PARSER printf ("[PROCESS_SEPARATORS] %s\n", cmd); #endif while (*str) { /* * Find separator, or string end * Allow simple escape of ';' by writing "\;" */ for (inquotes = 0, sep = str; *sep; sep++) { if ((*sep=='\'') && (*(sep-1) != '\\')) inquotes=!inquotes; if (!inquotes && (*sep == ';') && /* separator */ ( sep != str) && /* past string start */ (*(sep-1) != '\\')) /* and NOT escaped */ break; } /* * Limit the token to data between separators */ token = str; if (*sep) { str = sep + 1; /* start of command for next pass */ *sep = '\0'; } else str = sep; /* no more commands for next pass */ #ifdef DEBUG_PARSER printf ("token: \"%s\"\n", token); #endif /* find macros in this token and replace them */ process_macros (token, finaltoken); /* Extract arguments */ if ((argc = parse_line (finaltoken, argv)) == 0) { rc = -1; /* no command at all */ continue; } /* Look up command in command table */ if ((cmdtp = find_cmd(argv[0])) == NULL) { printf ("Unknown command '%s' - try 'help'\n", argv[0]); rc = -1; /* give up after bad command */ continue; } /* found - check max args */ if (argc > cmdtp->maxargs) { printf ("Usage:\n%s\n", cmdtp->usage); rc = -1; continue; } #if (CONFIG_COMMANDS & CFG_CMD_BOOTD) /* avoid "bootd" recursion */ if (cmdtp->cmd == do_bootd) { #ifdef DEBUG_PARSER printf ("[%s]\n", finaltoken); #endif if (flag & CMD_FLAG_BOOTD) { puts ("'bootd' recursion detected\n"); rc = -1; continue; } else { flag |= CMD_FLAG_BOOTD; } } #endif /* CFG_CMD_BOOTD */ /* OK - call function to do the command */ if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) { rc = -1; } repeatable &= cmdtp->repeatable; /* Did the user stop this? */ if (had_ctrlc ()) return 0; /* if stopped then not repeatable */ } return rc ? rc : repeatable; } F:解析 U_BOOT_CMD 命令! | 1:宏定义 | #define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \ | cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help} |typedef struct cmd_tbl_s cmd_tbl_t; |#define Struct_Section __attribute__ ((unused,section (".u_boot_cmd"))) 2:举例分析: U_BOOT_CMD( flinfo, 2, 1, do_flinfo, "flinfo - print FLASH memory information\n", "\n - print information for all FLASH memory banks\n" "flinfo N\n - print information for FLASH memory bank # N\n" ); 3:函数原型 |struct cmd_tbl_s { int do_flinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) | char *name; /* Command Name */ { | int maxargs; /* maximum number of arguments */ ulong bank; | int repeatable; /* autorepeat allowed? */ | /* Implementation function */ #ifdef CONFIG_HAS_DATAFLASH | int (*cmd)(struct cmd_tbl_s *, int, int, char *[]); dataflash_print_info(); | char *usage; /* Usage message (short) */ #endif |#ifdef CFG_LONGHELP | char *help; /* Help message (long) */ if (argc == 1) { /* print info for all FLASH banks */ |#endif for (bank=0; bank#ifdef CONFIG_AUTO_COMPLETE printf ("\nBank # %ld: ", bank+1); | /* do auto completion on the arguments */ | int (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]); flash_print_info (&flash_info[bank]); |#endif } |}; return 0; |-------------------------------------------------------------------------------------- } |unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base) |{ bank = simple_strtoul(argv[1], NULL, 16); | unsigned long result = 0,value; if ((bank < 1) || (bank > CFG_MAX_FLASH_BANKS)) { | printf ("Only FLASH Banks # 1 ... # %d supported\n", | if (*cp == '0') { CFG_MAX_FLASH_BANKS); | cp++; return 1; | if ((*cp == 'x') && isxdigit(cp[1])) { } | base = 16; printf ("\nBank # %ld: ", bank); | cp++; flash_print_info (&flash_info[bank-1]); | } return 0; | if (!base) { } | base = 8; | } | } | if (!base) { | base = 10; | } | while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp) | ? toupper(*cp) : *cp)-'A'+10) < base) { | result = result*base + value; | cp++; | } | if (endp) | *endp = (char *)cp; | return result; | } 1.u-boot的最终目的是:启动内核 U_BOOT_CMD( bootm, CFG_MAXARGS, 1, do_bootm, "bootm - boot application image from memory\n", "[addr [arg ...]]\n - boot application image stored in memory\n" "\tpassing arguments 'arg ...'; when booting a Linux kernel,\n" "\t'arg' can be the address of an initrd image\n" #ifdef CONFIG_OF_FLAT_TREE "\tWhen booting a Linux kernel which requires a flat device-tree\n" "\ta third argument is required which is the address of the of the\n" "\tdevice-tree blob. To boot that kernel without an initrd image,\n" "\tuse a '-' for the second argument. If you do not pass a third\n" "\ta bd_info struct will be passed instead\n" #endif ); ------------------------------------------------------------------------------------------- int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { ulong iflag; ulong addr; ulong data, len, checksum; ulong *len_ptr; uint unc_len = CFG_BOOTM_LEN; int i, verify; char *name, *s; int (*appl)(int, char *[]); image_header_t *hdr = &header; s = getenv ("verify"); verify = (s && (*s == 'n')) ? 0 : 1; if (argc < 2) { addr = load_addr; } else { addr = simple_strtoul(argv[1], NULL, 16); } SHOW_BOOT_PROGRESS (1); printf ("## Booting image at %08lx ...\n", addr); /* Copy header so we can blank CRC field for re-calculation */ #ifdef CONFIG_HAS_DATAFLASH if (addr_dataflash(addr)){ read_dataflash(addr, sizeof(image_header_t), (char *)&header); } else #endif memmove (&header, (char *)addr, sizeof(image_header_t)); if (ntohl(hdr->ih_magic) != IH_MAGIC) { #ifdef __I386__ /* correct image format not implemented yet - fake it */ if (fake_header(hdr, (void*)addr, -1) != NULL) { /* to compensate for the addition below */ addr -= sizeof(image_header_t); /* turnof verify, * fake_header() does not fake the data crc */ verify = 0; } else #endif /* __I386__ */ { puts ("Bad Magic Number\n"); SHOW_BOOT_PROGRESS (-1); return 1; } } SHOW_BOOT_PROGRESS (2); data = (ulong)&header; len = sizeof(image_header_t); checksum = ntohl(hdr->ih_hcrc); hdr->ih_hcrc = 0; if (crc32 (0, (uchar *)data, len) != checksum) { puts ("Bad Header Checksum\n"); SHOW_BOOT_PROGRESS (-2); return 1; } SHOW_BOOT_PROGRESS (3); #ifdef CONFIG_HAS_DATAFLASH if (addr_dataflash(addr)){ len = ntohl(hdr->ih_size) + sizeof(image_header_t); read_dataflash(addr, len, (char *)CFG_LOAD_ADDR); addr = CFG_LOAD_ADDR; } #endif /* for multi-file images we need the data part, too */ print_image_hdr ((image_header_t *)addr); data = addr + sizeof(image_header_t); len = ntohl(hdr->ih_size); if (verify) { puts (" Verifying Checksum ... "); if (crc32 (0, (uchar *)data, len) != ntohl(hdr->ih_dcrc)) { printf ("Bad Data CRC\n"); SHOW_BOOT_PROGRESS (-3); return 1; } puts ("OK\n"); } SHOW_BOOT_PROGRESS (4); len_ptr = (ulong *)data; #if defined(__PPC__) if (hdr->ih_arch != IH_CPU_PPC) #elif defined(__ARM__) if (hdr->ih_arch != IH_CPU_ARM) #elif defined(__I386__) if (hdr->ih_arch != IH_CPU_I386) #elif defined(__mips__) if (hdr->ih_arch != IH_CPU_MIPS) #elif defined(__nios__) if (hdr->ih_arch != IH_CPU_NIOS) #elif defined(__M68K__) if (hdr->ih_arch != IH_CPU_M68K) #elif defined(__microblaze__) if (hdr->ih_arch != IH_CPU_MICROBLAZE) #elif defined(__nios2__) if (hdr->ih_arch != IH_CPU_NIOS2) #elif defined(__blackfin__) if (hdr->ih_arch != IH_CPU_BLACKFIN) #elif defined(__avr32__) if (hdr->ih_arch != IH_CPU_AVR32) #else # error Unknown CPU type #endif { printf ("Unsupported Architecture 0x%x\n", hdr->ih_arch); SHOW_BOOT_PROGRESS (-4); return 1; } SHOW_BOOT_PROGRESS (5); switch (hdr->ih_type) { case IH_TYPE_STANDALONE: name = "Standalone Application"; /* A second argument overwrites the load address */ if (argc > 2) { hdr->ih_load = htonl(simple_strtoul(argv[2], NULL, 16)); } break; case IH_TYPE_KERNEL: name = "Kernel Image"; break; case IH_TYPE_MULTI: name = "Multi-File Image"; len = ntohl(len_ptr[0]); /* OS kernel is always the first image */ data += 8; /* kernel_len + terminator */ for (i=1; len_ptr[i]; ++i) data += 4; break; default: printf ("Wrong Image Type for %s command\n", cmdtp->name); SHOW_BOOT_PROGRESS (-5); return 1; } SHOW_BOOT_PROGRESS (6); /* * We have reached the point of no return: we are going to * overwrite all exception vector code, so we cannot easily * recover from any failures any more... */ iflag = disable_interrupts(); #ifdef CONFIG_AMIGAONEG3SE /* * We've possible left the caches enabled during * bios emulation, so turn them off again */ icache_disable(); invalidate_l1_instruction_cache(); flush_data_cache(); dcache_disable(); #endif switch (hdr->ih_comp) { case IH_COMP_NONE: if(ntohl(hdr->ih_load) == addr) { printf (" XIP %s ... ", name); } else { #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) size_t l = len; void *to = (void *)ntohl(hdr->ih_load); void *from = (void *)data; printf (" Loading %s ... ", name); while (l > 0) { size_t tail = (l > CHUNKSZ) ? CHUNKSZ : l; WATCHDOG_RESET(); memmove (to, from, tail); to += tail; from += tail; l -= tail; } #else /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */ memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len); #endif /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */ } break; case IH_COMP_GZIP: printf (" Uncompressing %s ... ", name); if (gunzip ((void *)ntohl(hdr->ih_load), unc_len, (uchar *)data, &len) != 0) { puts ("GUNZIP ERROR - must RESET board to recover\n"); SHOW_BOOT_PROGRESS (-6); do_reset (cmdtp, flag, argc, argv); } break; #ifdef CONFIG_BZIP2 case IH_COMP_BZIP2: printf (" Uncompressing %s ... ", name); /* * If we've got less than 4 MB of malloc() space, * use slower decompression algorithm which requires * at most 2300 KB of memory. */ i = BZ2_bzBuffToBuffDecompress ((char*)ntohl(hdr->ih_load), &unc_len, (char *)data, len, CFG_MALLOC_LEN < (4096 * 1024), 0); if (i != BZ_OK) { printf ("BUNZIP2 ERROR %d - must RESET board to recover\n", i); SHOW_BOOT_PROGRESS (-6); udelay(100000); do_reset (cmdtp, flag, argc, argv); } break; #endif /* CONFIG_BZIP2 */ default: if (iflag) enable_interrupts(); printf ("Unimplemented compression type %d\n", hdr->ih_comp); SHOW_BOOT_PROGRESS (-7); return 1; } puts ("OK\n"); SHOW_BOOT_PROGRESS (7); switch (hdr->ih_type) { case IH_TYPE_STANDALONE: if (iflag) enable_interrupts(); /* load (and uncompress), but don't start if "autostart" * is set to "no" */ if (((s = getenv("autostart")) != NULL) && (strcmp(s,"no") == 0)) { char buf[32]; sprintf(buf, "%lX", len); setenv("filesize", buf); return 0; } appl = (int (*)(int, char *[]))ntohl(hdr->ih_ep); (*appl)(argc-1, &argv[1]); return 0; case IH_TYPE_KERNEL: case IH_TYPE_MULTI: /* handled below */ break; default: if (iflag) enable_interrupts(); printf ("Can't boot image type %d\n", hdr->ih_type); SHOW_BOOT_PROGRESS (-8); return 1; } SHOW_BOOT_PROGRESS (8); switch (hdr->ih_os) { default: /* handled by (original) Linux case */ case IH_OS_LINUX: #ifdef CONFIG_SILENT_CONSOLE fixup_silent_linux(); #endif do_bootm_linux (cmdtp, flag, argc, argv, addr, len_ptr, verify); break; case IH_OS_NETBSD: do_bootm_netbsd (cmdtp, flag, argc, argv, addr, len_ptr, verify); break; #ifdef CONFIG_LYNXKDI case IH_OS_LYNXOS: do_bootm_lynxkdi (cmdtp, flag, argc, argv, addr, len_ptr, verify); break; #endif case IH_OS_RTEMS: do_bootm_rtems (cmdtp, flag, argc, argv, addr, len_ptr, verify); break; #if (CONFIG_COMMANDS & CFG_CMD_ELF) case IH_OS_VXWORKS: do_bootm_vxworks (cmdtp, flag, argc, argv, addr, len_ptr, verify); break; case IH_OS_QNX: do_bootm_qnxelf (cmdtp, flag, argc, argv, addr, len_ptr, verify); break; #endif /* CFG_CMD_ELF */ #ifdef CONFIG_ARTOS case IH_OS_ARTOS: do_bootm_artos (cmdtp, flag, argc, argv, addr, len_ptr, verify); break; #endif } SHOW_BOOT_PROGRESS (-9); #ifdef DEBUG puts ("\n## Control returned to monitor - resetting...\n"); do_reset (cmdtp, flag, argc, argv); #endif return 1; }