TI-Davinci开发系列之八x-loader工作流程分析

时间:2021-12-11 08:49:10

    上接博文《TI-Davinci开发系列之七DVSDK-4.03目录介绍》。DM3730仅集成了一个Nand Flash控制器,所以uboot镜像只能烧在Nand Flash上,通过Nand Flash启动,然而Nand Flash并不支持XIP(eXecute In Place,即芯片内执行)。所以针对Nand Flash的启动方式,一般在采用0x0地址挂载一个容量较小的SRAM(称为Steppingstone)。而且Nand Flash的第一页烧入的x-load,原因是uboot较大,Steppingstone没有足够的空间存放uboot,而x-loader则较小,只有几KB。系统启动时会自动将Nand Flash的第一页上x-loader复制到Steppingstone,其主要工作是初始化PLL,DDR,只有初始化了DDR,才能把uboot下载到DDR里面执行。所以说系统启动首先执行的是x-loader,而x-loader第一阶段的工作与u-boot的第一阶段完全相同,实际上x-loader是u-boot的一个精简版,所以其第一阶段的工作我们只在x-loader中介绍。X-loader启动过程分为stage1和stage2两个阶段, stage1主要完成基本硬件设备初始化和为加载stage2部分的代码准备RAM空间,stage2则是准备环境并引导u-boot在内存中运行。下面分两部分来分析x-loader启动的两个阶段。

/******************************************************************************************************************************************/

原创作品,转载时请务必以超链接形式标明文章原始出处:http://blog.csdn.net/gqb_driver/article/details/20069643,作者:gqb666  

/******************************************************************************************************************************************/

TI-Davinci开发系列之八x-loader工作流程分析

                                                                                  图2.1 两种启动方式存储分配

一、x-loader启动第一阶段stage1

x-loader的第一阶段主要由x-boot源文件目录\cpu\omap3目录下的start.S和board\omap3stalker目录下platform.S来完成,前者是SOC平台相关,后者是开发板相关的。

(1) 硬件设备初始化

基本硬件设备的初始化主要在start.S内完成,依次完成如下设置:将CPU的工作模式设为管理模式(svc),将中断向量表拷贝到SRAM,关闭WATCHDOG,后来就是关闭MMU,CACHE等。

reset:
/*
* set the cpu to SVC32 mode 设置ARM处理器的工作模式为SVC模式
*/
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr,r0
/*将中断向量表拷贝到SRAM*/
#if (CONFIG_OMAP34XX)
/* Copy vectorsto mask ROM indirect addr */
adr r0, _start @ r0<- current position of code
add r0, r0, #4 @ skip reset vector
mov r2, #64 @ r2 <- size to copy
add r2, r0, r2 @ r2 <- sourceend address
mov r1, #SRAM_OFFSET0 @ build vect addr
mov r3, #SRAM_OFFSET1
add r1, r1, r3
mov r3, #SRAM_OFFSET2
add r1, r1, r3
next:
ldmia r0!, {r3 - r10} @ copy from source address [r0]
stmia r1!, {r3 - r10} @ copyto target address [r1]
cmp r0, r2 @until source end address [r2]
bne next @loop until equal */
//

ldr pc, _start_armboot @ jump to C code
_start_armboot: .wordstart_armboot
cpu_init_crit:
/*关闭MMU与CACHE */
mov r0, #0 @ set up for MCR
mcr p15, 0, r0, c8, c7, 0 @ invalidateTLBs
mcr p15, 0, r0, c7, c5, 0 @ invalidateicache

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 12(Z---) BTB
mcr p15, 0, r0, c1, c0, 0
/*调用lowlevel_init用来初始化RAM*/
mov ip, lr @persevere link reg across call
bl lowlevel_init @go setup pll,mux,memory
mov lr, ip @restore link
mov pc, lr @back to my caller
(2)为stage2准备RAM空间

所谓准备RAM空间,就是初始化内存芯片,使它可用。对于OMAP3这种SOC,通过在start.S中调用lowlevel_init函数来设置存储控制器,使得外接的SDRAM可用。代码在board\omap3stalker目录下platform.S中。

