/*
#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的移植.
*/
一、体验过程
.从u-boot官网下载 u-boot-1.1..tar.bz2 源码.
.解压
tar xvf u-boot-1.1..tar.bz2
.进入u-boot-1.1./ 目录
book@book-desktop:/work/system/u-boot-1.1.$ cd u-boot-1.1./
book@book-desktop:/work/system/u-boot-1.1.$ 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. 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
.尝试一下,观察现象
book@book-desktop:/work/system/u-boot-1.1.$ make
System not configured - see README #提示 系统没有配置 -看 README
make: *** [all] Error
.按照提示,打开u-boot根目录下的README文档(如果有时间多看看,这里我们选取最重要的信息来分析)
()以下是从README中截取的内容:
Selection of Processor Architecture and Board Type:
For all supported boards there are ready-to-use default
configurations available; just type "make
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.
() type "make
我们所选的单板为smdk2410,所以 在u-boot-1.1./目录下输入 make smdk2410_config
然后输入make就OK了.(当然,前提是你的交叉编译环境必须是正确的.这是必须的).
()终端上操作过程:
book@book-desktop:/work/system/u-boot-1.1.$ make smdk2410_config
Configuring for smdk2410 board…
book@book-desktop:/work/system/u-boot-1.1.$ 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
()可以看出已经生产 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:
. 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下添加 有关"用户单板"配置选项 \*/
. 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\*/
. Create a new configuration file "include/configs/<board>.h" for
your board
/\* 3.在include/configs目录下为你的单板创建一个新的配置文件<board>.h \*/
. 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特定的代码,添加你需要的一些文件 \*/
. Run "make <board>\_config" with your new name.
/\* 4.配置单板,在串口终端输入:make <board>\_config \*/
. Type "make", and you should get a working "u-boot.srec" file
to be installed on your target system.
/\* 5.输入make,会在目标系统上生成一个可执行文件u-boot.srec \*/
. Debug and solve any problems that might arise.
\[Of course, this last step is much harder than it sounds.\]
/\* 6.调试和解决任何可能产生的问题 \*/
b.还有这个过程到底是如何实现的呢?
PS:怎么组织实现,见我们第二步.分析makefile及其他相关文件.
二、分析makefile及其他一些相关的文件
.分析makefile,我们还得从前面的 make smdk2410\_config 开始分析.
()在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个参数.
()分析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 \] ; 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-$ asm /* asm是编译时临时生成指向某个架构,ln 建立一个链接文件 asm -> asm-arm */ ;include/asm -> asm-arm
fi
rm -f asm-$/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-$ asm-$/arch /* LNPREFIX 没有定义, asm-arm/arch->arch-s3c24x0*/ ;include/asm-arm/arch -> arch-s3c24x0
fi
if \[ "$2" = "arm" \] ; then
rm -f asm-$/proc /\* rm -f asm-arm/proc \*/
ln -s ${LNPREFIX}proc-armv asm-$/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
exit
=======================================================编译成功后===============================================================
-------------------------------------------------------------------------------------------------------------------------------|
|include/config.h : |include/config.mk : |include/asm -> asm-arm |
|/* Automatically generated - do not edit */ | ARCH = arm |include/asm-arm/arch -> arch-s3c24x0|
|#include
| | BOARD = smdk2410 | |
| | SOC = s3c24x0 | |
-------------------------------------------------------------------------------------------------------------------------------|
.继续分析makefile. 在终端(我使用的是串口)输入make,分析串口打印出的信息,继续深入.
注意:这里我们来约定几个符号,方便分析makefile及其关联的文件
①<<==>> 表示: 等价于
②/\* \*/ 表示: 注释,一般用于说明变量的含义或者其来源.
()打开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 ,因为这个文件中无处不在!
()打开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
.分析代码启动流程.
().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, #* /* r2=30+34=0x64 */ |
| : |
| /* write SMRDATA to BWSCON <--> init SDRAM*/ |
| ldr r3, [r0], # /* [r0]=[0x33f80430] */ |
| str r3, [r1], # /* [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 (+(B1_BWSCON<<)+(B2_BWSCON<<)+(B3_BWSCON<<)+(B4_BWSCON<<)+(B5_BWSCON<<)+(B6_BWSCON<<)+(B7_BWSCON<<)) |
| .word ((B0_Tacs<<)+(B0_Tcos<<)+(B0_Tacc<<)+(B0_Tcoh<<)+(B0_Tah<<)+(B0_Tacp<<)+(B0_PMC)) |
| .word ((B1_Tacs<<)+(B1_Tcos<<)+(B1_Tacc<<)+(B1_Tcoh<<)+(B1_Tah<<)+(B1_Tacp<<)+(B1_PMC)) |
| .word ((B2_Tacs<<)+(B2_Tcos<<)+(B2_Tacc<<)+(B2_Tcoh<<)+(B2_Tah<<)+(B2_Tacp<<)+(B2_PMC)) |
| .word ((B3_Tacs<<)+(B3_Tcos<<)+(B3_Tacc<<)+(B3_Tcoh<<)+(B3_Tah<<)+(B3_Tacp<<)+(B3_PMC)) |
| .word ((B4_Tacs<<)+(B4_Tcos<<)+(B4_Tacc<<)+(B4_Tcoh<<)+(B4_Tah<<)+(B4_Tacp<<)+(B4_PMC)) |
| .word ((B5_Tacs<<)+(B5_Tcos<<)+(B5_Tacc<<)+(B5_Tcoh<<)+(B5_Tah<<)+(B5_Tacp<<)+(B5_PMC)) |
| .word ((B6_MT<<)+(B6_Trcd<<)+(B6_SCAN)) |
| .word ((B7_MT<<)+(B7_Trcd<<)+(B7_SCAN)) |
| .word ((REFEN<<)+(TREFMD<<)+(Trp<<)+(Trc<<)+(Tchr<<)+REFCNT) |
| .word 0x32 |
| .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, # /\* 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, #
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, , sizeof (gd\_t));/\* 初始化一块内存,清除gd 所指的内存 \*/
gd->bd = (bd\_t\*)((char\*)gd - sizeof(bd\_t)); /\* bd也是一个结构体(bd\_info) , \*/
memset (gd->bd, , 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)() != ) {
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
# endif
/\*
\* reserve memory for VFD display (always full pages)
\*/
/\* bss\_end is defined in the board-specific linker script \*/
addr = (\_bss\_end + (PAGE\_SIZE - )) & ~(PAGE\_SIZE - );
size = vfd\_setmem (addr);
gd->fb\_base = addr;
#endif /\* CONFIG\_VFD \*/
#ifdef CONFIG\_LCD
# ifndef PAGE\_SIZE
# define PAGE\_SIZE
# endif
/\*
\* reserve memory for LCD display (always full pages)
\*/
/\* bss\_end is defined in the board-specific linker script \*/
addr = (\_bss\_end + (PAGE\_SIZE - )) & ~(PAGE\_SIZE - ); /\* (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\[\];
i = getenv\_r ("ethaddr", tmp, sizeof (tmp));
s = (i > ) ? tmp : NULL;
for (reg = ; reg < ; ++reg) {
gd->bd->bi\_enetaddr\[reg\] = s ? simple\_strtoul (s, &e, ) : ;
if (s)
s = (\*e) ? e + : e;
}
#ifdef CONFIG\_HAS\_ETH1
i = getenv\_r ("eth1addr", tmp, sizeof (tmp));
s = (i > ) ? tmp : NULL;
for (reg = ; reg < ; ++reg) {
gd->bd->bi\_enet1addr\[reg\] = s ? simple\_strtoul (s, &e, ) : ;
if (s)
s = (\*e) ? e + : 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, );
}
#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\] = { , };
int len;
int rc = ;
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 = ;
unsigned long bootlimit = ;
char \*bcs;
char bcs\_set\[\];
#endif /\* CONFIG\_BOOTCOUNT\_LIMIT \*/
#if defined(CONFIG\_VFD) && defined(VFD\_TEST\_LOGO)
ulong bmp = ; /\* default bitmap \*/
extern int trab\_vfd (ulong bitmap);
#ifdef CONFIG\_MODEM\_SUPPORT
if (do\_mdm\_init)
bmp = ; /\* 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, ) : ;
#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(); /\* disable Control C checking \*/
# endif
# ifndef CFG\_HUSH\_PARSER
run\_command (p, );
# 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, ) : 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 >= && s && !abortboot (bootdelay)) {
# ifdef CONFIG\_AUTOBOOT\_KEYED
int prev = disable\_ctrlc(); /\* disable Control C checking \*/
# endif
# ifndef CFG\_HUSH\_PARSER
run\_command (s, );
# 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, );
# 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 >= ) {
/\* Saw enough of a valid command to
\* restart the timeout.
\*/
reset\_cmd\_timeout();
}
#endif
len = readline (CFG\_PROMPT);
flag = ; /\* assume no special flags for now \*/
if (len > )
strcpy (lastcommand, console\_buffer);
else if (len == )
flag |= CMD\_FLAG\_REPEAT;
#ifdef CONFIG\_BOOT\_RETRY\_TIME
else if (len == -) {
/\* -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, , , NULL);
# else
return; /\* retry autoboot \*/
# endif
}
#endif
if (len == -)
puts ("<INTERRUPT>\\n");
else
rc = run\_command (lastcommand, flag);
if (rc <= ) {
/\* invalid command or not repeatable, forget it \*/
lastcommand\[\] = ;
}
}
#endif /\*CFG\_HUSH\_PARSER\*/
}
===========================================================================================================
E:2个比较重要的函数
void setenv (char \*varname, char \*varvalue)
{
char \*argv\[\] = { "setenv", varname, varvalue, NULL };
\_do\_setenv (, , 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=; env\_get\_char(i) != '\\0'; i=nxt+) {
int val;
for (nxt=i; env\_get\_char(nxt) != '\\0'; ++nxt) {
if (nxt >= CFG\_ENV\_SIZE) {
return (NULL);
}
}
if ((val=envmatch((uchar \*)name, i)) < )
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 + \]; /\* NULL terminated \*/
int argc, inquotes;
int repeatable = ;
int rc = ;
#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 -; /\* empty command \*/
}
if (strlen(cmd) >= CFG\_CBSIZE) {
puts ("## Command too long!\\n");
return -;
}
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 = , sep = str; \*sep; sep++) {
if ((\*sep=='\\'') &&
(\*(sep-) != '\\\\'))
inquotes=!inquotes;
if (!inquotes &&
(\*sep == ';') && /\* separator \*/
( sep != str) && /\* past string start \*/
(\*(sep-) != '\\\\')) /\* and NOT escaped \*/
break;
}
/\*
\* Limit the token to data between separators
\*/
token = str;
if (\*sep) {
str = sep + ; /\* 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)) == ) {
rc = -; /\* no command at all \*/
continue;
}
/\* Look up command in command table \*/
if ((cmdtp = find\_cmd(argv\[\])) == NULL) {
printf ("Unknown command '%s' - try 'help'\\n", argv\[\]);
rc = -; /\* give up after bad command \*/
continue;
}
/\* found - check max args \*/
if (argc > cmdtp->maxargs) {
printf ("Usage:\\n%s\\n", cmdtp->usage);
rc = -;
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 = -;
continue;
} else {
flag |= CMD\_FLAG\_BOOTD;
}
}
#endif /\* CFG\_CMD\_BOOTD \*/
/\* OK - call function to do the command \*/
if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != ) {
rc = -;
}
repeatable &= cmdtp->repeatable;
/\* Did the user stop this? \*/
if (had\_ctrlc ())
return ; /\* if stopped then not repeatable \*/
}
return rc ? rc : repeatable;
}
F:解析 U\_BOOT\_CMD 命令! |
:宏定义 |
#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")))
:举例分析:
U\_BOOT\_CMD(
flinfo, , , 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"
);
:函数原型 |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 == ) { /\* print info for all FLASH banks \*/ |#endif
for (bank=; bank <CFG\_MAX\_FLASH\_BANKS; ++bank) { |#ifdef CONFIG\_AUTO\_COMPLETE
printf ("\\nBank # %ld: ", bank+); | /\* 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 ; |--------------------------------------------------------------------------------------
} |unsigned long simple\_strtoul(const char \*cp,char \*\*endp,unsigned int base)
|{
bank = simple\_strtoul(argv\[\], NULL, ); | unsigned long result = ,value;
if ((bank < ) || (bank > CFG\_MAX\_FLASH\_BANKS)) { |
printf ("Only FLASH Banks # 1 ... # %d supported\\n", | if (\*cp == '') {
CFG\_MAX\_FLASH\_BANKS); | cp++;
return ; | if ((\*cp == 'x') && isxdigit(cp\[\])) {
} | base = ;
printf ("\\nBank # %ld: ", bank); | cp++;
flash\_print\_info (&flash\_info\[bank-\]); | }
return ; | if (!base) {
} | base = ;
| }
| }
| if (!base) {
| base = ;
| }
| while (isxdigit(\*cp) && (value = isdigit(\*cp) ? \*cp-'' : (islower(\*cp)
| ? toupper(\*cp) : \*cp)-'A'+) < base) {
| result = result\*base + value;
| cp++;
| }
| if (endp)
| \*endp = (char \*)cp;
| return result;
| }
.u-boot的最终目的是:启动内核
U\_BOOT\_CMD(
bootm, CFG\_MAXARGS, , 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')) ? : ;
if (argc < ) {
addr = load\_addr;
} else {
addr = simple\_strtoul(argv\[\], NULL, );
}
SHOW\_BOOT\_PROGRESS ();
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, -) != NULL) {
/\* to compensate for the addition below \*/
addr -= sizeof(image\_header\_t);
/\* turnof verify,
\* fake\_header() does not fake the data crc
\*/
verify = ;
} else
#endif /\* \_\_I386\_\_ \*/
{
puts ("Bad Magic Number\\n");
SHOW\_BOOT\_PROGRESS (-);
return ;
}
}
SHOW\_BOOT\_PROGRESS ();
data = (ulong)&header;
len = sizeof(image\_header\_t);
checksum = ntohl(hdr->ih\_hcrc);
hdr->ih\_hcrc = ;
if (crc32 (, (uchar \*)data, len) != checksum) {
puts ("Bad Header Checksum\\n");
SHOW\_BOOT\_PROGRESS (-);
return ;
}
SHOW\_BOOT\_PROGRESS ();
#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 (, (uchar \*)data, len) != ntohl(hdr->ih\_dcrc)) {
printf ("Bad Data CRC\\n");
SHOW\_BOOT\_PROGRESS (-);
return ;
}
puts ("OK\\n");
}
SHOW\_BOOT\_PROGRESS ();
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 (-);
return ;
}
SHOW\_BOOT\_PROGRESS ();
switch (hdr->ih\_type) {
case IH\_TYPE\_STANDALONE:
name = "Standalone Application";
/\* A second argument overwrites the load address \*/
if (argc > ) {
hdr->ih\_load = htonl(simple\_strtoul(argv\[\], NULL, ));
}
break;
case IH\_TYPE\_KERNEL:
name = "Kernel Image";
break;
case IH\_TYPE\_MULTI:
name = "Multi-File Image";
len = ntohl(len\_ptr\[\]);
/\* OS kernel is always the first image \*/
data += ; /\* kernel\_len + terminator \*/
for (i=; len\_ptr\[i\]; ++i)
data += ;
break;
default: printf ("Wrong Image Type for %s command\\n", cmdtp->name);
SHOW\_BOOT\_PROGRESS (-);
return ;
}
SHOW\_BOOT\_PROGRESS ();
/\*
\* 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 > ) {
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) != ) {
puts ("GUNZIP ERROR - must RESET board to recover\\n");
SHOW\_BOOT\_PROGRESS (-);
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 < ( \* ), );
if (i != BZ\_OK) {
printf ("BUNZIP2 ERROR %d - must RESET board to recover\\n", i);
SHOW\_BOOT\_PROGRESS (-);
udelay();
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 (-);
return ;
}
puts ("OK\\n");
SHOW\_BOOT\_PROGRESS ();
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") == )) {
char buf\[\];
sprintf(buf, "%lX", len);
setenv("filesize", buf);
return ;
}
appl = (int (\*)(int, char \*\[\]))ntohl(hdr->ih\_ep);
(\*appl)(argc-, &argv\[\]);
return ;
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 (-);
return ;
}
SHOW\_BOOT\_PROGRESS ();
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 (-);
#ifdef DEBUG
puts ("\\n## Control returned to monitor - resetting...\\n");
do\_reset (cmdtp, flag, argc, argv);
#endif
return ;
}
手机扫一扫
移动阅读更方便
你可能感兴趣的文章