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的移植.
*/ 一、体验过程 .从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 <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. () type "make <board_name>_config" 这句话得知,我们必须先配置单板.
我们所选的单板为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 <configs/$1.h>" >>config.h 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 <configs/smdk2410.h> | CPU = arm920t |include/asm-arm/proc -> proc-armv |
| | BOARD = smdk2410 | |
| | SOC = s3c24x0 | |
-------------------------------------------------------------------------------------------------------------------------------|
-->在include/下生成了config.h<-- --> include/生成了config.mk <-- -->建立3个链接文件<--
================================================================================================================================ .继续分析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 |
| .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 ;
}
uboot-README_uboot分析的更多相关文章
- 嵌入式Linux驱动学习之路(四)u-boot编译分析
u-boot编译分析 在配置完成后,执行make开始编译.这里打开Makefile. 首先在目标all前有一句话首先检查是否有include/config.mk文件来判断是否成功配置过. ifeq ( ...
- ARM上电启动及Uboot代码分析
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/qianlong4526888/article/details/27698707 注意:由于文档是去年 ...
- 嵌入式Linux驱动学习之路(三)u-boot配置分析
u-boot配置流程分析 执行make tiny4412_config后,将会对u-boot进行一些列的配置,以便于后面的编译. 打开顶层目录下的Makefile,查找对于的规则tiny4412_co ...
- u-boot 流程分析
u-boot 介绍: 对于计算机来说 , 从一开始上机通电是无法直接启动操作系统的 , 这中间需要一个引导过程 , 嵌入式Linux系统同样离不开引导程序 , 这个启动程序就叫启动加载程序(Boot ...
- uboot命令分析+实现【转】
转自:http://xouou.iteye.com/blog/2150061 先贴一个重要结构,位于uboot/include/command.h,这个结构代表每个uboot命令 struct cmd ...
- u-boot学习(两):u-boot简要分析
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 看到不错的文章.不要加入收藏夹, ...
- U-Boot Makefile分析(5)主控Makefile分析
这次分析源码根目录下的Makefile,它负责读入配置过的信息,通过OBJS.LIBS等变量设置能够参与镜像链接的目标文件,设定编译的目标等等. HOSTARCH := $(shell uname - ...
- U-Boot Makefile分析(2) config.mk分析
浏览一下U-Boot各个子目录下的Makefile可以看到,几乎他们都会包含$(TOPDIR)/config.mk,那么这个文件进行了什么操作呢?简单概括:读入include/config.mk.in ...
- U-Boot Makefile分析(1)配置脚本mkconfig分析
我们在编译U-Boot之前,需要根据当前使用的板子进行配置,例如make s5p_goni_config,接着才能进行编译make.下面首先分析配置阶段U-Boot做了哪些事情. 由于执行这些命令是在 ...
- 4412 uboot启动分析
感谢sea1105, https://blog.csdn.net/sea1105/article/details/52142772 在学习过程中,由于tiny4412资料太过于少,因此参考210的视屏 ...
随机推荐
- 2017"百度之星"程序设计大赛 - 资格赛 度度熊的王国战略
度度熊的王国战略 度度熊国王率领着喵哈哈族的勇士,准备进攻哗啦啦族. 哗啦啦族是一个强悍的民族,里面有充满智慧的谋士,拥有无穷力量的战士. 所以这一场战争,将会十分艰难. 为了更好的进攻哗啦啦族,度度 ...
- Influxdb 时序数据库 centos 安装
Influxdb 环境搭建 操作系统:CentOS 7 X64 SSH工具:PuTTY 操作系统安装,请参照官网文档进行:https://www.centos.org/ 使用PuTTY 通过ssh连接 ...
- [aspnetcore]asp.net core程序部署到Ubuntu中的路径问题
先标记下正确写法 new FileInfo(Environment.CurrentDirectory + "/Config/Log4net.config") 很多同行喜欢这样写: ...
- python学习之内部函数:
python内置函数表:https://docs.python.org/3/library/functions.html 1 判断数据类型的函数:isinstance(变量, 待要判断的类型) 2判断 ...
- [在读]JavaScript异步编程:设计快速响应的网络应用
很棒的一本,就如书名所示,主要讲js异步的一些东西,比如定时器.Jquery的promise和deffered,node...看了一小半.推荐哦~~
- 07.Javascript——入门高阶函数
高阶函数英文叫Higher-order function..JavaScript的函数其实都指向某个变量.既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数 ...
- vue http请求 vue-resource使用方法
1.安装vue-resource扩展: npm install vue-resource 2.在main.js中引入 import http from 'vue-resource' 3.使用方法 // ...
- jQuery选择器之样式二
prop()方法和attr()类似,但是HTML5规定有一种属性在DOM节点中可以没有值,只有出现与不出现两种,例如: <input id="test-radio" type ...
- CommonJS与ES6、AMD、CMD比较
Javascript,javascript是一种脚本编程语言,有自己独立的语法与语义,没有javascript,也就没有其他的那些概念了. 关于ES6,可直接理解为javascript的增强版(增加了 ...
- Android项目中包名的修改
通常修改包名时会造成R文件错误,并且有时带有原因不明的Manifest文件中多处文本混乱. 所以,将目前认为最为简洁方便的修改包名流程记录如下: 假设我们目前的包名为com.pepper.util,我 ...