Atmel SAMA5D3 AT91Bootstrap 分析


一、 AT91Bootstrap 介绍

        AT91Bootstrap 是针对 Atmel 芯片的第一级引导装载程序,它提供了一整套的算法管理硬件初始化(GPIO,Clock,SDRAM等),从指定的存储介质( Nand Flash,SDCard 等)下载主应用程序( uboot 或 kernel )到主存储器( SDRAM )并启动它。

二、 代码分析

首先浏览一下 Makefile,指定了链接脚本 elf32-littlearm.lds 。简单看一下 elf32-littlearm.lds ,指定了程序入口 ENTRY(reset) 。reset 定义在 crt0_gnu.S ,它即入口文件。

crt0_gnu.S :


reset:

/* 异常向量表 */
_exception_vectors:
    b   reset_vector    /* reset */
    b   undef_vector    /* Undefined Instruction */
    b   swi_vector      /* Software Interrupt */
    b   pabt_vector     /* Prefetch Abort */
    b   dabt_vector     /* Data Abort */
.word       _edata      /* Size of the binary for ROMCode loading */
    b   irq_vector  /* IRQ : read the AIC */
    b   fiq_vector      /* FIQ */

reset_vector:

/* 设置堆栈指针 SP */
_init_stack:
    ldr   sp,=TOP_OF_MEMORY   /* TOP_OF_MEMORY = “0x310000”  */

/* 初始化时钟 */

    /* r4 = lowlevel_clock_init 的入口地址  */

    ldr     r4, = lowlevel_clock_init  

    

    /* 保存 PC 指针 */

    mov  lr, pc            

    

    /* 跳转到函数 lowlevel_clock_init 的入口地址去执行 */                      

    bx     r4 

/* 拷贝数据段 */
_init_data:
    /*
      _lp_data:
          .word _edummy
          .word _sdata
          .word _edata

      */

    /* r2 指向 _lp_data */

    ldr      r2, =_lp_data  

    

    /* r1 = [r2] , r1 指向 _edummy

        r3 = [r2+4] , r3 指向 _sdata
        r4 = [r2+8] , r4 指向 _edata
    */
    ldmia    r2, {r1, r3, r4}

1:

    /* 比较 r3,r4 */

    cmp     r3, r4          

    

    /* 如 r3<r4 ,则 r2=[r1], r1=r1+4 */

    ldrcc    r2, [r1], #4  


    /* 如 r3<r4 ,则 [r3]=r2, r3=r3+4 */

    strcc    r2, [r3], #4  


    /* 如 r3<r4 ,则跳到 1 */

    bcc      1b               

/* 清 bss 段 */
_init_bss:
    /*
    _lp_bss:
        .word _sbss
        .word _ebss

    */

    /* r2 指向 _lp_bss */

    adr    r2, _lp_bss  


    /* r3 = [r2] , r1 指向 _sbss
        r4 = [r2+4] , r3 指向 _ebss
    */

    ldmia  r2, {r3, r4}


    /* r2=0 */

    mov    r2, #0  

1:


    /* 比较 r3,r4 */

    cmp  r3, r4      

     

    /* 如 r3<r4 ,则 [r3]=r2=0, r3=r3+4 */

    strcc  r2, [r3], #4  


    /* 如 r3<r4 ,则跳到 1 */

    bcc    1b               

/* 跳转到 c 代码 main 函数*/

_branch_main:

    /* r4 指向 main 函数入口地址 */

    ldr     r4, = main 


    /* 保存 PC */ 

    mov  lr, pc           


    /* 跳转到 main 函数 */

    bx      r4               

/* main 函数返回 JUMP_ADDR 到r0中,该值是 u-boot 或 kernel 在 SDRAM 中的地址 。具体是引导哪个程序还要看是使用的哪个配置,比如使用 board/at91sama5d3xek/at91sama5d3xeknf_android_dt_defconfig,则引导 NandFlash 中的 android 内核,使用 board/at91sama5d3xek/at91sama5d3xeknf_uboot_defconfig ,则引导 NandFlash 中的 u-boot 。
*/

/* 跳转到指定的地址去执行 */

_go:

    /* 获取机器 ID */

    ldr     r1, =MACH_TYPE  


    /* 保存 PC */

    mov  lr, pc                       


    /* 跳转到 JUMP_ADDR */

    bx     r0                            

main 函数 定义在 main.c 文件中 
int main(void)

{

    /* 镜像的加载地址 */

    image.dest = (unsigned char *)JUMP_ADDR; 

    /* 启动方式 ,可以从 DataFlash ,NandFalsh ,SDCard 等启动。这里以 NandFlash 启动为例 */
#ifdef CONFIG_NANDFLASH

    media_str = "NAND: ";

    /* 镜像地址 */

    image.offset = IMG_ADDRESS; 

    /* 镜像大小 */ 

    image.length = IMG_SIZE;         
#endif

#ifdef CONFIG_HW_INIT

    /* 关闭看门狗,配置 PLLA,主时钟,使能外部复位,初始化 DBGU ,设置协处理器 CP15,初始化 DDRAM 控制器等 */

    hw_init(); 
#endif

#ifdef CONFIG_LOAD_ONE_WIRE
    /* Load one wire informaion */
    load_1wire_info();

#endif


    /* 初始化函数指针 load_image */

    init_loadfunction();                  


    /* 加载镜像文件 */

    ret = (*load_image)(&image); 

#ifdef CONFIG_SCLK
    slowclk_switch_osc32();
#endif


    /* 返回跳转地址 */

    return JUMP_ADDR;   

}

init_loadfunction() 定义如下,根据选定的启动方式和引导内容,将函数指针 load_image 指向相关函数的入口地址:
static int init_loadfunction(void)
{
#if defined(CONFIG_LOAD_LINUX) || defined(CONFIG_LOAD_ANDROID)
    load_image = &load_kernel;
#else
#if defined (CONFIG_DATAFLASH)
    load_image = &load_dataflash;
#elif defined(CONFIG_NANDFLASH)
    load_image = &load_nandflash;
#elif defined(CONFIG_SDCARD)
    load_image = &load_sdcard;
#else
#error "No booting media_str specified!"
#endif
#endif
    return 0;
}

本文是 NandFlash 启动,引导 u-boot ,所以 load_image = &load_nandflash 。

load_nandflash 定义在 driver/nandflash.c :
int load_nandflash(struct image_info *image)
{
    struct nand_info nand;
    int ret;


    /* 初始化 NandFlash */

    nandflash_hw_init(); 

    if (nandflash_get_type(&nand))
        return -1;

#ifdef CONFIG_NANDFLASH_RECOVERY
    if (nandflash_recovery(&nand) == 0)
        return -2;
#endif

#ifdef CONFIG_USE_PMECC
    if (init_pmecc(&nand))
        return -1;
#endif

#ifdef CONFIG_ENABLE_SW_ECC
    dbg_log(1, "NAND: Using Software ECC\n\r");
#endif

    dbg_log(1, "NAND: Image: Copy %d bytes from %d to %d\r\n",image->length, image->offset, image->dest);

    /* 将镜像文件从 NandFlash 加载到 SDRAM 的 JUMP_ADDR 地址处 */
    ret = nand_loadimage(&nand, image->offset, image->length, image->dest);
    if (ret)
        return ret;

    if (image->of) {
        dbg_log(1, "NAND: dt blob: Copy %d bytes from %d to %d\r\n",image->of_length, image->of_offset, image->of_dest);

        ret = nand_loadimage(&nand, image->of_offset,image->of_length, image->of_dest);
        if (ret)
            return ret;
}

    return 0;
}


AT91Bootstrap 的启动过程,主要分为两个阶段:

第一阶段:汇编程序 - crt0_gnu.S 主要是建立异常向量表、初始化堆栈、初始化时钟、设置数据段、设置 bss 段,然后跳转到main函数执行,最后跳转到 SDRAM 的 JUMP_ADDR 地址去启动 u-boot 或 kernel 。


第二阶段:C 程序 - main.c ,主要是 SDRAM 初始化,镜像文件的拷贝等,完成程序在 SDRAM中 运行的准备工作 。


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值