一、s3c6410启动流程
要移植uboot到tiny6410,首先需要弄清楚tiny6410的启动流程,下面是三星官方文档给出的启动流程图
从流程图中可以看到需要4步:
1、上电后先运行IROM里面的代码,芯片厂商固定好,进行硬件初始化,包括系统时钟初始化,D-TCM初始化等,这部分叫BL0。
2、iRom在初始化完后会把外部启动设备(nand flash、sd卡等)中的bootloader的前4K拷贝到stepping stone中,然后调到stepping stone中运行,这部分叫BL1。
3、BL1会初始化系统时钟,串口和内存,初始化完后,会把剩余的bootloader从启动设备拷贝到内存,这部分叫BL2。
4、拷贝完后跳到内存运行,之后就是加载内核、文件系统等。
大致的步骤就是这样,步骤1已经是固定好的,我们需要移植的是步骤2、3、4。
先下载好uboot-2010-03版本的uboot源码,在官方上好像下载不了,可以在这里下载:
http://download.csdn.net/detail/atmega_chen/9795885
二、uboot-2010-03 移植前分析
1、什么是nand spl
在下载好源码,解压后,移植前先分析uboot的编译流程和移植方向。因为2010-03版本的uboot加了nand spl,之前使用的版本并未使用到nand spl,所以会分析有nand spl和无nand spl的区别已经移植的。
nand spl也就是一个包含uboot前面4k大小的bin文件,在生成的时候uboot的总文件的时候会将4k的bin文件和u-boot.bin合并成一个大小为256k的u-boot-nand.bin。下面根据源码具体分析有nand spl和无nand spl的区别。
2、nand spl生成分析
由于我们要移植的是tiny6410,uboot2010-03中并没有支持tiny6410,但是有支持smdk6400,所以我们先用smdk6400的代码分析。
先看到根目录下面的Makefile,在6400配置规则里面当执行make smdk6400的时候会把CONFIG_NAND_U_BOOT宏定义写入到include/config.mk里面去,编译的时候会调用。
smdk6400_config : unconfig
@mkdir -p $(obj)include $(obj)board/samsung/smdk6400
@mkdir -p $(obj)nand_spl/board/samsung/smdk6400
@echo "#define CONFIG_NAND_U_BOOT" > $(obj)include/config.h
@if [ -z "$(findstring smdk6400_noUSB_config,$@)" ]; then \
echo "RAM_TEXT = 0x57e00000" >> $(obj)board/samsung/smdk6400/config.tmp;\
$(MKCONFIG) $(@:_config=) arm arm1176 smdk6400 samsung s3c64xx; \
else \
echo "RAM_TEXT = 0xc7e00000" >> $(obj)board/samsung/smdk6400/config.tmp;\
$(MKCONFIG) $(@:_noUSB_config=) arm arm1176 smdk6400 samsung s3c64xx; \
fi
@echo "CONFIG_NAND_U_BOOT = y" >> $(obj)include/config.mk
然后找到这个宏使用的地方,这里就是说如果有定义CONFIG_NAND_U_BOOT,就定义NAND_SPL和U_BOOT_NAND这两个变量,这两个变量有什么用呢。
ifeq ($(CONFIG_NAND_U_BOOT),y)
NAND_SPL = nand_spl
U_BOOT_NAND = $(obj)u-boot-nand.bin
endif
我们先看到Makefile的总生成目标,可以看到总的生成目标里面有u-boot.srec,u-boot.bin和U_BOOT_NAND,也就是u-boot-nand.bin
# Always append ALL so that arch config.mk's can add custom ones
ALL += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND) $(U_BOOT_ONENAND)
all: $(ALL)
在往下找U_BOOT_NAND的生产规则,u-boot-nand.bin依赖NAND_SPL和u-boot.bin,其中u-boot.bin的生成不分析就是正常的uboot生成u-boot.bin的流程,主要分析NAND_SPL的生成。如果依赖关系满足,那么就将u-boot-spl-16k.bin和u-boot.bin这个两个文件合并成u-boot-nand.bin。其中u-boot-spl-16k.bin这个文件的生成,就是根据依赖NAND_SPL来生成,具体怎么生成往下分析。
$(U_BOOT_NAND): $(NAND_SPL) $(obj)u-boot.bin
cat $(obj)nand_spl/u-boot-spl-16k.bin $(obj)u-boot.bin > $(obj)u-boot-nand.bin
搜索NAND_SPL的生成规则,这条规则会去编译nand_spl/board/ (BOARDDIR)下面的文件,其中 (BOARDDIR)就是samsung目录。
$(NAND_SPL): $(TIMESTAMP_FILE) $(VERSION_FILE) $(obj)include/autoconf.mk
$(MAKE) -C nand_spl/board/$(BOARDDIR) all
进入到nand_spl/board/samsung/smdk6400目录,看到一开始只有三个文件。
这里就是nand spl的关键所在,也就说前面只要定义了CONFIG_NAND_U_BOOT就会编译nand spl这个目录,那么编译出来的是什么东西呢?打开Makefile看看。
首先定义了CONFIG_NAND_SPL = y,这个宏比较重要,后面会介绍用处。
CONFIG_NAND_SPL = y
include $(TOPDIR)/config.mk
include $(TOPDIR)/nand_spl/board/$(BOARDDIR)/config.mk
LDSCRIPT= $(TOPDIR)/nand_spl/board/$(BOARDDIR)/u-boot.lds
LDFLAGS = -Bstatic -T $(nandobj)u-boot.lds -Ttext $(TEXT_BASE) $(PLATFORM_LDFLAGS)
AFLAGS += -DCONFIG_NAND_SPL
CFLAGS += -DCONFIG_NAND_SPL
SOBJS = start.o cpu_init.o lowlevel_init.o
COBJS = nand_boot.o nand_ecc.o s3c64xx.o
SRCS := $(addprefix $(obj),$(SOBJS:.o=.S) $(COBJS:.o=.c))
OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS))
__OBJS := $(SOBJS) $(COBJS)
LNDIR := $(OBJTREE)/nand_spl/board/$(BOARDDIR)
nandobj := $(OBJTREE)/nand_spl/
ALL = $(nandobj)u-boot-spl $(nandobj)u-boot-spl.bin $(nandobj)u-boot-spl-16k.bin
all: $(obj).depend $(ALL)
$(nandobj)u-boot-spl-16k.bin: $(nandobj)u-boot-spl
$(OBJCOPY) ${OBJCFLAGS} --pad-to=$(PAD_TO) -O binary $< $@
$(nandobj)u-boot-spl.bin: $(nandobj)u-boot-spl
$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
$(nandobj)u-boot-spl: $(OBJS) $(nandobj)u-boot.lds
cd $(LNDIR) && $(LD) $(LDFLAGS) $(__OBJS) \
-Map $(nandobj)u-boot-spl.map \
-o $(nandobj)u-boot-spl
$(nandobj)u-boot.lds: $(LDSCRIPT)
$(CPP) $(CPPFLAGS) $(LDPPFLAGS) -ansi -D__ASSEMBLY__ -P - <$^ >$@
# create symbolic links for common files
# from cpu directory
$(obj)start.S:
@rm -f $@
@ln -s $(TOPDIR)/cpu/arm1176/start.S $@
# from SoC directory
$(obj)cpu_init.S:
@rm -f $@
@ln -s $(TOPDIR)/cpu/arm1176/s3c64xx/cpu_init.S $@
# from board directory
$(obj)lowlevel_init.S:
@rm -f $@
@ln -s $(TOPDIR)/board/samsung/smdk6400/lowlevel_init.S $@
# from nand_spl directory
$(obj)nand_boot.c:
@rm -f $@
@ln -s $(TOPDIR)/nand_spl/nand_boot.c $@
# from drivers/mtd/nand directory
$(obj)nand_ecc.c:
@rm -f $@
@ln -s $(TOPDIR)/drivers/mtd/nand/nand_ecc.c $@
$(obj)s3c64xx.c:
@rm -f $@
@ln -s $(TOPDIR)/drivers/mtd/nand/s3c64xx.c $@
#########################################################################
$(obj)%.o: $(obj)%.S
$(CC) $(AFLAGS) -c -o $@ $<
$(obj)%.o: $(obj)%.c
$(CC) $(CFLAGS) -c -o $@ $<
# defines $(obj).depend target
include $(SRCTREE)/rules.mk
sinclude $(obj).depend
###################
通过ALL总目标可以知道这个Makefile编译生成的文件u-boot-spl,u-boot-spl.bin和u-boot-spl-16k.bin。其中u-boot-spl-16k.bin就是前面提到的合成u-boot-nand.bin需要的文件,这个文件具体有什么用呢。
ALL = $(nandobj)u-boot-spl $(nandobj)u-boot-spl.bin $(nandobj)u-boot-spl-16k.bin
可以看到u-boot-spl-16k.bin依赖u-boot-spl
$(nandobj)u-boot-spl-16k.bin: $(nandobj)u-boot-spl
$(OBJCOPY) ${OBJCFLAGS} --pad-to=$(PAD_TO) -O binary $< $@
u-boot-spl依赖$(OBJS)和u-boot.lds
$(nandobj)u-boot-spl: $(OBJS) $(nandobj)u-boot.lds
cd $(LNDIR) && $(LD) $(LDFLAGS) $(__OBJS) \
-Map $(nandobj)u-boot-spl.map \
-o $(nandobj)u-boot-spl
$(OBJS)又依赖start.s,cpu_init.s等等,但是这个目录下面并没有这些源文件,那是如何编译出.o文件的呢,往下看。
SOBJS = start.o cpu_init.o lowlevel_init.o
COBJS = nand_boot.o nand_ecc.o s3c64xx.o
SRCS := $(addprefix $(obj),$(SOBJS:.o=.S) $(COBJS:.o=.c))
OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS))
__OBJS := $(SOBJS) $(COBJS)
LNDIR := $(OBJTREE)/nand_spl/board/$(BOARDDIR)
这些源文件其实都是软连接,连接到不同的目录下面去,所以这个nand spl编译出来的u-boot-spl-16k.bin其实就是包含start.S的uboot的前4K的头部,具体这个头部和以前是有的u-boot.bin有什么不同呢,分析一下start.S就知道了。
# from cpu directory
$(obj)start.S:
@rm -f $@
@ln -s $(TOPDIR)/cpu/arm1176/start.S $@
# from SoC directory
$(obj)cpu_init.S:
@rm -f $@
@ln -s $(TOPDIR)/cpu/arm1176/s3c64xx/cpu_init.S $@
# from board directory
$(obj)lowlevel_init.S:
@rm -f $@
@ln -s $(TOPDIR)/board/samsung/smdk6400/lowlevel_init.S $@
# from nand_spl directory
$(obj)nand_boot.c:
@rm -f $@
@ln -s $(TOPDIR)/nand_spl/nand_boot.c $@
# from drivers/mtd/nand directory
$(obj)nand_ecc.c:
@rm -f $@
@ln -s $(TOPDIR)/drivers/mtd/nand/nand_ecc.c $@
$(obj)s3c64xx.c:
@rm -f $@
@ln -s $(TOPDIR)/drivers/mtd/nand/s3c64xx.c $@
3、nand spl作用
打开u-boot-2010.03/cpu/arm1176/start.S,搜索CONFIG_NAND_SPL
可以看到有三个地方用到了#ifndef CONFIG_NAND_SPL,而这个宏在哪里定义呢,就是我们前面分析的nand spl的Makefile,一开始就定义了这个宏,所以可以知道在u-boot-spl-16k.bin这个文件中,这个宏是被定义的,但是在u-boot.bin这个文件中这个宏是没有被定义的,这样做有什么用呢。
#include <config.h>
#include <version.h>
#ifdef CONFIG_ENABLE_MMU
#include <asm/proc/domain.h>
#endif
#include <asm/arch/s3c6400.h>
#if !defined(CONFIG_ENABLE_MMU) && !defined(CONFIG_SYS_PHY_UBOOT_BASE)
#define CONFIG_SYS_PHY_UBOOT_BASE CONFIG_SYS_UBOOT_BASE
#endif
/*
*************************************************************************
*
* Jump vector table as in table 3.1 in [1]
*
*************************************************************************
*/
.globl _start
_start: b reset
#ifndef CONFIG_NAND_SPL
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
_undefined_instruction:
.word undefined_instruction
_software_interrupt:
.word software_interrupt
_prefetch_abort:
.word prefetch_abort
_data_abort:
.word data_abort
_not_used:
.word not_used
_irq:
.word irq
_fiq:
.word fiq
_pad:
.word 0x12345678 /* now 16*4=64 */
#else
. = _start + 64
#endif
.global _end_vect
_end_vect:
.balignl 16,0xdeadbeef
/*
*************************************************************************
*
* Startup Code (reset vector)
*
* do important init only if we don't start from memory!
* setup Memory and board specific bits prior to relocation.
* relocate armboot to ram
* setup stack
*
*************************************************************************
*/
_TEXT_BASE:
.word TEXT_BASE
/*
* Below variable is very important because we use MMU in U-Boot.
* Without it, we cannot run code correctly before MMU is ON.
* by scsuh.
*/
_TEXT_PHY_BASE:
.word CONFIG_SYS_PHY_UBOOT_BASE
.globl _armboot_start
_armboot_start:
.word _start
/*
* These are defined in the board-specific linker script.
*/
.globl _bss_start
_bss_start:
.word __bss_start
.globl _bss_end
_bss_end:
.word _end
/*
* the actual reset code
*/
reset:
/*
* set the cpu to SVC32 mode
*/
mrs r0, cpsr
bic r0, r0, #0x3f
orr r0, r0, #0xd3
msr cpsr, r0
/*
*************************************************************************
*
* CPU_init_critical registers
*
* setup important registers
* setup memory timing
*
*************************************************************************
*/
/*
* we do sys-critical inits only at reboot,
* not when booting from ram!
*/
cpu_init_crit:
/*
* When booting from NAND - it has definitely been a reset, so, no need
* to flush caches and disable the MMU
*/
#ifndef CONFIG_NAND_SPL
/*
* flush v4 I/D caches
*/
mov r0, #0
mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */
mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */
/*
* disable MMU stuff and caches
*/
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)
bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)
orr r0, r0, #0x00000002 @ set bit 2 (A) Align
orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache
/* Prepare to disable the MMU */
adr r1, mmu_disable_phys
/* We presume we're within the first 1024 bytes */
and r1, r1, #0x3fc
ldr r2, _TEXT_PHY_BASE
ldr r3, =0xfff00000
and r2, r2, r3
orr r2, r2, r1
b mmu_disable
.align 5
/* Run in a single cache-line */
mmu_disable:
mcr p15, 0, r0, c1, c0, 0
nop
nop
mov pc, r2
#endif
mmu_disable_phys:
/* Peri port setup */
ldr r0, =0x70000000
orr r0, r0, #0x13
mcr p15,0,r0,c15,c2,4 @ 256M (0x70000000 - 0x7fffffff)
/*
* Go setup Memory and board specific bits prior to relocation.
*/
bl lowlevel_init /* go setup pll,mux,memory */
after_copy:
#ifdef CONFIG_ENABLE_MMU
enable_mmu:
/* enable domain access */
ldr r5, =0x0000ffff
mcr p15, 0, r5, c3, c0, 0 /* load domain access register */
/* Set the TTB register */
ldr r0, _mmu_table_base
ldr r1, =CONFIG_SYS_PHY_UBOOT_BASE
ldr r2, =0xfff00000
bic r0, r0, r2
orr r1, r0, r1
mcr p15, 0, r1, c2, c0, 0
/* Enable the MMU */
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #1 /* Set CR_M to enable MMU */
/* Prepare to enable the MMU */
adr r1, skip_hw_init
and r1, r1, #0x3fc
ldr r2, _TEXT_BASE
ldr r3, =0xfff00000
and r2, r2, r3
orr r2, r2, r1
b mmu_enable
.align 5
/* Run in a single cache-line */
mmu_enable:
mcr p15, 0, r0, c1, c0, 0
nop
nop
mov pc, r2
#endif
skip_hw_init:
/* Set up the stack */
stack_setup:
ldr r0, =CONFIG_SYS_UBOOT_BASE /* base of copy in DRAM */
sub r0, r0, #CONFIG_SYS_MALLOC_LEN /* malloc area */
sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE /* bdinfo */
sub sp, r0, #12 /* leave 3 words for abort-stack */
clear_bss:
ldr r0, _bss_start /* find start of bss segment */
ldr r1, _bss_end /* stop here */
mov r2, #0 /* clear */
clbss_l:
str r2, [r0] /* clear loop... */
add r0, r0, #4
cmp r0, r1
ble clbss_l
#ifndef CONFIG_NAND_SPL
ldr pc, _start_armboot
_start_armboot:
.word start_armboot
#else
b nand_boot
/* .word nand_boot*/
#endif
#ifdef CONFIG_ENABLE_MMU
_mmu_table_base:
.word mmu_table
#endif
#ifndef CONFIG_NAND_SPL
/*
* we assume that cache operation is done before. (eg. cleanup_before_linux())
* actually, we don't need to do anything about cache if not use d-cache in
* U-Boot. So, in this function we clean only MMU. by scsuh
*
* void theLastJump(void *kernel, int arch_num, uint boot_params);
*/
#ifdef CONFIG_ENABLE_MMU
.globl theLastJump
theLastJump:
mov r9, r0
ldr r3, =0xfff00000
ldr r4, _TEXT_PHY_BASE
adr r5, phy_last_jump
bic r5, r5, r3
orr r5, r5, r4
mov pc, r5
phy_last_jump:
/*
* disable MMU stuff
*/
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00002300 /* clear bits 13, 9:8 (--V- --RS) */
bic r0, r0, #0x00000087 /* clear bits 7, 2:0 (B--- -CAM) */
orr r0, r0, #0x00000002 /* set bit 2 (A) Align */
orr r0, r0, #0x00001000 /* set bit 12 (I) I-Cache */
mcr p15, 0, r0, c1, c0, 0
mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */
mov r0, #0
mov pc, r9
#endif
/*
*************************************************************************
*
* Interrupt handling
*
*************************************************************************
*/
@
@ IRQ stack frame.
@
#define S_FRAME_SIZE 72
#define S_OLD_R0 68
#define S_PSR 64
#define S_PC 60
#define S_LR 56
#define S_SP 52
#define S_IP 48
#define S_FP 44
#define S_R10 40
#define S_R9 36
#define S_R8 32
#define S_R7 28
#define S_R6 24
#define S_R5 20
#define S_R4 16
#define S_R3 12
#define S_R2 8
#define S_R1 4
#define S_R0 0
#define MODE_SVC 0x13
#define I_BIT 0x80
/*
* use bad_save_user_regs for abort/prefetch/undef/swi ...
*/
.macro bad_save_user_regs
/* carve out a frame on current user stack */
sub sp, sp, #S_FRAME_SIZE
/* Save user registers (now in svc mode) r0-r12 */
stmia sp, {r0 - r12}
ldr r2, _armboot_start
sub r2, r2, #(CONFIG_SYS_MALLOC_LEN)
/* set base 2 words into abort stack */
sub r2, r2, #(CONFIG_SYS_GBL_DATA_SIZE+8)
/* get values for "aborted" pc and cpsr (into parm regs) */
ldmia r2, {r2 - r3}
/* grab pointer to old stack */
add r0, sp, #S_FRAME_SIZE
add r5, sp, #S_SP
mov r1, lr
/* save sp_SVC, lr_SVC, pc, cpsr */
stmia r5, {r0 - r3}
/* save current stack into r0 (param register) */
mov r0, sp
.endm
.macro get_bad_stack
/* setup our mode stack (enter in banked mode) */
ldr r13, _armboot_start
/* move past malloc pool */
sub r13, r13, #(CONFIG_SYS_MALLOC_LEN)
/* move to reserved a couple spots for abort stack */
sub r13, r13, #(CONFIG_SYS_GBL_DATA_SIZE + 8)
/* save caller lr in position 0 of saved stack */
str lr, [r13]
/* get the spsr */
mrs lr, spsr
/* save spsr in position 1 of saved stack */
str lr, [r13, #4]
/* prepare SVC-Mode */
mov r13, #MODE_SVC
@ msr spsr_c, r13
/* switch modes, make sure moves will execute */
msr spsr, r13
/* capture return pc */
mov lr, pc
/* jump to next instruction & switch modes. */
movs pc, lr
.endm
.macro get_bad_stack_swi
/* space on current stack for scratch reg. */
sub r13, r13, #4
/* save R0's value. */
str r0, [r13]
/* get data regions start */
ldr r0, _armboot_start
/* move past malloc pool */
sub r0, r0, #(CONFIG_SYS_MALLOC_LEN)
/* move past gbl and a couple spots for abort stack */
sub r0, r0, #(CONFIG_SYS_GBL_DATA_SIZE + 8)
/* save caller lr in position 0 of saved stack */
str lr, [r0]
/* get the spsr */
mrs r0, spsr
/* save spsr in position 1 of saved stack */
str lr, [r0, #4]
/* restore r0 */
ldr r0, [r13]
/* pop stack entry */
add r13, r13, #4
.endm
/*
* exception handlers
*/
.align 5
undefined_instruction:
get_bad_stack
bad_save_user_regs
bl do_undefined_instruction
.align 5
software_interrupt:
get_bad_stack_swi
bad_save_user_regs
bl do_software_interrupt
.align 5
prefetch_abort:
get_bad_stack
bad_save_user_regs
bl do_prefetch_abort
.align 5
data_abort:
get_bad_stack
bad_save_user_regs
bl do_data_abort
.align 5
not_used:
get_bad_stack
bad_save_user_regs
bl do_not_used
.align 5
irq:
get_bad_stack
bad_save_user_regs
bl do_irq
.align 5
fiq:
get_bad_stack
bad_save_user_regs
bl do_fiq
#endif /* CONFIG_NAND_SPL */
因为我们前面分析了uboot的启动流程知道,首先启动设备的前4K代码会被拷贝到steeping stone中去,这里通过前面分析知道
u-boot-nand.bin的前4k代码就是u-boot-spl-16k.bin这个文件,所以一开始这个u-boot-spl-16k.bin会被执行,然后会执行start.S,由于u-boot-spl-16k.bin中定义了CONFIG_NAND_SPL所以三个地方的#ifndef CONFIG_NAND_SPL的代码都会被跳过,这些代码主要是做一些硬件的初始化,堆栈的设置等,并且最后会执行b nand_boot。
和以前分析的uboot不一样,以前uboot在start.S中执行到最后都会把剩余的uboot拷贝到内存里面去了,然后执行start_armboot进入内存运行。但加了nand spl后,前面跳过了很多代码,并没有执行拷贝uboot到内存的操作,是在b nand_boot里面执行的。
#ifndef CONFIG_NAND_SPL
ldr pc, _start_armboot
_start_armboot:
.word start_armboot
#else
b nand_boot
/* .word nand_boot*/
#endif
打开nand_spl/nand_boot.c找到nand_boot函数,这个函数先调用nand_load函数拷贝uboot到内存,具体拷贝的是什么样的uboot呢,找到这个几个宏定义
void nand_boot(void)
{
struct nand_chip nand_chip;
nand_info_t nand_info;
int ret;
__attribute__((noreturn)) void (*uboot)(void);
/*
* Init board specific nand support
*/
nand_info.priv = &nand_chip;
nand_chip.IO_ADDR_R = nand_chip.IO_ADDR_W = (void __iomem *)CONFIG_SYS_NAND_BASE;
nand_chip.dev_ready = NULL; /* preset to NULL */
board_nand_init(&nand_chip);
if (nand_chip.select_chip)
nand_chip.select_chip(&nand_info, 0);
/*
* Load U-Boot image from NAND into RAM
*/
ret = nand_load(&nand_info, CONFIG_SYS_NAND_U_BOOT_OFFS, CONFIG_SYS_NAND_U_BOOT_SIZE,
(uchar *)CONFIG_SYS_NAND_U_BOOT_DST);
#ifdef CONFIG_NAND_ENV_DST
nand_load(&nand_info, CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE,
(uchar *)CONFIG_NAND_ENV_DST);
#ifdef CONFIG_ENV_OFFSET_REDUND
nand_load(&nand_info, CONFIG_ENV_OFFSET_REDUND, CONFIG_ENV_SIZE,
(uchar *)CONFIG_NAND_ENV_DST + CONFIG_ENV_SIZE);
#endif
#endif
if (nand_chip.select_chip)
nand_chip.select_chip(&nand_info, -1);
/*
* Jump to U-Boot image
*/
uboot = (void *)CONFIG_SYS_NAND_U_BOOT_START;
(*uboot)();
}
通过宏定义可以知道,从nand flash的第4K位置开始拷贝,拷贝的大小为252K,也就是说跳过u-boot-spl-16k.bin,将u-boot.bin整个拷贝到内存
#define CONFIG_SYS_NAND_U_BOOT_OFFS (4 * 1024) /* Offset to RAM U-Boot image */
#define CONFIG_SYS_NAND_U_BOOT_SIZE (252 * 1024) /* Size of RAM U-Boot image */
#define CONFIG_SYS_NAND_U_BOOT_DST CONFIG_SYS_PHY_UBOOT_BASE /* NUB load-addr */
然后将指针指到内存的起始地址处,开始执行u-boot.bin。u-boot.bin又重新开始从start.S开始执行,因为u-boot.bin中没有定义CONFIG_NAND_SPL,所以三个#ifndef CONFIG_NAND_SPL的代码都会被执行到,之前是没有执行到的,然后做一些硬件的初始化,堆栈设置等,最后跳到start_armboot。
4、nand spl比较分析
使用nand spl启动的话,一开始的start.S会跳过很多初始化的代码,直接到最后调用nand_boot函数加载完整的u-boot.bin到内存,然后重新运行uboot并进行初始化,这也就是为什么在start.S中看不到类似copy_uboot_to_ram这样的操作。如果不使用nand spl的话,在执行到start.S的时候,会执行一些初始化工作,并且最重要的一点是会在跳到start_armboot之前先把代码拷贝到内存,会有类似copy_uboot_to_ram这样的操作。并且不使用nand spl的话只需要生成u-boot.bin即可,不用生成两部分。
5、具体移植做法
通过前面分析可以知道,启动可以分使用nand spl和不使用nand spl启动,我会把两种启动方式都移植到tiny6410上,因为uboot-2010-03默认使用的就是使用nand spl的方式启动,所以先移植使用nand spl启动的方式,之后会移植不使用nand spl要如何修改。