uboot-README_uboot分析

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/ 目录
    [email protected]-desktop:/work/system/u-boot-1.1.6$  cd u-boot-1.1.6/
    [email protected]-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.尝试一下,观察现象
    [email protected]-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 <board_name>_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 <board_name>_config" 这句话得知,我们必须先配置单板.
          我们所选的单板为smdk2410,所以 在u-boot-1.1.6/目录下输入 make smdk2410_config
          然后输入make就OK了.(当然,前提是你的交叉编译环境必须是正确的.这是必须的).

  (3)终端上操作过程:
      [email protected]-desktop:/work/system/u-boot-1.1.6$ make smdk2410_config
    Configuring for smdk2410 board...
      [email protected]-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 "<board>.c", "flash.c" and "u-boot.lds".
                /* 2.创建一个新的文件来保存单板的特点代码,至少需要4个文件 Makefile <board>.c flash.c  u-boot.lds*/     

            3.  Create a new configuration file "include/configs/<board>.h" for
                your board
                /* 3.在include/configs目录下为你的单板创建一个新的配置文件<board>.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 <board>_config" with your new name.
                    /* 4.配置单板,在串口终端输入:make <board>_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 <configs/smdk2410.h>                         |   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 <configs/$1.h>" >>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 <configs/smdk2410.h>                         |              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 $< [email protected]               /* 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 $< [email protected]  

         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 [email protected]                                                        |                                                    |
//                      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 >> [email protected] ; \|                                                    |
                                                                 |        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),[email protected],$(notdir [email protected]))

                        /* $(if $(REMOTE_BUILD),[email protected],$(notdir [email protected]))  -> 如果定义了 则表达式为 [email protected] 否则,表达式为$(notdir [email protected]) */
                        /* notdir函数用于 从[email protected]路径中 抽取 文件名 */

                        <<==>>
                        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) [email protected] $(OBJS)                                           |
                        |                                                                              |
                        |#########################################################################     |
                        |                                                                              |
                        |# defines $(obj).depend target                                                |
                        |include $(SRCTREE)/rules.mk                                                   |
                        |                                                                              |
                        |sinclude $(obj).depend                                                        |
                        |                                                                              |
                        |#########################################################################     |
                        |------------------------------------------------------------------------------|
                        */

                    (E)$(LIBS)
                        $(LIBS):
                              $(MAKE) -C $(dir $(subst $(obj),,[email protected]) )/* 删除$(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) [email protected] $(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 [email protected]                                                             ||        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 >> [email protected] ; \     ||              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 >> [email protected] ; \    -->>自动生成依赖 , -M / -MQ     并把这个依赖(规则) 写入到 [email protected](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 : "<UNDEFINED>");  

          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 ("<INTERRUPT>\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 <CFG_MAX_FLASH_BANKS; ++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;
    }                      
时间: 2024-11-02 09:36:23

uboot-README_uboot分析的相关文章

Linux嵌入式驱动学习之路④u-boot编译分析

u-boot编译分析 在配置完成后,执行make开始编译.这里打开Makefile. 首先包含在配置时生成的config.mk all: sinclude $(obj)include/autoconf.mk.dep sinclude $(obj)include/autoconf.mk # load ARCH, BOARD, and CPU configuration include $(obj)include/config.mk //配置时生成的 export ARCH CPU BOARD VE

ARM上电启动及Uboot代码分析

注意:由于文档是去年写的,内有多个图片,上传图片很麻烦(需要截图另存插入等等),我把文章的PDF版本上传到了CSDN下载资源中.为了给自己赚点积分,所以标价2分,没有积分的同学可以直接留言跟我要,记得留下邮箱. 以下是文章内容,由于我懒得编辑图片了,所以文章看来会很不爽,强烈推荐点击以上红色链接下载pdf版. 文件编号:DCC01 版本号:1.0 ARM上电启动及Uboot代码分析 部    门:                          作    者:                 

u-boot学习(二):u-boot简要分析

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 看到不错的文章,不要添加收藏夹,想着以后有时间再看,因为很有可能你以后再也不会看它们了. 想写总结的文章,不要想着等到以后有时间了再总结,因为很有可能你以后更没有时间总结它们了. --送给自己 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Tiny4412 uboot Makefile 分析

* Build uboot a) 安装好toolchain (arm-linux-gcc-4.5.1-v6-vfp-20120301.tgz)并设置好 环境变量PATH,保证可以正常使用.b) 解压 uboot_tiny4412-20130729.tgz 并进入相应的目录 tar xzf uboot_tiny4412-20130729.tgzc) 配置 uboot 并编译 cd uboot_tiny4412 make tiny4412_config maked) 编译 用于生成bl2 的工具 m

u-boot学习(两):u-boot简要分析

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 看到不错的文章.不要加入收藏夹,想着以后有时间再看.由于非常有可能你以后再也不会看它们了. 想写总结的文章.不要想着等到以后有时间了再总结,由于非常有可能你以后更没有时间总结它们了. --送给自己 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

uboot移植一uboot架构分析

开发环境: 1 .开发板mini2440 2. u-boot-2010.12 参考i资料:https://blog.csdn.net/androidbbc/article/details/50961163 http://www.cnblogs.com/kele-dad/p/8969174.html 一.下载u-boot- 2010.12,并且解压 二.分析u-boor-2010.12 api: 存放uboot提供的接口函数 config.mk: 根据不同开发板定制的代码,代码也不少 driver

一,移植uboot,分析uboot启动流程

文档时间:2018-08-08 交叉编译器:arm-linux-gcc-4.3.2 Ubuntu版本:16.04 uboot版本:2013.10 uboot启动流程简要如下: a,设置CPU为管理模式 b,关闭看门狗 c,关闭中断 d,设置时钟频率 e,进入lowlevel_init.S,初始化各个bank f,进入board_init_f()函数 h,代码重定位,清除bss i,跳转到board_init_r(),进入第二阶段 1,进入https://www.amazon.com/cloudd

U-Boot的分析与移植之U-Boot的主要目录及结构

U-Boot官方下载网站: ftp://ftp.denx.de/pub/u-boot/ 这个网址是德国denx 软件中心提供的ftp下载集合 以U-Boot 2013.10为例: U-Boot-2010.03主要的目录结构及说明 Cpu 体系结构专有文件对应不同CPU,如arm720t,arm920t,arm1136等: Api 外部程序使用的与体系无关的API Board 包括不同配置类型的开发板(即使CPU相同),如smdk2410,sbc2410x; Common 通用函数,多是对下一层驱

u-boot分析(十一)----MMU简单分析|u-boot分析大结局|学习规划

u-boot分析(十一) 通过前面十篇博文,我们已经完成了对BL1阶段的分析,通过这些分析相信我们对u-boot已经有了一个比较深入的认识,在BL2阶段大部分是对外设的初始化,并且有的我们已经分析过,在这篇博文我打算对BL1阶段没有分析到的重要外设进行简单分析,并结束对u-boot的分析,同时对后面自己的博文进行简单的规划,希望有兴趣的朋友跟我一块学习和研究嵌入式. 今天我们会分析到以下内容: 1.      MMU分析(内容出自我以前的博客) 2.      裸机开发总结 3.      后期

U-Boot启动过程--详细版的完全分析2

一.初识u-boot 3 1,Bootloader介绍 3 2,Bootloader的启动方式 3 (1)网络启动方式 4 (2)磁盘启动方式 4 (3)Flash启动方式 4 3,U-boot的定义 4 4,u-boot源代码的目录结构 4 5,U-boot中的地址 5 (1)什么是编译地址?什么是运行地址? 5 (2)编译地址和运行地址如何来算呢? 5 (3)为什么要分配编译地址?这样做有什么好处,有什么作用? 5 (4)什么是相对地址? 6 (5)如何去做呢? 6 二.U-Boot总体分析