U-boot-2014.04移植到MINI2440(11) 第二启动阶段分析

来源:互联网 发布:英文润色软件 编辑:程序博客网 时间:2024/05/14 03:25

回顾一下u-boot启动其一阶段做了哪些事:

第一:设置CPU为SVC模式

第二:关闭看门狗

第三:关中断和子中断

第四:设置时钟

第五:MMU关闭,清除cache和TLB,使能地址对齐检查等

第六:初始化SDRAM

       在我前面的分析里,第一阶段的最后,通过bl _main,跳到了arch/arm/lib/crt0.S里面去了,从这里开始时第二阶段的入口,下面从这里开始分析。

       文件:crt0.S

       先看看该文件对_main的描述,在第18行,有一个_main execution sequence is:下面有五步,其实就是对_main的执行流程的一个介绍,我翻译一下:

       1.设置初始环境准备调用board_init_f()。提供一个堆栈或者地址来存储全局数据结构gd。

       2.调用board_init_f()。该函数是为了准备执行的硬件环境,因为RAM可能还不能使用,board_init_f()必须使用当前的GD来存储必须在稍后的阶段传递的任何数据。这些数据包括搬迁目的地,未来堆栈,以及未来GD位置。

       3.设置中间环境。使用board_init_f()在RAM中分配空间给gd和堆栈,但是bss和非常量数据仍然无法使用。

       4.调用重定向代码。此功能重新定位U-Boot从当前位置到由board_init_f计算的重定向后的地址。

       5.建立最终环境调用board_init_r()。包括在RAM中对BSS清零,初始化变量和堆栈,gd保留通过board_init_f()设定的值。

       6.跳转到board_init_r()执行

函数:_main

       ENTRY(_main)

 

/*

 * Set up initial C runtime environment andcall board_init_f(0).

 */

 

#ifdefined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)

       ldr   sp,=(CONFIG_SPL_STACK)

#else

       ldr   sp,=(CONFIG_SYS_INIT_SP_ADDR)

#endif

       bic  sp,sp, #7      /* 8-byte alignment for ABI compliance*/

       sub  sp,sp, #GD_SIZE     /* allocate one GD aboveSP */

       bic  sp,sp, #7      /* 8-byte alignment for ABIcompliance */

       mov       r9,sp            /* GD is above SP */

       初始化栈指针,为board_init_f准备调用环境。最后r9寄存器中的地址就是gd结构体的首地址。

       #if 1

       __TEXT_BASE:

       .word CONFIG_SYS_TEXT_BASE

       mov r0, #0

       ldr r1, __TEXT_BASE

       ldr r2, __TEXT_BASE

       ldr r3, =__bss_end

       sub r2, r3, r2

       bl copy_code_to_sdram

       bl clear_bss

       ldr pc, =call_board_init_f

       .word的意思是在__TEXT_BASE地址处放置CONFIG_SYS_TEXT_BASE的值,还有一种就是.globl,这是告诉编译器紧跟着后面的的符号要被编译器用到。

       给r0清零,r1和r2都给__TEXT_BASE地址,r3给bss段的结束地址。结束地址和TEXT_BASE的差值给r2,然后跳转到copy_code_to_sdram,切过去:

       void copy_code_to_sdram(unsigned char*src, unsigned char *dest, unsigned int len)

{

int i = 0;

/* 如果是 NOR 启动 */

       if (isBootFromNorFlash())

       {

       while (i < len)

              {

                     dest[i] = src[i];

              i++;

              }

       }

else

       {

       nand_init_b();

       nand_read_b((unsigned int)src, dest,len);

       }

}

先判断是从nand还是从nor启动,然后将代码拷贝到sdram中去。接着,请bss段,然后ldr pc, =call_board_init_f,跳转到

call_board_init_f:

       mov r0, #0

       bl board_init_f

函数:board_init_f

       gd->mon_len = (ulong)&__bss_end -(ulong)_start;

指定代码的大小,为bss段的尾地址减去_start地址。

       for (init_fnc_ptr = init_sequence;*init_fnc_ptr; ++init_fnc_ptr) {

              if ((*init_fnc_ptr)() != 0) {

                     hang ();

              }

       }

遍历了init_sequence中的函数,init_sequence函数如下:

init_fnc_t *init_sequence[]= {

       arch_cpu_init,            /* basic arch cpu dependent setup */

       mark_bootstage,

#ifdefCONFIG_OF_CONTROL

       fdtdec_check_fdt,

#endif

#ifdefined(CONFIG_BOARD_EARLY_INIT_F)

       board_early_init_f,

#endif

       timer_init,            /* initialize timer */

#ifdef CONFIG_BOARD_POSTCLK_INIT

       board_postclk_init,

#endif

#ifdefCONFIG_FSL_ESDHC

       get_clocks,

#endif

       env_init,              /*initialize environment */

       init_baudrate,             /* initialze baudrate settings */

       serial_init,            /* serial communications setup */

       console_init_f,           /* stage 1 init of console */

       display_banner,          /* say that we are here */

       print_cpuinfo,            /* display cpu info (and speed) */

#ifdefined(CONFIG_DISPLAY_BOARDINFO)

       checkboard,         /* display board info */

#endif

#ifdefined(CONFIG_HARD_I2C) || defined(CONFIG_SYS_I2C)

       init_func_i2c,

#endif

       dram_init,            /* configure available RAM banks */

       NULL,

};

