注:本文是学习朱老师课程整理的笔记,基于uboot-1.3.4和s5pc11x分析。
前面的分析见uboot之start_armboot分析3
console_init_f是控制台的第一阶段初始化,console_init_r是第二阶段初始化。实际上第一阶段初始化并没有实质性工作,第二阶段初始化才进行了实质性工作。
console_init_r就是console的纯软件架构方面的初始化(说白了就是去给console相关的数据结构中填充相应的值),所以属于纯软件配置类型的初始化。
uboot的console实际上并没有干有意义的转化,它就是直接调用的串口通信的函数。所以用不用console实际并没有什么分别。在uboot的启动时会在串口上显示In,Out,Err等标准输入,标准输出,标准错误信息。
/* enable exceptions */
enable_interrupts ();
……
#ifdef CONFIG_USE_IRQ
/* enable IRQ interrupts */
void enable_interrupts (void)
{
unsigned long temp;
__asm__ __volatile__("mrs %0, cpsr\n"
"bic %0, %0, #0x80\n"
"msr cpsr_c, %0"
: "=r" (temp)
:
: "memory");
}
……
#else
void enable_interrupts (void)
{
return;
}
#endif
看名字应该是中断初始化代码。这里指的是CPSR中总中断标志位的使能。
因为我们uboot中没有使用中断,因此没有定义CONFIG_USE_IRQ宏,因此我们这里这个函数是个空壳子。
uboot中经常出现一种情况就是根据一个宏是否定义了来条件编译决定是否调用一个函数内部的代码。uboot中有2种解决方案来处理这种情况:方案一:在调用函数处使用条件编译,然后函数体实际完全提供代码。方案二:在调用函数处直接调用,然后在函数体处提供2个函数体,一个是有实体的一个是空壳子,用宏定义条件编译来决定实际编译时编译哪个函数进去。
/* Initialize from environment */
if ((s = getenv ("loadaddr")) != NULL) {
load_addr = simple_strtoul (s, NULL, 16);
}
#if defined(CONFIG_CMD_NET)
if ((s = getenv ("bootfile")) != NULL) {
copy_filename (BootFile, s, sizeof (BootFile));
}
这两个环境变量都是内核启动有关的,在启动linux内核时会参考这两个环境变量的值。
int board_late_init (void)
{
return 0;
}
看名字这个函数就是开发板级别的一些初始化里比较晚的了,就是晚期初始化。所以晚期就是前面该初始化的都初始化过了,剩下的一些必须放在后面初始化的就在这里了。侧面说明了开发板级别的硬件软件初始化告一段落了。
对于X210来说,这个函数是空的。
看名字应该是网卡相关的初始化。这里不是SoC与网卡芯片连接时SoC这边的初始化,而是网卡芯片本身的一些初始化。
对于X210(DM9000)来说,这个函数是空的。X210的网卡初始化在board_init函数中,网卡芯片的初始化在驱动中。
x210开发板在启动起来之前的一些初始化,以及LCD屏幕上的logo显示。
/* check menukey to update from sd */
if(check_menu_update_from_sd()==0)
{
puts("[LEFT DOWN] update mode\n");
run_comman("fdisk -c -0", 0);
update_all();
}
else
puts("[LEFT UP] boot mode\n");
uboot启动的最后阶段设计了一个自动更新的功能。就是:我们可以将要升级的镜像放到SD卡的固定目录中,然后开机时在uboot启动的最后阶段检查升级标志(是一个按键。按键中标志为”LEFT”的那个按键,这个按键如果按下则表示update mode,如果启动时未按下则表示boot mode)。如果进入update mode则uboot会自动从SD卡中读取镜像文件然后烧录到iNand中;如果进入boot mode则uboot不执行update,直接启动正常运行。
这种机制能够帮助我们快速烧录系统,常用于量产时用SD卡进行系统烧录部署。
for (;;) {
main_loop ();
}
循环读取串口数据执行相应命令。
第二阶段主要是对开发板级别的硬件、软件数据结构进行初始化。
启动流程回顾、重点函数标出:
init_sequence
cpu_init /*空的*/
board_init /*网卡、机器码、内存传参地址*/
dm9000_pre_init /*网卡*/
gd->bd->bi_arch_number /*机器码*/
gd->bd->bi_boot_params /*内存传参地址*/
interrupt_init /*定时器*/
env_init
init_baudrate /*gd数据结构中波特率*/
serial_init /*空的*/
console_init_f /*空的*/
display_banner /*打印启动信息*/
print_cpuinfo /*打印CPU时钟设置信息*/
checkboard /*检验开发板名字*/
dram_init /*gd数据结构中DDR信息*/
display_dram_config /*打印DDR配置信息表*/
mem_malloc_init /*初始化uboot自己维护的堆管理器的内存*/
mmc_initialize /*inand/SD卡的SoC控制器和卡的初始化*/
env_relocate /*环境变量重定位*/
gd->bd->bi_ip_addr /*gd数据结构赋值*/
gd->bd->bi_enetaddr /*gd数据结构赋值*/
devices_init /*空的*/
jumptable_init /*不用关注的*/
console_init_r /*真正的控制台初始化*/
enable_interrupts /*空的*/
loadaddr、bootfile /*环境变量读出初始化全局变量*/
board_late_init /*空的*/
eth_initialize /*空的*/
x210_preboot_init /*LCD初始化和显示logo*/
check_menu_update_from_sd /*检查自动更新*/
main_loop /*主循环*/
第一阶段为汇编阶段、第二阶段为C阶段
第一阶段在SRAM中、第二阶段在DRAM中
第一阶段注重SoC内部、第二阶段注重SoC外部Board内部