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里面去,所以那部分比较难懂的代码这里没分析,就分析道这里吧,如有不正确的地方还请指出,大家共同进步。
- U-boot-2014.04移植到MINI2440(11) 第二启动阶段分析
- U-boot-2014.04移植到MINI2440(4) 第一启动阶段start.S等详细分析
- U-boot-2014.04移植到MINI2440(3) Makefile分析
- 移植u-boot到mini2440--board_init_r 分析
- U-boot-2014.04移植到MINI2440(9) nor flash启动和nand flash 启动
- U-boot-2014.04移植到MINI2440(2) Readme翻译分析
- U-boot-2014.04移植到MINI2440(7) nand flash datasheet及arm9控制寄存器分析
- u-boot移植到mini2440
- 移植u-boot到mini2440--从norflash启动
- u-boot-2009.11移植(适用于TQ2440和MINI2440)第二篇:探索启动代码
- 移植u-boot到mini2440--初始化代码分析
- U-boot-2014.04移植到MINI2440(1) 初步探索移植
- U-boot-2014.04移植到MINI2440(5) Nor FLASH 读写支持移植
- U-boot-2014.04移植到MINI2440(6) DM9000网卡移植
- U-boot-2014.04移植到MINI2440(8) nand flash 读写支持移植
- U-boot-2014.04移植到MINI2440(10) 移植nand flash保存环境变量、添加分区
- u-boot-2009.11移植到mini2440(一)
- 移植u-boot到mini2440开发板。
- VS2010如何添加MSCOMM控件
- 代码封装
- 表单checkbox选中问题
- C++虚函数的工作原理是什么
- C语言基础知识之(二十):指针高级运用
- U-boot-2014.04移植到MINI2440(11) 第二启动阶段分析
- LeetCode -- Balanced Binary Tree
- 《实用技巧》——让你的网站变成响应式的3个简单步骤
- Android UI 调试工具 Hierarchy Viewer
- 把我弄混淆的操作符重载
- linux syscall系统调用获取线程PID
- URAL 1939 First Seal
- 分布式事务JTA 实现之 JOTM
- simhash类的使用