一:uboot启动的第一阶段start.S(路径uboot/cpu/s5pc11x/start.S)
1:#include <config.h> //头文件包含,config.h文件源码中不存
在,配置后自动生成;路径/include/linux/config.h;
2:#include <version.h>//头文件包含,version.h文件源码中不存
在,配置后自动生成;路径/include/version.h;
3:#include <asm/proc/domain.h> //头文件包含,asm/proc是链接
符号,实际指向include/asm-arm/proc-armv/domain.h;
4:填充uboot的前16字节,为后面的CRC校验占位;
5:构建异常向量表,但uboot中并没有设置异常处理,发生异常时重
启即可;
6:balignl 16,0xdeadbeef 内存对齐,如果不对齐则用0xdeadbeef进行填充;
7:复位函数,通过msr命令来操作CP15协处理器的后8位,设置为SVC模式;
8:l2cache设置相关;关闭MMU;
9:读取OMpin引脚的电平高低来判断启动方式(SD卡 nand等);
10:第一次设置栈,因为这个时候DDR还没有被初始化,所以这次设置栈是在SDRAM中;
11:lowlevel_init函数;
(1)check reset status :检查CPU复位状态(热上电,睡眠模式唤醒不需要初始化DDR;冷上电需要初始化DDR);
(2) IO Retention release :复位后IO口的保存与恢复;
(3)Disable Watchdog :关看门狗;
(4)PS_HOLD pin(GPH0_0) set to high :设置开发板供电锁存
(5)判断当前代码执行的位置是在SDRAM还是DDR中,主要思路是通过
bic将当前PC位置和_TEXT_BASE(uboot在DDR的起始地址)的高8位和
低12位清零,比较剩下的中间12位是否相等,如果相等,则在当前代
码则在DDR中运行,如果不相等,则当前代码在SDRAM中运行;在DDR中
运行则不需要初始化时钟和DDR,在SDRAM中运行则需要初始化时钟和
DDR;
(6)串口初始化,并打印出'OK',OK是一个中间的检查标志,如果没
有看到OK则代表是lowlevel_init函数之前出了问题,如果打印了OK则
代表是lowlevel_init后面出了问题;
12:set PS_HOLD signal to high :再次设置开发板供电锁存
13:get ready to call C functions:第二次设置栈,在DDR中,位
置是0x33e00000;
14:判断当前代码运行位置是在DDR还是SDRAM,如果在SDRAM则完成重
定位,将BL2(整个uboot)复制到链接地址33e00000处
15:开启MMU,进行虚拟地址映射;
16:第三次设置栈,目的是为了使栈更加安全,内存使用合理,地址
是0x33e00000+2M-1K;
17:clear_bss: 清bss段;
18:ldr pc, _start_armboot 短跳转到start_armboot函数,进行
uboot启动的第二阶段;二:uboot启动的第二阶段start_armboot()函数(路径 uboot/lib_arm/Board.c)1:gd bd地址的设置:gd在DDR中的位置33e00000+2M-912k-512k,bd
在gd下面,紧挨着;gd是一个结构体指针,放在寄存器r8中,gd所指
向的结构体中存放的都是一些全局变量gd->bd也是一个结构体里面存
放着bi_baudrate 波特率(开发板的波特率);
bi_ip_addr IP地址; bi_enetaddr MAC地址; bi_arch_number
机器码;
bi_boot_params 将来给内核传参的参数的存放地址0x30000010
struct {ulong start;ulong size; }
bi_dram[CONFIG_NR_DRAM_BANKS];DDR的起始地址和大小;2:通过一个for循环来遍历init_sequence函数指针数组中的指针,最
后通过判断最后一个函数是不是NULL来跳出这个循环
(1)cpu_init:一个空函数,返回0
(2)reloc_init
(3)board_init:初始化网卡(DM9000),获取机器码
bi_arch_number 和分配bi_boot_params的内存地址;
(4)interrupt_init:初始化定时器4,设置10ms定时,用于
bootdelay ;
(5)env_init:环境变量的设置;
(6)init_baudrate:初始化波特率(控制台的波特率,数值上和开
发板的波特率相等);
(7)serial_init:初始化串口,串口在第一阶段start.S 中就已经
初始化了,所以这个函数什么也没做;
(8)console_init_f:控制台初始化的第一阶段,在uboot中没有用
到控制台,而是直接调用串口发送函数puts();
(9)display_banner:打印uboot的版本信息,也就是我们在主
Makefile设置的uboot的版本号;
(10)print_cpuinfo:初始化时钟;
(11)checkboard:打印开发板信息 ,Board: X210;
(12)init_func_i2c:这里没使用i2c,所以这个函数实际没起作
用;
(13)dram_init():gd-bd.bi_dram结构体内各个变量的赋值,也就
是每片DDR的起始地址和大小;
(14)display_dram_config:打印DDR的配置信息;3:mem_malloc_init (CFG_UBOOT_BASE + CFG_UBOOT_SIZE -
CFG_MALLOC_LEN - CFG_STACK_SIZE); 分配堆空间,
33e00000+2M-896K-512K4:#if defined(CONFIG_X210):不同开发板独有的初始化,我们是
x210,所以执行这个条件编译。这里面主要是初始化MMC控制器,并打
印SD/MMC 的大小; 5:env_relocate();环境变量的重定位,将SD卡中的环境变量读取到
DDR中,需要注意的是第一次启动uboot的时候SD卡时没有env分区,而
是使用uboot内部硬编码的一套环境变量,然后写到SD卡中。6:gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr"); 获取开发板
的IP地址,这个IP地址在x210_sd.h中有定义,并通过gd->bd来维护
(下面是MAC地址,同IP一样) 7:devices_init();设备初始化;8:jumptable_init();跳转表初始化,因为这里的跳转表只被赋值,
而没有被引用,所以并无实际作用;9:console_init_r ();控制台初始化的第二阶段,控制台初始化的主
要部分都在第二阶段完成;10:enable_interrupts();中断初始化,这里是CPSR寄存器中总中断
标志位的使能,但是由于uboot中并没有使用到中断所以这个函数并没
实际作用; 11:loadaddr;bootfile;这两个环境变量都是内核启动相关的环境变
量;12:board_late_init (); 开发板级别的晚期初始化,也是最后的初
始化,实际是一个空函数;13:x210_preboot_init();x210开发板在启动起来之前的初始化,主
要是led的初始化和logo的显示;14:check menukey to update from sd :uboot提供了一种方便的刷
机方式,当我们需要升级系统时,只需要将系统烧录到SD卡的相应扇
区,在启动时按下LEFT按键,便可实现简便地升级系统;
15:for (;;) { main_loop ();} //死循环 输入命令 解析命令
输入命令 解析命令.... ; uboot启动第二阶段结束