用这个文件u-boot-1.1.6进行说明
配置步骤(以s3c2440为例):
tar -jxvf u-boot-1.1.6.tar.bz2//解压
make smdk2410_config//makefile中的配置项
make//编译
配置说明:
查找makefile中的配置项smdk2410_config(在makefile的1879行)
smdk2410_config : unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0
这行的意思是以smdk2410_config为目标,依赖unconfig
1,在makefile中搜索"unconfig",发现在338行定义,如下主要是删除一些配置文件
unconfig:
@rm -f $(obj)include/config.h $(obj)include/config.mk \
$(obj)board/*/config.tmp $(obj)board/*/*/config.tmp
2,依赖目标执行完,下面执行目标:
@$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0
看这行的第一个符号@,在Makefile中以@开头的命令表示,在命令执行的时候不在终端上打印信息
搜索"MKCONFIG"看看在哪定义,在92行
MKCONFIG := $(SRCTREE)/mkconfig
SRCTREE这个变量表示根目录,MKCONFIG即是根目录下面的mkconfig文件,执行这个脚本文件。
$(@:_config=)这句话的意思是将目标($(@) = $@)smdk2410_config的_config用空白代替,只剩下smdk2410。
后面的smdk2410 arm arm920t smdk2410 NULL s3c24x0都是以传参的方式进行
$1:smdk2410
$2: arm
$3: arm920t
$4: smdk2410
$5: NULL
$6: s3c24x0
所以,$# = 6,6个参数
分析mkconfig脚本文件
14-21行:
while [ $# -gt 0 ] ; do
case "$1" in
--) shift ; break ;;
-a) shift ; APPEND=yes ;;
-n) shift ; BOARD_NAME="${1%%_config}" ; shift ;;
*) break ;;
esac
done
传入6个参数,传进去用switch语句来判断是哪个case,在脚本里case是会自动跳出的,
如果加了break表示跳出while循环,且*表示任何情况。
23行:
[ "${BOARD_NAME}" ] || BOARD_NAME="$1"
可以理解为简列的if语句,如果${BOARD_NAME}成立BOARD_NAME=“$1"就不执行。
由前面的 BOARD_NAME="" 可知,BOARD_NAME为空,BOARD_NAME=“$1"执行,BOARD_NAME=smdk2410。
25-28行:
[ $# -lt 4 ] && exit 1
[ $# -gt 6 ] && exit 1
echo "Configuring for ${BOARD_NAME} board..."
if($#<4) return 1,if($#>6) return 1,传参只能是4,5,6。
打印出"Configuring for ${BOARD_NAME} board..."
33-63行:创建符号链接
if [ "$SRCTREE" != "$OBJTREE" ] ; then //SRCTREE和OBJTREE默认情况下是一样的,都是根目录,这个if条件不成立,执行else
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 //进入inlcude目录
rm -f asm //创建之前先确定没有这个目录,这里先强制删除下
ln -s asm-$2 asm //在include目录下创建asm文件,指向asm-arm
fi
rm -f asm-$2/arch //创建之前先确定没有这个目录,这里先强制删除下
if [ -z "$6" -o "$6" = "NULL" ] ; then //参数6即不为0,也不为NULL,执行else
ln -s ${LNPREFIX}arch-$3 asm-$2/arch
else
ln -s ${LNPREFIX}arch-$6 asm-$2/arch //在include/asm目录下创建arch文件,指向include/asm目录下的arch-s3c24x0
fi
if [ "$2" = "arm" ] ; then
rm -f asm-$2/proc
ln -s ${LNPREFIX}proc-armv asm-$2/proc //在include/asm目录下创建proc文件,指向include/asm目录下的proc-armv
fi
67-73行:创建文件
echo "ARCH = $2" > config.mk //ARCH = arm
echo "CPU = $3" >> config.mk //CPU = arm920t
echo "BOARD = $4" >> config.mk //BOARD = smdk2410
[ "$5" ] && [ "$5" != "NULL" ] && echo "VENDOR = $5" >> config.mk
[ "$6" ] && [ "$6" != "NULL" ] && echo "SOC = $6" >> config.mk //SOC = s3c24x0
"<" 这个是创建一个文件,把前面的内容加到文件中
"<<" 添加内容到文件中
创建 config.mk 在include目录,并加入了4行代码
78-87行: 创建板级头文件
if [ "$APPEND" = "yes" ] # Append to existing config file
then
echo >> config.h
else
> config.h # Create new config file //创建文件在include目录
fi
echo "/ Automatically generated - do not edit /" >>config.h
echo "#include <configs/$1.h>" >>config.h //加入一行 #include <configs/smdk2410.h>
exit 0
make 过程分析
在makefile中找第一个目标
241行:
all: $(ALL)
ALL = $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND)
目标是生成u-boot相关文件
从第1行查看相关变量的定义
24-42行:
生成相关u-boot版本号,include/version_autogenerated.h,里面是一个宏
HOSTARCH 主机的CPU架构
HOSTOS 主机的操作系统
69-90行:
工程输出文件与根文件目录,这个没有指定是一样的。
92-93行:
引入mkconfig配置文件,这个在上面说过了
117-118行:
加入配置时生成的include/config.mk
120-161行:
配置交叉工具链,关注arm的就行,写成与当前环境一样的
169-215行:
u-boot包括的工程文件
OBJS = cpu/$(CPU)/start.o //CPU = arm920t BOARDDIR BOARD = smdk2410 SOC = s3c24x0
LIBS = lib_generic/libgeneric.a
LIBS += board/$(BOARDDIR)/lib$(BOARD).a // board/smdk2410/libsmdk2410.a
LIBS += cpu/$(CPU)/lib$(CPU).a // cpu/arm920t/libarm920t.a
LIBS += cpu/$(CPU)/$(SOC)/lib$(SOC).a // cpu/arm920t/s3c24x0/libs3c24x0.a
LIBS += lib_$(ARCH)/lib$(ARCH).a // lib_arm/libarm.a
下面的不重要了
239行:
这一行是第一个目标,当我们输入make时,这一行被执行
来看看链接脚本u-boot.lds
u-boot-1.1.6\board\smdk2410\u-boot.lds
ENTRY(_start) //入口地址
SECTIONS
{
. = 0x00000000; //首地址,注意这里还会加上链接地址0x33F80000
. = ALIGN(4); //以4字节对齐
.text : //代码段
{
cpu/arm920t/start.o (.text) //首先放.text
*(.text)
}
. = ALIGN(4);
.rodata : { *(.rodata) } //只读数据
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
.got : { *(.got) }
. = .;
__u_boot_cmd_start = .; //命令
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;
. = ALIGN(4); //bss段
__bss_start = .;
.bss : { *(.bss) }
_end = .;
}
链接地址在u-boot-1.1.6\board\smdk2410\config.mk 里面有个宏比较重要 TEXT_BASE = 0x33F80000
grep -nr 0x33F80000 *
find -name config.mk
start.S (第一个被编译的)
先看头文件,这两个都是include目录下的
include <config.h> //配置时生成的,里面是 #include <configs/smdk2410.h> 各种控制编译的宏
include <version.h> //这个u-boot的版本号
_start: b reset
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
这是u-boot的异常向量表,先进入reset(其他没有设置,都是死循环)
.balignl 16,0xdeadbeef. 这一句指令是让当前地址对齐排布
110行:
reset :
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr,r0
这个是set the cpu to SVC32 mode,读改写
119-134行:
这里说一点,在source insight创建工程时把需要的文件加上去,这样会方便很多,
如配置文件configs/smdk2410.h加上去,里面是一些宏包含上的话,在查看时会自动变红,如这里是CONFIG_S3C2410
定义了看门狗,中断控制器,子中断控制器,时钟分频器寄存器
关看门狗时,寄存器写0即可
139-146行:
关闭所有中断,包括子中断
150-152行:
设置时钟,FCLK:HCLK:PCLK = 1:2:4,default FCLK is 120 MHz
159行:
如果没有定义CONFIG_SKIP_RELOCATE_UBOOT,则执行cpu_init_crit
只在重新启动时进行系统关键初始化,而不是从ram启动时,当ram启动后这步不需要执行
来看看cpu_init_crit:
前几行主要关MMU和caches,然后执行lowlevel_init
初始化sdram
164行:
重定位 relocate
adr r0, _start / r0 当前代码_start的位置 /
ldr r1, _TEXT_BASE /* r1 链接地址的位置 */
cmp r0, r1 /* 比较是否相等 */
beq stack_setup // 相等则跳转,设置栈
ldr r2, _armboot_start //_start的地址
ldr r3, _bss_start //_bss_start的地址
sub r2, r3, r2 /* r2 代码段的大小 */
add r2, r0, r2 /* r2 末尾地址 */
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
stack_setup:
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
sub r0, r0, #CFG_MALLOC_LEN /* 减去堆的大小 */
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 /* 预留3个字给溢出堆栈 */
清bss段
223行:
进入start_armboot,第二阶段
cpu_init
什么都没做
board_init
设置时钟,寄存器,机械id,环境变量地址,使能icache,dcache
interrupt_init
什么都没做
env_init
gd->env_addr = (ulong)&default_environment[0];
gd->env_valid = 0;
init_baudrate
获得波特率从环境变量
serial_init
什么都没做
console_init_f
gd->have_console = 1;
display_banner
printf ("\n\n%s\n\n", version_string);
打印下版本号什么的
用这个文件u-boot-2012.04.01进行说明
从版本发布的命名上来看,现在的UBOOT不再用以前版本号的方式进行描述。而采用日期的方式进行发布
现在UBOOT的架构已经发生了一个结构上的新转变,主要就是Makefile的功能更加专一化了,
板子的配置被移出了Makefile,放到了一个叫做boards.cfg的文件中
旧版本的cpu目录,在新版本下位于新增的arch目录下,这样的改变时目录结构更明确
旧版本 cpu
新版本 arch/cpu
对于移植中的make <board_name>_config命令
旧版本 顶级Makefile中修改
新版本 boards.cfg中修改
这里boards.cfg文件是新增的,在旧版本是没有的
arch:体系架构,比如 arm、 x86、 mips 等
cpu: cpu 类型,比如 arm920t、 arm11 等
board:单板名称,比如 smdk2410、 smdkc100 等
vendor:厂商名称,比如 samsung、 freescale 等
soc:片上系统,比如 s3c2410、 s3c2440、 s5pv210 等
一般我们都会执行这样make smdk2410_config的格式,在makefile中查找,发现和之前的不一样,具体的板子配置没有了,
往下翻,在661行:找到匹配项,和之前相比这个是通用的,然后调用mkconfig,参数-A和smdk2410。
%_config:: unconfig
@$(MKCONFIG) -A $(@:_config=)
看看mkconfig脚本,
22行:
if [ ( $# -eq 2 \) -a \( "$1" = "-A" ) ] ; then
如果参数为2,并且第一个为-A,条件满足进入
这条我猜测是读取boards.cfg文件中的${2}的信息,而我们传递的第二个参数是smdk2410,
所以就是读取boards.cfg文件中的smdk2410的信息,如果不存在smdk2410的信息的话,
就打印出一条语句:make: * No rule to make target \`$2_config'. Stop." >&2并退出。
从boards.cfg读出的信息为:
smdk2410 arm arm920t - samsung s3c24x0
$1:smdk2410
$2: arm
$3: arm920t
$4: -
$5: samsung
$6: s3c24x0
所以,$# = 6,6个参数
43行:
while [ $# -gt 0 ] ; do
case "$1" in
--) shift ; break ;;
-a) shift ; APPEND=yes ;;
-n) shift ; BOARD_NAME="${1%_config}" ; shift ;;
-t) shift ; TARGETS="`echo $1 | sed 's:_: :g'` ${TARGETS}" ; shift ;;
*) break ;;
esac
done
mkconfig中没有这些参数,所以上面语句不执行
53行:
[ $# -lt 4 ] && exit 1
[ $# -gt 7 ] && exit 1
$# = 6,6个参数,不会退出
CONFIG_NAME="${1%_config}"
CONFIG_NAME设为第一个参数smdk2410
59行:
[ "${BOARD_NAME}" ] || BOARD_NAME="${1%_config}"
BOARD_NAME = smdk2410
61-86行:
arch="$2" //arch=arm
cpu="$3" //cpu=arm920t
if [ "$4" = "-" ] ; then
board=${BOARD_NAME} //board=smdk2410
else
board="$4"
fi
[ $# -gt 4 ] && [ "$5" != "-" ] && vendor="$5" //vendor=samsung
[ $# -gt 5 ] && [ "$6" != "-" ] && soc="$6" //soc=s3c24x0
102-128行:
cd ./include //进入include目录
rm -f asm //创建前确保没有这个文件
ln -s ../arch/${arch}/include/asm asm //创建指向../arch/arm/include/asm的asm目录
rm -f asm/arch //创建前确保没有这个文件
ln -s ${LNPREFIX}arch-${soc} asm/arch //创建指向../arch/arm/include/asm/arch-s3c24x0的asm/arch目录
rm -f asm/proc //创建前确保没有这个文件
ln -s ${LNPREFIX}proc-armv asm/proc //创建指向../arch/arm/include/asm/proc-armv的asm/proc目录
//${LNPREFIX} = /arch/arm/include/asm/
133行:
创建config.mk文件
ARCH = arm
CPU = arm920t
BOARD = smdk2410
VENDOR = samsung
SOC = s3c24x0
151行:
创建config.h文件,内容如下
/ Automatically generated - do not edit /
define CONFIG_BOARDDIR board/samsung/smdk2410
include <config_cmd_defaults.h>
include <config_defaults.h>
include <configs/smdk2410.h>
include <asm/config.h>
makefile和上面类似
高版本u-boot-2017移植
什么是SPL?
SPL(secondary program loader)是一个十分小的bin文件,它是用来引导主u-boot文件。对于一些SRAM很小的SOC,无法一次性加载ROM中的bootloader到SRAM中,因为一般SRAM远远小于bootloader的大小。这时候SPL应运而生了。
描述启动顺序的各个阶段表 | |||
---|---|---|---|
Boot | Terminology #1 | Terminology #2 | Actual |
stage | program | ||
number | name | ||
1 | Primary | - | ROM code |
Program | |||
Loader | |||
2 | Secondary | 1st stage | u-boot |
Program | bootloader | SPL | |
Loader (SPL) | |||
3 | - | 2nd stage | u-boot |
bootloader | |||
4 | - | - | kernel |
ENTRY宏展开
ENTRY(save_boot_params)
.globl save_boot_params
.align 4
save_boot_params:
u-boot的SPL源码流程分析:(以u-boot 2017-03为例)
SPL中,入口在u-boot-spl.lds中(u-boot-2017.03\arch\arm\cpu\armv7\sunxi)
ENTRY(_start)
SECTIONS
{
.text :
{
__start = .;
*(.vectors) //进入中断向量表,对应的跳转到U-boot/arch/arm/lib/vectors.S文件处理
arch/arm/cpu/armv7/start.o (.text*) //跳转到对应的启动加载项,后续针对这个做处理。
(.text)
}
在这里,启动加载会跳转到文件arch/arm/cpu/armv7/start.S中
文件的主要工作有下面几种:
A 重启保存启动参数:
reset:
/* Allow the board to save important registers */
b save_boot_params
save_boot_params_ret:
ifdef CONFIG_ARMV7_LPAE
/*
- check for Hypervisor support
*/
mrc p15, 0, r0, c0, c1, 1 @ read ID_PFR1
and r0, r0, #CPUID_ARM_VIRT_MASK @ mask virtualization bits
cmp r0, #(1 << CPUID_ARM_VIRT_SHIFT)
beq switch_to_hypervisor
switch_to_hypervisor_ret:
endif
/*
* disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode,
* except if in HYP mode already
*/
mrs r0, cpsr
and r1, r0, #0x1f @ mask mode bits
teq r1, #0x1a @ test for HYP mode
bicne r0, r0, #0x1f @ clear all mode bits
orrne r0, r0, #0x13 @ set SVC mode
orr r0, r0, #0xc0 @ disable FIQ and IRQ
msr cpsr,r0
B 设置向量表并跳转:
/*
- Setup vector:
- (OMAP4 spl TEXT_BASE is not 32 byte aligned.
- Continue to use ROM code vector only in OMAP4 spl)
*/
if !(defined(CONFIG_OMAP44XX) && defined(CONFIG_SPL_BUILD))
/* Set V=0 in CP15 SCTLR register - for VBAR to point to vector */
mrc p15, 0, r0, c1, c0, 0 @ Read CP15 SCTLR Register
bic r0, #CR_V @ V = 0
mcr p15, 0, r0, c1, c0, 0 @ Write CP15 SCTLR Register
/* Set vector address in CP15 VBAR register */
ldr r0, =_start
mcr p15, 0, r0, c12, c0, 0 @Set VBAR
endif
/* the mask ROM code should have PLL and others stable */
ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_cp15
ifndef CONFIG_SKIP_LOWLEVEL_INIT_ONLY
bl cpu_init_crit
endif
endif
bl _main
C 针对CP15协处理器做优化,并关闭Icache MMU和TLBS,具体代码如下:
ENTRY(cpu_init_cp15)
/*
* Invalidate L1 I/D
*/
mov r0, #0 @ set up for MCR
mcr p15, 0, r0, c8, c7, 0 @ invalidate TLBs
mcr p15, 0, r0, c7, c5, 0 @ invalidate icache
mcr p15, 0, r0, c7, c5, 6 @ invalidate BP array
mcr p15, 0, r0, c7, c10, 4 @ DSB
mcr p15, 0, r0, c7, c5, 4 @ ISB
/*
* disable MMU stuff and caches
*/
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00002000 @ clear bits 13 (--V-)
bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM)
orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align
orr r0, r0, #0x00000800 @ set bit 11 (Z---) BTB
为什么要关闭这些特性呢?
/*
*catch和MMU是通过CP15管理的,刚上电的时候,CPU还不能管理他们。
*所以上电的时候MMU必须关闭,指令cache可关闭,可不关闭,但数据cache一定要关闭
*否则可能导致刚开始的代码里面,去取数据的时候,从catch里面取,
*而这时候RAM中数据还没有cache过来,导致数据预取异常
*/
D 系统的重要寄存器和内存时钟初始化。
/*
*
- CPU_init_critical registers
*
- setup important registers
- setup memory timing
*
*/
ENTRY(cpu_init_crit)
/*
* Jump to board specific initialization...
* The Mask ROM will have already initialized
* basic memory. Go here to bump up clock rate and handle
* wake up conditions.
*/
b lowlevel_init @ go setup pll,mux,memory
ENDPROC(cpu_init_crit)
下面系统就跳转到了函数lowlevel_init去执行了,接下来要进行追踪arch/arm/cpu/armv7/lowlevel_init.S
进去看看
ENTRY(lowlevel_init)
/*
* Setup a temporary stack. Global data is not available yet.
*/
if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
ldr sp, =CONFIG_SPL_STACK
else
ldr sp, =CONFIG_SYS_INIT_SP_ADDR
endif
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
ifdef CONFIG_SPL_DM
mov r9, #0
else
/*
* Set up global data for boards that still need it. This will be
* removed soon.
*/
ifdef CONFIG_SPL_BUILD
ldr r9, =gdata
else
sub sp, sp, #GD_SIZE
bic sp, sp, #7
mov r9, sp
endif
endif
/*
* Save the old lr(passed in ip) and the current lr to stack
*/
push {ip, lr}
/*
* Call the very early init function. This should do only the
* absolute bare minimum to get started. It should not:
*
* - set up DRAM
* - use global_data
* - clear BSS
* - try to start a console
*
* For boards with SPL this should be empty since SPL can do all of
* this init in the SPL board_init_f() function which is called
* immediately after this.
*/
bl s_init
pop {ip, pc}
ENDPROC(lowlevel_init)
在最后的跳转__main()中,函数跳转到了文件arch/arm/lib/crt0.S中来
ENTRY(_main)
/*
- Set up initial C runtime environment and call board_init_f(0).
*/
if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
ldr sp, =(CONFIG_SPL_STACK)
else
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
endif
if defined(CONFIG_CPU_V7M) / v7M forbids using SP as BIC destination /
mov r3, sp
bic r3, r3, #7
mov sp, r3
else
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
endif
mov r0, sp
bl board_init_f_alloc_reserve
mov sp, r0
/* set up gd here, outside any C code */
mov r9, r0
bl board_init_f_init_reserve
mov r0, #0
bl board_init_f
if ! defined(CONFIG_SPL_BUILD)
/*
- Set up intermediate environment (new sp and gd) and call
- relocate_code(addr_moni). Trick here is that we'll return
- 'here' but relocated.
*/
ldr sp, [r9, #GD_START_ADDR_SP] /* sp = gd->start_addr_sp */
if defined(CONFIG_CPU_V7M) / v7M forbids using SP as BIC destination /
mov r3, sp
bic r3, r3, #7
mov sp, r3
else
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
endif
ldr r9, [r9, #GD_BD] /* r9 = gd->bd */
sub r9, r9, #GD_SIZE /* new GD is below bd */
adr lr, here
ldr r0, [r9, #GD_RELOC_OFF] /* r0 = gd->reloc_off */
add lr, lr, r0
if defined(CONFIG_CPU_V7M)
orr lr, #1 /* As required by Thumb-only */
endif
ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr */
b relocate_code
here:
/*
- now relocate vectors
*/
bl relocate_vectors
/ Set up final (full) environment /
bl c_runtime_cpu_setup /* we still call old routine here */
endif
if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_FRAMEWORK)
ifdef CONFIG_SPL_BUILD
/* Use a DRAM stack for the rest of SPL, if requested */
bl spl_relocate_stack_gd
cmp r0, #0
movne sp, r0
movne r9, r0
endif
ldr r0, =__bss_start /* this is auto-relocated! */
ifdef CONFIG_USE_ARCH_MEMSET
ldr r3, =__bss_end /* this is auto-relocated! */
mov r1, #0x00000000 /* prepare zero to clear BSS */
subs r2, r3, r0 /* r2 = memset len */
bl memset
else
ldr r1, =__bss_end /* this is auto-relocated! */
mov r2, #0x00000000 /* prepare zero to clear BSS */
clbss_l:cmp r0, r1 / while not at end of BSS /
if defined(CONFIG_CPU_V7M)
itt lo
endif
strlo r2, [r0] /* clear 32-bit BSS word */
addlo r0, r0, #4 /* move to next */
blo clbss_l
endif
if ! defined(CONFIG_SPL_BUILD)
bl coloured_LED_init
bl red_led_on
endif
/* call board_init_r(gd_t *id, ulong dest_addr) */
mov r0, r9 /* gd_t */
ldr r1, [r9, #GD_RELOCADDR] /* dest_addr */
/* call board_init_r */
if defined(CONFIG_SYS_THUMB_BUILD)
ldr lr, =board_init_r /* this is auto-relocated! */
bx lr
else
ldr pc, =board_init_r /* this is auto-relocated! */
endif
/* we should not return here. */
endif
ENDPROC(_main)
board_init_f在common/board_f.c中
下面就要看board_init_r的工作了。在文件common/spl.c中可以看到:
void board_init_r(gd_t *dummy1, ulong dummy2)
{
u32 spl_boot_list[] = {
BOOT_DEVICE_NONE,
BOOT_DEVICE_NONE,
BOOT_DEVICE_NONE,
BOOT_DEVICE_NONE,
BOOT_DEVICE_NONE,
};
struct spl_image_info spl_image;
debug(">>spl:board_init_r()\n");
if defined(CONFIG_SYS_SPL_MALLOC_START)
mem_malloc_init(CONFIG_SYS_SPL_MALLOC_START,
CONFIG_SYS_SPL_MALLOC_SIZE);
gd->flags |= GD_FLG_FULL_MALLOC_INIT;
endif
if (!(gd->flags & GD_FLG_SPL_INIT)) {
if (spl_init())
hang();
}
ifndef CONFIG_PPC
/*
* timer_init() does not exist on PPC systems. The timer is initialized
* and enabled (decrementer) in interrupt_init() here.
*/
timer_init();
endif
ifdef CONFIG_SPL_BOARD_INIT
spl_board_init();
endif
memset(&spl_image, '\0', sizeof(spl_image));
board_boot_order(spl_boot_list);
if (boot_from_devices(&spl_image, spl_boot_list,
ARRAY_SIZE(spl_boot_list))) {
puts("SPL: failed to boot from all boot devices\n");
hang();
}
switch (spl_image.os) {
case IH_OS_U_BOOT:
debug("Jumping to U-Boot\n");
break;
ifdef CONFIG_SPL_OS_BOOT
case IH_OS_LINUX:
debug("Jumping to Linux\n");
spl_board_prepare_for_linux();
jump_to_image_linux(&spl_image,
(void *)CONFIG_SYS_SPL_ARGS_ADDR);
endif
default:
debug("Unsupported OS image.. Jumping nevertheless..\n");
}
if defined(CONFIG_SYS_MALLOC_F_LEN) && !defined(CONFIG_SYS_SPL_MALLOC_SIZE)
debug("SPL malloc() used %#lx bytes (%ld KB)\n", gd->malloc_ptr,
gd->malloc_ptr / 1024);
endif
debug("loaded - jumping to U-Boot...\n");
spl_board_prepare_for_boot();
jump_to_image_no_args(&spl_image);
}