.globl lowlevel_init
lowlevel_init:
ldr sp, SRAM_STACK
str ip, [sp] /* stashold link register */
mov ip, lr /*save link reg across call */
bl s_init /* gosetup pll,mux,memory */
ldr ip, [sp] /* restore saveip */
mov lr, ip /*restore link reg */
/* back toarch calling code */
mov pc, lr
/* the literalpools origin */
.ltorg

(3)复制stage2代码到RAM空间

这里将x-loader的代码(实际包括第一、二阶段)都复制到SDRAM中,这在\cpu\omap3中start.S中完成,在本系统的x-loader中,复制代码实际并未发生,因为SRAM支持XIP。

relocate:                           /*将x-loader复制到RAM中      */
adr r0, _start /* r0:当前代码的开始地址 */
ldr r1, _TEXT_BASE /* r1:代码段的链接地址 */
cmp r0, r1 /* 测试是否需要复制(SRAM,SDRAM,NOR FLAHS不需要复制)
beq stack_setup /*直接跳到栈初始化部分) */

ldr r2, _armboot_start /*_armboot_start在前面定义,第一条指令地址*/
ldr r3, _bss_start /*链接脚本x-loader.lds中定义,是代码段的结束地址*/
sub r2, r3, r2 /* r2 :代码段长度 */
add r2, r0, r2 /* r2:SRAM上代码段的结束地址 */

copy_loop:
ldmia r0!, {r3-r10} /*从地址[r0]处获得数据 */
stmia r1!, {r3-r10} /*复制到地址[r1]处 */
cmp r0, r2 /*判断是否复制完毕 */
ble copy_loop

(4) 设置堆栈

栈的设置灵活性很大,只要让sp寄存器指向一段没有使用的内存即可。

/* Set up the stack                                           */
stack_setup:
ldr r0, _TEXT_BASE /*_TEXT_BASE代码段的开始地址 */
sub sp, r0, #128 /*为 abort-栈保留32字节 */
and sp, sp, #~7 /* 8字节对齐 */

(5)跳转到stage2的入口点

在跳转之前,还要清除BSS段(初始值为0、无初始值的全局变量、静态变量放在BSS段),代码如下:

clear_bss:
ldr r0, _bss_start /* bss段的开始地址 */
ldr r1, _bss_end /* bss段的结束地址,它的值在链接脚本中定义*/
mov r2, #0x00000000 /* clear value */
clbss_l:
str r2, [r0] /*往bss段内写入0值 */
cmp r0, r1 /*are we at the end yet */
add r0, r0, #4 /* increment clearindex pointer */
bne clbss_l /* keep clearing till atend */

ldr pc, _start_armboot /*向C函数入口跳转 */
_start_armboot: .word start_armboot

二、 x-loader启动第二阶段stage2

X-loader第二阶段主要用来引导u-boot从SDRAM启动,主要根据配置文件中定义的启动类型调用相应驱动程序,将u-boot.bin格式的镜像文件从不同存储介质中拷贝到内存,并从内存开始执行。主要代码在lib/下的board.c。

#ifdef CONFIG_MMC  //如果配置了MMC启动,则调用mmc驱动加载
/* first trymmc */
if (mmc_init(1)) {
size =file_fat_read("u-boot.bin", buf, 0);
if (size > 0) {
#ifdef CFG_PRINTF
printf("Loadingu-boot.bin from mmc\n");
#endif
buf += size;
}
}
#endif
if (buf == (uchar*)CFG_LOADADDR) {
/* if no u-boot on mmc, tryonenand or nand, depending upon sysboot */
if (get_mem_type() ==GPMC_ONENAND){
#ifdef CFG_ONENAND
……
#ifdef CFG_NAND_K9F1G08R0A //如果定义了nand启动,调用nand加载
#ifdef CFG_PRINTF
printf("Loading u-boot.bin fromnand\n");
#endif
for (i = NAND_UBOOT_START; i < NAND_UBOOT_END; i+= NAND_BLOCK_SIZE){
if (!nand_read_block(buf, i))
buf += NAND_BLOCK_SIZE; /* advance buf ptr*/
}
#endif
}

下转博文u-boot之u-boot-2009.11启动过程分析