uboot从1.1.6到2012,2017版本的编译过程

简介: uboot

用这个文件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);

}

相关文章
|
Ubuntu Linux 开发工具
嵌入式Linux系列第4篇:Kernel编译下载
嵌入式Linux系列第4篇:Kernel编译下载
|
2月前
编译cuttlefish内核遇到的问题
编译cuttlefish内核遇到的问题
|
Linux 芯片 Windows
嵌入式Linux系列第3篇:uboot编译下载
嵌入式Linux系列第3篇:uboot编译下载
|
存储 Ubuntu Unix
【三、深入浅出GCC编译器】一个源文件到可执行文件是如何生成的:GCC编译工具链及编译参数详解(一)
【三、深入浅出GCC编译器】一个源文件到可执行文件是如何生成的:GCC编译工具链及编译参数详解
350 0
【三、深入浅出GCC编译器】一个源文件到可执行文件是如何生成的:GCC编译工具链及编译参数详解(一)
|
NoSQL 编译器 Linux
【三、深入浅出GCC编译器】一个源文件到可执行文件是如何生成的:GCC编译工具链及编译参数详解(三)
【三、深入浅出GCC编译器】一个源文件到可执行文件是如何生成的:GCC编译工具链及编译参数详解
303 0
【三、深入浅出GCC编译器】一个源文件到可执行文件是如何生成的:GCC编译工具链及编译参数详解(三)
|
自然语言处理 编译器 Linux
【三、深入浅出GCC编译器】一个源文件到可执行文件是如何生成的:GCC编译工具链及编译参数详解(二)
【三、深入浅出GCC编译器】一个源文件到可执行文件是如何生成的:GCC编译工具链及编译参数详解
563 0
【三、深入浅出GCC编译器】一个源文件到可执行文件是如何生成的:GCC编译工具链及编译参数详解(二)
|
Linux 编译器 C语言
『Linux从入门到精通』第 ⑦ 期 - Linux编译器——gcc/g++(预处理、编译、汇编、链接)
『Linux从入门到精通』第 ⑦ 期 - Linux编译器——gcc/g++(预处理、编译、汇编、链接)
139 0
|
存储 编译器 Linux
MDK编译过程及ARM编译工具链
MDK编译过程及ARM编译工具链
451 0
MDK编译过程及ARM编译工具链
|
Linux Windows
WINDOWS使用msys2编译ffmpeg(编译成功,无法使用)
WINDOWS使用msys2编译ffmpeg(编译成功,无法使用)
366 0
|
Linux 编译器 Shell
【Linux】【编译】编译及Makefile的调试手段和技巧
【Linux】【编译】编译及Makefile的调试手段和技巧
636 0