u_boot初始化流程
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
U-Boot启动代码分析
U-boot的启动顺序分为stage1和stage2两部分,见下图。依赖于CPU体系结构的代码(如设备初始化代码等)通常放在stage1中用汇编语言实现,而在stage2则通常由C语言实现,这样可以实现复杂的功能,而且有更好的可读性和移植性。以下主要梳理了stage2阶段函数的调用顺序以及每个函数的功能。
U-boot的启动顺序
C语言代码部分lib_arm/board.c中的start_armboot既是C语言开始的函数也是整个启动代码中C语言的主函数,同时还是整个U-boot的主函数,该函数只要完成如下操作。
(1)调用一系列的初始化函数。
(2)初始化Flash设备。
(3)初始化系统内存分配函数
(4)如果目标系统拥有NAND设备,则初始化NAND设备
(5)如果目标系统有显示设备,则初始化该类设备。
(6)初始化相关网络设备,填写IP、MAC地址等。
(7)进入命令循环(即整个Boot的工作循环),接收用户从串口输入的命令,然后进行相应的工作。
下面结合源码分析函数调用顺序以及函功能:
代码:
void start_armboot (void)
{
init_fnc_t **init_fnc_ptr;
char *s;
int mmc_exist = 0;
#if defined(CONFIG_VFD) || defined(CONFIG_LCD)
unsigned long addr;
#endif
注释:从U-boot stage1中start.s程序调到这里执行start_armboot函数,这一段代码进行了变量声明,其中定义了一个名为init_fnc_ptr的双重指针。如果CONFIG_VFD或者CONFIG_LCD被定义了则声明一无符号长整型变量addr,本开发板中没有定义无需声明addr。
代码:
/* Pointer is writable since we allocated a register for it */
gd = (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t));
/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__("": : :"memory"); //内存屏障,告诉编译器内存被修改过了
memset ((void*)gd, 0, sizeof (gd_t));
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t)); //指向gd之前
memset (gd->bd, 0, sizeof (bd_t));
// gd->flags |= GD_FLG_RELOC;
monitor_flash_len = _bss_start - _armboot_start; //u-boot映像的大小其中_armboot_start为code start ,_bss_start为code + data end == BSS start.
注释:
gd = (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t));//内存强制转换,gd为全局环境变量,gd指向uboot之前的地址;
memset ():void * memset(void * s,char c,size_t count)将指针s所指地址以及之后count个地址中数值赋值为c。memset ((void*)gd, 0, sizeof (gd_t))的作用为:gd整个地址的值初始化为0;memset (gd->bd, 0, sizeof (bd_t))的作用为bd地址的值初始化为0。
代码:
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) { //相当于调用指针中的一个函数,如果不为0就表示死机
hang ();
}
}
注释:
将init_squence数组送给init_fnc_ptr,利用循环调用init_squence数组中的多个初始化函数,包括初始化CPU、board、中断、时钟、NOR Flash、NAND Flash等,后面根据代码进行分析。初始化完成之后进入hang()处于死循环即完成U-boot使命。
init_sequence[ ]数组保存基本的初始化函数指针,在board.c中对数组进行了定义:
#if defined(CONFIG_ARCH_CPU_INIT)
arch_cpu_init, /* basic arch cpu dependent setup */
#endif
board_init, /* basic board dependent setup */
//#if defined(CONFIG_USE_IRQ)
interrupt_init, /* set up exceptions */
//#endif
//timer_init, /* initialize timer */
#ifdef CONFIG_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 */
off_charge,// xiebin.wang @ 20110531,for charger&power off device.
display_banner,/* say that we are here */
#if defined(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo,/* display cpu info (and speed) */
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
checkboard,/* display board info */
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
//init_func_i2c,
#endif
dram_init, /* configure available RAM banks */
#if defined(CONFIG_CMD_PCI) || defined (CONFIG_PCI)
//arm_pci_init,
#endif
display_dram_config,
NULL,
};
注释:
下面按照顺序依次分析各个初始化函数作用(绿色代码是被注释掉的并不执行):
arch_cpu_init():基本处理器相关配置。如果定义了CONFIG_ARCH_CPU_INIT则执行此函数,本开发板在include/configs/smdkc100.h中定义了此变量。
最终在串口打印:
CPU: SMDK4412-AP1.1 [e4412211]