打印
[视频教程]

nuvoton uboo2013引导流程 2 - spl

[复制链接]
685|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2021-4-9 12:49 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
基于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的过程。


使用特权

评论回复
沙发
chenjun89| | 2021-4-9 18:33 | 只看该作者
看看,学习一下。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1942

主题

15667

帖子

12

粉丝