这里有很多重要的初始化函数,例如init_baudrate,serial_init,,console_init_f,等等,就不一一切过去看了,只要知道每个函数名是干嘛的就可以了。

addr = CONFIG_SYS_SDRAM_BASE +get_effective_memsize();

这里地址等于BASE+有效地址,也就是整个sdram的可用部分。在下面:

#if !(defined(CONFIG_SYS_ICACHE_OFF) &&defined(CONFIG_SYS_DCACHE_OFF))

       /* reserveTLB table */

       gd->arch.tlb_size= PGTABLE_SIZE;

       addr -=gd->arch.tlb_size;

 

       /* rounddown to next 64 kB limit */

       addr&= ~(0x10000 - 1);

 

       gd->arch.tlb_addr= addr;

       debug("TLBtable from %08lx to %08lx\n", addr, addr + gd->arch.tlb_size);

#endif

 

       /* rounddown to next 4 kB limit */

       addr&= ~(4096 - 1);

       debug("Topof RAM usable for U-Boot at: %08lx\n", addr);

这里是说如果没有定义关闭icache以及dcache关闭,就把PGTABLE_SIZE给gd,同时addr要减去gd这部分的大小,最后addr的值其实就是tlb的地址,并且要4Kb对齐。

addr=CONFIG_SYS_TEXT_BASE;

这里的CONFIG_SYS_TEXT_BASE;代码u-boot代码在内存中的起始地址。

addr_sp = addr - TOTAL_MALLOC_LEN;

       debug("Reserving %dk for malloc()at: %08lx\n",

                     TOTAL_MALLOC_LEN >>10, addr_sp);

       /*

        *(permanently) allocate a Board Info struct

        *and a permanent copy of the "global" data

        */

       addr_sp -= sizeof (bd_t);

       bd = (bd_t *) addr_sp;

       gd->bd = bd;

       debug("Reserving %zu Bytes for BoardInfo at: %08lx\n",

                     sizeof (bd_t), addr_sp);

#ifdef CONFIG_MACH_TYPE

       gd->bd->bi_arch_number= CONFIG_MACH_TYPE; /* board id for Linux */

#endif

 

       addr_sp-= sizeof (gd_t);

       id= (gd_t *) addr_sp;

       debug("Reserving%zu Bytes for Global Data at: %08lx\n",

                     sizeof(gd_t), addr_sp);

 

首先预留malloclen,一般为0x400000,为bd,gd做一个永久的拷贝,因为这时候环境已经准备的差不多了。留出了全局信息bd_t结构体的空间,首地址存在gd->bd。留出gd_t结构体的空间。首地址存在id中。将此地址保存在gd->irq_sp中作为异常栈指针。

addr_sp += 128;  /*leave 32 words for abort-stack   */

       gd->irq_sp= addr_sp;

这里是为异常留的堆栈部分。

gd->bd->bi_baudrate = gd->baudrate;

       /* Ram istboard specific, so move it to board code ... */

       dram_init_banksize();

       display_dram_config();     /* and display it */

首先将gd->baudrate赋给gd->bd->bi_baudrate,然后对板上的BANKS进行一个初始化。

gd->relocaddr = addr;

       gd->start_addr_sp = addr_sp;

       gd->reloc_off = addr - (ulong)&_start;

       debug("relocation Offset is:%08lx\n", gd->reloc_off);

       if (new_fdt) {

              memcpy(new_fdt, gd->fdt_blob,fdt_size);

              gd->fdt_blob = new_fdt;

       }

       memcpy(id, (void *)gd, sizeof(gd_t));

       return (unsigned int)id;

       三个地址的幅值,主要是重定向的起始结束以及sp的起始地址。最后将gd结构体拷贝到新的地址上。board_init_f结束。

       ldr sp, [r9, #GD_START_ADDR_SP] /* sp =gd->start_addr_sp */

       bic sp, sp, #7 /* 8-byte alignment forABI compliance */

       ldr r9, [r9, #GD_BD] /* r9 = gd->bd */

       sub r9, r9, #GD_SIZE /* new GD is belowbd */

       ldr r1, __TEXT_BASE

       bl board_init_r

       执行这一段,更新sp,更新gd地址,跳转到board_init_r。

函数:board_init_r

       void board_init_r(gd_t *id, ulongdest_addr)

{

       ulong malloc_start;

#if!defined(CONFIG_SYS_NO_FLASH)

       ulong flash_size;

#endif

 

       gd->flags |= GD_FLG_RELOC;   /* tell others: relocation done */

       bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_R,"board_init_r");

 

       monitor_flash_len =(ulong)&__rel_dyn_end - (ulong)_start;

 

       /* Enable caches */

       enable_caches();

 

       debug("monitor flash len:%08lX\n", monitor_flash_len);

       board_init(); /* Setup chipselects */

       使能caches,做初步板级初始化。

       在下面主要是对比如串口,时钟,Flash外设等等做一板级初始化,这里不一一细致介绍了,然后进入      

for (;;) {

              main_loop();

       }

这里main_loop里面,就等待我们的命令输入和解析了。这里我修改移植的方法,并没有选用-pie选项,并且我在board_init_f当中进行了如下修改:

//addr -= gd->mon_len;
//addr &= ~(4096 - 1);
addr = CONFIG_SYS_TEXT_BASE;

相当于进行了代码的重定向,所以就没有跳转到relocate_code里面去,所以那部分比较难懂的代码这里没分析,就分析道这里吧,如有不正确的地方还请指出,大家共同进步。

0 0
原创粉丝点击