nuvoton uboo2013引导流程 2 - spl

基于nuvoton970学习 uboo2013 之 u-boot-spl

1、先来看看源码根目录下Makefile

​ 打开Makefile 搜索 all: (默认的编译目标)

all:		$(ALL-y) $(SUBDIR_EXAMPLES)
#
#	所以 默认目标是依赖 $(ALL-y) 和 $(SUBDIR_EXAMPLES)

​ 在来看看 $(ALL-y), 在Makefile中搜索 ALL- :

# Always append ALL so that arch config.mk's can add custom ones
ALL-y	+= $(obj)u-boot.srec $(obj)u-boot.bin	$(obj)System.map
ALL-$(CONFIG_NAND_U_BOOT)	 += $(obj)u-boot-nand.bin
ALL-$(CONFIG_ONENAND_U_BOOT) += $(obj)u-boot-onenand.bin
ALL-$(CONFIG_SPL)			 += $(obj)spl/u-boot-spl.bin
ALL-$(CONFIG_SPL) += $(obj)$(subst ",,$(CONFIG_SPL_TARGET))
ALL-$(CONFIG_OF_SEPARATE) += $(obj)u-boot.dtb $(obj)u-boot-dtb.bin

首先这里 我使用的源码路径和编译路径一样,所以 $(obj) 的值为空,在Makefile中有如下定义:

# 如果 目标路径和源码路径不一样,obj 就等于目标路径,否则为空
ifneq ($(OBJTREE), $(SRCTREE))
obj	:=	$(OBJTREE)/
src	:=	$(OBJTREE)/
else
obj	:=
src	:=
endif

接着分析上面的ALL,从上面的定义可以看出, ALL-y 中一定要包含的有 u-boot.srec 、u-boot.bin和System.map。而u-boot-spl.bin是可选的。而我现在用的工程中配置过程中定义了CONFIG_NAND_U_BOOT,所以ALL-y中也包含了$(obj)u-boot-nand.bin。 在主目录下Makefile中搜索 $(obj)u-boot-nand.bin的定义:

$(obj)u-boot-nand.bin:  nand_spl $(obj)u-boot.bin                                 
         cat $(obj)nand_spl/u-boot-spl-16k.bin $(obj)u-boot.bin > $(obj)u-boot-nand.bin

从上面可以看出,u-boot-nand.bin 依赖 nand_spl 和 $(obj)u-boot.bin。

然后执行 cat 命令相对于把前两个文件合并成 u-boot-nand.bin 。而$(obj)u-boot.bin就是我们的主体u-boot.bin。此处暂不讨论,先分析nand_spl 。

nand_spl的定义如下:

nand_spl: $(TIMESTAMP_FILE) $(VERSION_FILE) depend
         $(MAKE) -C nand_spl/board/$(BOARDDIR) all

nand_spl 依赖 $(TIMESTAMP_FILE) 时间戳文件和$(VERSION_FILE)版本文件。

TIMESTAP_FILE	= $(obj)include/generated/timestamp_autogenerated.h
VERSION_FILE	= $(obj)include/generated/version_autogenerated.h

$(VERSION_FILE):
                @mkdir -p $(dir $(VERSION_FILE))
                @( localvers='$(shell $(TOPDIR)/tools/setlocalversion $(TOPDIR))' ; \
                   printf '#define PLAIN_VERSION "%s%s"\n' \
                        "$(U_BOOT_VERSION)" "$${localvers}" ; \
                   printf '#define U_BOOT_VERSION "U-Boot %s%s"\n' \
                        "$(U_BOOT_VERSION)" "$${localvers}" ; \
                ) > $@.tmp
                @( printf '#define CC_VERSION_STRING "%s"\n' \
                 '$(shell $(CC) --version | head -n 1)' )>>  $@.tmp
                @( printf '#define LD_VERSION_STRING "%s"\n' \
                 '$(shell $(LD) -v | head -n 1)' )>>  $@.tmp
                @cmp -s $@ $@.tmp && rm -f $@.tmp || mv -f $@.tmp $@
                
$(TIMESTAMP_FILE):
                @mkdir -p $(dir $(TIMESTAMP_FILE))
                @LC_ALL=C date +'#define U_BOOT_DATE "%b %d %C%y"' > $@.tmp                                                        
                @LC_ALL=C date +'#define U_BOOT_TIME "%T"' >> $@.tmp
                @cmp -s $@ $@.tmp && rm -f $@.tmp || mv -f $@.tmp $@
#
# 根据编译时间动态的创建时间戳文件和版本文件,不做过多分析。
#

重点是:$(MAKE) -C nand_spl/board/$(BOARDDIR) all

源码路径下 config.mk 有:

ifdef VENDOR
BOARDDIR = $(VENDOR)/$(BOARD)
else
BOARDDIR = $(BOARD)
endif

include/config.mk 中有:

BOARD 	=	nuc970evb
VENDOR	=	nuvoton

所以 BOARDDIR = nuvoton/nuc970evb。因此上面的命令是:

​ make -C nand_spl/boatd/nuvoton/nuc970evb all

make -C 命令是执行指定路径下的Makefile,所以就继续分析nand_spl/boatd/nuvoton/nuc970evb/Makefile。打开Makefile,搜索 all 的定义:

all:	$(obj).depend	$(ALL)

同上,在 nand_spl/boatd/nuvoton/nuc970evb/Makefile 中查找 ALL 的定义:

nandobj := $(OBJTREE)nand_spl/

ALL	=	$(nandobj)u-boot-spl  $(nandobj)u-boot-spl.bin  $(nandobj)u-boot-spl-16k.bin

可以看出默认会编译出u-boot-spl、u-boot-spl.bin和u-boot-spl-16k.bin三个镜像。在Makefile中搜索三个镜像的定义:

$(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

可以看出 u-boot-spl.bin 和 u-boot-spl-16k.bin 都是从u-boot-spl 使用$(OBJCOPY) 过来的,区别是u-boot-spl-16k.bin在生成的过程中有个对齐。从生成的结果讲,u-boot-spl 比 u-boot-spl.bin和u-boot-spl-16k.bin都要大,u-boot-spl.bin和u-boot-spl-16k.bin刚好一样大,也就是u-boot-spl.bin本身就是按照$(PAD_TO) 对齐的。

所以现在重点分析: $(nandobj)u-boot-spl 。

$(nandobj)u-boot-spl 依赖于 $(OBJS) 和 $(nandobj)u-boot.lds,前者就是编译出的目标文件(.o文件), 后者是链接脚本,u-boot-spl 就是把 $(OBJS) 按照链接脚本链接成一个目标文件,链接指令:

$(LD)	$(LDFLAGS)	$(__OBJS)	-Map	$(nandobj)u-boot-spl.map		\
				-o	$(nandobj)u-boot-spl。

-Map 输出链接map到文件中, -o 输出选项。

在 nand_spl/boatd/nuvoton/nuc970evb/Makefile 搜索 LDFLAGS :

LDFLAGS	:=	-T $(nandobj)u-boot.lds -Ttext $(CONFIG_SYS_TEXT_BASE) $(LDFLAGS) \
			$(LDFLAGS_FINAL) -gc-sections

在 nand_spl/boatd/nuvoton/nuc970evb/Makefile 搜索 __OBJS :

# SOBJS 的源文件为汇编文件,.S文件
#
SOBJS = start.o	cpu_init.o lowlevel_init.o divlib.o _lshrdi3.o _ashldi3.o _adhrdi3.o

# COBJS 的源文件为C文件, .c文件
#
COBJS = nand_boot.o	nand_ecc.o nuc970_nand.o nuc970_nand_spl.o nand.o nand_bbt.o nand_ids.o nand_util.o nand_base.o serial_nuc970.o serial.o nuc970_sysprintf.o nuc970_wdt.o timer.o .........
# 省略一些 .o 比较多

# 把SOBJS 和 COBJS 的名字换成源文件的名字
SRCS	:= $(addprefix $(obj), $(SOBJS:.O=.S) $(COBJS:.o=.c))

# 把COBJS和SOBJS加上路径名
OBJS	:=	$(addprefix $(obj), $(SOBJS) $(COBJS))

__OBJS	:=	$(SOBJS) $(COBJS)

到这里 u-boot-spl需要的源文件可以完全知道了,还有一步链接文件 u-boot.lds。

LDSCRIPT= $(TOPDIR)/nand_spl/board/$(BOARDDIR)/u-boot.lds

$(nandobj)u-boot.lds:	$(LDSCRIPT)
		$(CPP)	$(CPPFLAGS)	$(LDFLAGS)	-ansi -D__ASSEMBLY -P - <$^ >$@

nand_spl/boatd/nuvoton/nuc970evb/Makefile 中还有类似

$(obj)start.S:
	@rm -f $@
	@ln -s $(TOPDIR)/nand_spl/board/nuvoton/nuc970evb/start_nand_spl.S $@
	
$(obj)lowlevel_init.S:
	@rm -f $@
	@ln -s $(TOPDIR)/arch/arm/cpu/arm926ejs/nuc970/lowlevel_init.S $@
.....
#
# 建立软链接到合适的源文件
#

#
# 熟悉的编译规则,.S编译成.o 和.c编译成.o的规则动作。
$(obj)%.o:	$(obj)%.S
		$(CC) $(AFLAGS) -c -o $@ $<
		
$(obj)%.o:	$(obj)%.c
		$(CC) $(AFLAGS) -c -o $@ $<

Makefile分析到这里结束,接下来是源码分析。

2、源码分析

​ 从nand_spl/board/nuvoton/nuc970evb/Makefile 中可以看出

​ start.S ----> nand_spl/board/nuvoton/nuc970evb/start_nand_spl.S,所以开始代码从这里分析:


.global	_start
_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
/* 省略一些代码 */
......
......
.global	_TEXT_BASE
_TEXT_BASE:
		.word	CONFIG_SYS_TEXT_BASE
		
.global	_bss_start_ofs
_bss_start_ofs:
		.word	__bss_start	- _start

.global	_bss_end_ofs
_bss_end_ofs:
		.word	__bss_end__	- _start
		
.global	_end_ofs:
_end_ofs:	
		.word	_end	-	_start
/* 省略一些代码 */
.....
reset:
/* ARM芯片有7中工作模式:
 * 1、用户模式(User):用于正常执行程序
 * 2、快速中断模式(FIQ):用于高速数据传输
 * 3、外部中断模式(IRQ):用于通常的中断处理
 * 4、管理模式(SVC):操作系统使用的保护模式
 * 5、数据访问终止模式(abt):
 * 6、系统模式(sys):运行具有特权的操作系统任务
 * 7、未定义指令终止模式(und):当未定义的指令执行时进入该模式,可用于支持硬件
 */
	/* set the cpu to svc32 mode
	 */
	 mrs	r0,cpsr
	 bic	r0,r0,#0x1f
     orr	r0,r0,#0xd3
     msr	cpsr,r0
     
call_board_init_f:
	/* 设置堆栈指针 */
	ldr		sp,	=(CONFIG_SYS_INIT_SP_ADDR)
	
	bic		sp,	sp,	#7
	ldr		r0,+0x00000000
	/* 跳转到board_init_f */
	bl		board_init_f

Arm的工作模式切换有两种方法:

被动切换:在arm运行的时候产生一些异常或者中断来自动进行模式切换

主动切换:通过软件改变,即软件设置寄存器来经行arm的模式切换,应为arm的工作模式都是可以通过相应寄存器的赋值来切换的。

Tips:当处理器运行在用户模式下,某些被保护的系统资源是不能被访问的。

=======================================================================================

board_init_f 在 nand_spl/board/nuvoton/nuc970evb/nuc970_nand_spl.c中定义:

void board_init_f( unsigned long bootflag )
{
    writel( read(REG_PCLKEN0) | 0x10000, REG_PCLKEN0 ); /* UART clk*/
    writel( read(REG_PCLKEN0) | 0x100, REG_PCLKEN0 ); /* Timer clk */
    
    nuc970_serial_initialize();
    nuc970_serial_init();
    
    printf("nand_boot\n");
    nand_boot();
}

​ board_init_f函数中打开了UART和Timer的时钟,做了串口的初始化,然后跳转到nand_boot();

​ nand_boot函数定义在nand_spl/board/nuvoton/nuc970evb/nand_boot.c

void nand_boot( void )
{
    struct nand_chip	nand_chip;
    nand_info_t			nand_info;
    __attribute__((noreturn)) void	(*uboot) (void);
    
    /* 初始化nand */
    nand_chip.select_chip	=	NULL;
    nand_info.priv			=	&nand_chip;
    nand_chip.IO_ADDR_R 	=	nand_chip.IO_ADDR_W = (void	__iomem*)CONFIG_SYS_NAND_BASE;
    nand_chip.dev_read		=	NULL;
    nand_chip.options		= 	0;
    board_nand_init(&nand_chip);
    
    if (nand_chip.select_chip)
        nand_chip.select_chip(&nand_info, 0);
    
    if (nand_scan(&nand_info, 1))
        return;
    
    nand_register(0);
    
    nand_load( &nand_info, CONFIG_SYS_NAND_U_BOOT_OFFS, CONFIG_SYS_NAND_U_BOOT_SIZE,
              (uchar*)CONFIG_SYS_NAND_U_BOOT_DST);
    if ( nand_chip.select_chip)
        nand_chip.select_chip( &nand_chip, -1 );
    
    /* jump to u-boot image
     */
    
    uboot = (void*)CONFIG_SYS_NAND_U_BOOT_START;
    
    (*uboot)();
}

到这里u-boot-spl.bin结束,跳转到u-boot.bin。
Tip:
nuc972内部集成64MB的DDR2,所以代码中未看到初始化SDRAM的过程。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值