从makefile和mkconfig我们知道了,第一个运行的文件时 cpu/arm920t/start.S
一、uboot源代码第一阶段
所以我们从start.S着手分析源代码。
uboot第一阶段是硬件相关的初始化:
- 设置cpu为svc模式
- 关闭看门狗
- 屏蔽中断
- 初始化SDRAM:
blne cpu_init_crit
cpu的初始化 点进这个函数里,就能看到SDRAM的初始化:
bl lowlevel_init /* go setup pll,mux,memory */
-
设置栈:
-
设置时钟
-
重定位:
bl CopyCode2Ram
- 清除bss段:
clear_bss:
ldr r0, _bss_start /* find start of bss segment */
ldr r1, _bss_end /* stop here */
mov r2, #0x00000000 /* clear */
- 调用_start_armboot函数:
ldr pc, _start_armboot
_start_armboot: .word start_armboot
二、uboot源代码第二阶段
第二阶段的作用:
烧写FLash
网卡
usb
串口
启动内核
uboot的最终目的是启动内核:
1、从Flash读出内核
2、启动内核
我们抱着这个了解如何启动内核的目的,去分析第二阶段的源码。(注意这个思想,可以用在分析其他代码上)
第二阶段从start_armboot 这个函数开始。
书有画,内存分布,可以大概了解下:
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
可以看下init_sequence
,进行一系列初始化:
init_fnc_t *init_sequence[] = {
cpu_init, /* basic cpu dependent setup */
board_init, /* basic board dependent setup */
interrupt_init, /* set up exceptions */
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 */
#if defined(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo, /* display cpu info (and speed) */
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
checkboard, /* display board info */
#endif
dram_init, /* configure available RAM banks */
display_dram_config,
NULL,
};
稍微看下就可以了,因为我们想要研究的最终目的是怎么启动内核的。
gd = (gd_t *)CFG_GBL_DATA_OFFSET;
memset((void *)gd, 0, CFG_GBL_DATA_SIZE);
if (isS3C2410)
{
/* arch number of SMDK2410-Board */
gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;
}
else
{
/* arch number of SMDK2440-Board */
gd->bd->bi_arch_number = MACH_TYPE_S3C2440;
}
/* adress of boot parameters */
gd->bd->bi_boot_params = 0x30000100;
在CFG_GBL_DATA_SIZE这块内存里,设置arch_number(架构板子名称)、boot_params(启动参数)。
既然能从flash上读出内核,说明有读写Flash的能力:
#ifndef CFG_NO_FLASH
/* configure available FLASH banks */
size = flash_init ();
display_flash_config (size);
#endif /* CFG_NO_FLASH */
进入flash_init ();函数:
malloc区的分配,就是图中192K的分区。
Nand初始化。
环境变量的初始化:
/* initialize environment */
env_relocate ();
所以环境变量从哪来的?
修改后的环境变量在Flash上保存的,从Flash上取
Flash上没有,那就设置为默认环境变量
网卡、设备的初始化、usb
死循环,我们体验uboot的时候可以知道,uboot启动后,等待我们输入命令:
for (;;) {
main_loop ();
}
#endif /* CONFIG_BOOTCOUNT_LIMIT */
s = getenv ("bootcmd");
run_command (s, 0);
那么bootcmd是什么东西呢?
我们可以查看下环境变量里,bootcmd是怎么设置的:
从Flash上读出命令nand read.jffs 读到0x30007F00,从kernel分区上读
怎么启动?
bootm 0x30007F00
这些命令是什么意思呢?等下再分析。
菜单界面:
run_command("menu", 0);
死循环,等待命令:
for (;;) {
根据以上代码的分析,我们总结下,uboot主要是怎么在做什么:
(1)启动内核
s = getenv(“bootcmd”);
run_command(s…)
(2)uboot界面
readline(读入串口的数据)
run_command()
所以uboot的核心就是命令,下一节我们就要分析下这些命令是什么含义。