您的位置:首页 > 其它

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

2015-09-05 17:39 381 查看
回顾一下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里面去,所以那部分比较难懂的代码这里没分析,就分析道这里吧,如有不正确的地方还请指出,大家共同进步。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: