uboot启动的第一阶段是cpu架构相关的初始化,用汇编完成,从arch/arm/cpu/arm920t/s3c24x0目录下的start.S文件开始看:
代码一开始就跳转到start_code:
1、把cpu设为管理模式
为什么要设置成管理模式:https://blog.csdn.net/rheostat/article/details/7734407
2、关看门狗
3、屏蔽中断
4、设置时钟分频系数
5、调用cpu_init_crit函数
cpu_init_crit函数关闭了cache和mmu之后,调用lowlevel_init函数,在lowlevel_init里面初始化SDRAM。
6、设置栈,跳转到c函数board_init_f函数执行
board_init_f函数做的事:
①、遍历一个指针数组,循环调用各个初始化函数,如果这些初始化函数的返回值有一个不等于0,说明初始化出错,cpu陷入死循环函数hang()
指针数组成员如下:
1 init_fnc_t *init_sequence[] = { 2 board_early_init_f, 3 timer_init, /* initialize timer */ 4 env_init, /* initialize environment */ 5 init_baudrate, /* initialze baudrate settings */ 6 serial_init, /* serial communications setup */ 7 console_init_f, /* stage 1 init of console */ 8 display_banner, /* say that we are here */ 9 print_cpuinfo, /* display cpu info (and speed) */ 10 };
②、把指针gd指向之前栈指针指向的地址0x30000f80,并把gd指针强制转化的gd_t结构体指针,从而设置各种参数(gd的意思是global_data):
设置参数代码:
1 memset((void *)gd, 0, sizeof(gd_t));//初始化结构体内容为0 2 gd->mon_len = _bss_end_ofs; 3 gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16(uintptr_t)gd->fdt_blob); 4 gd->tlb_addr = addr; 5 ... 6 ...
③、把gd_t结构体搬移到地址为id的地方
id也是设置gd_t结构体的过程中得到的,所以一开始只能把gd_t结构体暂时放在原先设定的栈顶位置,等gd_t结构体设置完了再搬过去。
④、最后调用重定位函数relocate_code,三个参数从左到右依次赋值给寄存器R0,R1,R2
addr_sp:新设置的栈指针地址
id:gd_t结构体所在的地址
addr:需要把uboot复制到的地址
addr一开始指向64M SDRAM的最高地址0x34000000,从最高地址开始安排内存分布,为各个外设保留内存区域,最后addr指向的地址就是为uboot开辟的内存空间的起始地址;
而addr_sp是所有内存安排完了以后,指向的空余内存空间的最高地址(栈向下生长);
id参数是为了uboot重定位完成之后,传给board_init_r函数用的。