u_boot_2013.01启动流程分析(二)(for exynos4412)

一、前言

u-boot第一阶段的代码最终跳转到这里运行

这个函数做了两件事:

1、将u-boot整个的代码拷贝到内存当中

2、将pc指针指向SDRAM中的u-boot起始代码

u_boot_2013.01启动流程分析(二)(for exynos4412)

二、u-boot第二阶段代码(一)

(大家接下来看到的代码是只与exynos4412的u-boot相关的代码,本人对代码做了精简,方便理清启动流程)


arch/arm/lib/crt0.S 


_main:


/*
 * Set up initial C runtime environment and call board_init_f(0).
 */

/*

1)       Start . S 文件执行到bl main函数时,就会跳到crt0.s这个文件中。

 2)       调用board_init_f函数与设置C语言运行环境

 3)       CONFIG_SYS_INIT_SP_ADDR  =  0X43E00000- 128

4)       把这个地址作为sp数据栈指针

5)       这种操作是将sp栈指针所指地址8字节对齐

6)       GD_SIZE = 128  sp指针又向下偏移128字节后对齐

7)       将此时sp指针的值保存在r8寄存器中,将0写入r0寄存器中传参到 board_init_f函数

注意这个地方的 blboard_init_f函数它会朝两个方向跳转执行  一是U_boot第一阶段的程序 : 将整个bootloader拷贝到内存当中的程序。。。。二是U_boot 第二阶段的执行初始化列表,为U_boot重定向预留内存       */
      
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)


bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
sub sp, #GD_SIZE /* allocate one GD above SP */
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
mov r8, sp /* GD is above SP */
mov r0, #0
bl board_init_f


arch/arm/lib/board.c 

/*定义了bd-t 的结构体类型*/

typedef struct bd_info {
unsigned int bi_baudrate; /* serial console baudrate */
    ulong        bi_arch_number; /* unique id for this board */
    ulong        bi_boot_params; /* where this board expects params */
unsigned long bi_arm_freq; /* arm frequency */
unsigned long bi_dsp_freq; /* dsp core frequency */
unsigned long bi_ddr_freq; /* ddr frequency */
    struct /* RAM configuration */
    {
ulong start;
ulong size;
    } bi_dram[CONFIG_NR_DRAM_BANKS];
} bd_t;

/*为 int () ( void ) 这种函数类型取个别名为init_fnc_t*/

typedef int (init_fnc_t) (void);

/*gd.mon_len= _bss_end_ofs;(u_boot大小)*/

gd{

.mon_len = _bss_end_ofs;(u_boot大小)
}

/*                                       int () ( void )

init_sequence[] 数组中存放的是init_fnc_t这种类型的函数入口地址*/

init_fnc_t *init_sequence[] = {
/*获取cpu id*/
arch_cpu_init, /* basic arch cpu dependent setup */
/*定时器初始化*/
timer_init, /* initialize timer */
/*环境变量初始化:指定了一个默认的环境变量
         env_init 最最开始没有设置板子的环境变量setenv  ,就有这个默认的环境变量,如果设置了环境变量,就从emmc读取              envsetenvsave保存的)*/
env_init, /* initialize environment */
/*初始化波特率*/
init_baudrate, /* initialze baudrate settings */
/*初始化串口:确定哪一个串口设备输出(默认的输出是哪一个串口)  宏定义开关发现是2号串口*/
serial_init, /* serial communications setup */
/*控制台一级初始化*/
console_init_f, /* stage 1 init of console */
/*打印u_boot版本信息*/
display_banner, /* say that we are here */
/*打印cpu的信息*/
print_cpuinfo, /* display cpu info (and speed) */

/*记录内存的大小

          内存大小 gd->ram_size= 4x256M    */

dram_init, /* configure available RAM banks */
NULL,
};

/*定义一个bd_t结构体类型的指针

init_fnc_ptr指向一块地址该地址装的也是一个地址,此地址指向init_fnc_t类型的一个函数

定义一个gd_t结构体类型的指针Unsigned long 类型*/

void board_init_f(ulong bootflag)
{
bd_t *bd;
init_fnc_t **init_fnc_ptr;
gd_t *id;
ulong addr, addr_sp;
void *new_fdt = NULL;
size_t fdt_size = 0;


//#define DECLARE_GLOBAL_DATA_PTR     register volatile gd_t *gd asm ("r8")

       /*以内联汇编的形式定义了一个定义一个gd_t结构体类型的指针

        指向r8 所指向的地址CONFIG_SYS_INIT_SP_ADDR  =0X43E00000 - 128把这个地址作为sp数据栈指针*/

//DECLARE_GLOBAL_DATA_PTR;
memset((void *)gd, 0, sizeof(gd_t));

//记录uboot大小
gd->mon_len = _bss_end_ofs;

//调用初始化序列中的每一个函数
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}

下一节将会分析u-boot重定向时在内存中到底是怎么划分的

未完待续。。。。。。



(本人技术经验浅薄,文中难免有疏漏错误之处,请在评论中予以提醒,共同进步,非常感谢!)