**uboot/lib_arm/board.c
void start_armboot (void)
这个函数开始运行uboot启动的第二部分
(1)在内存中规划uboot的分配结构,堆区,栈区,gd,bd等。
分配过程图解请看我写的《uboot 运行过程中的存储分布图解》
(2)接下来进入一些列的必要的外设初始化
通过遍历函数指针数组里面的成员进行初始化各个函数,初始化成功,返回0,
只要有一个初始化失败,uboot就会进入挂起状态,进入死循环。
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
void hang (void)
{
puts ("### ERROR ### Please RESET the board ###\n");
for (;;);
}
函数指针数组里面的各个成员函数分析如下
【1】int cpu_init (void)
如果使用了IRQ的话,里面做的是设置IRQ,FIQ的栈。否则什么也没做。
【2】int board_init(void)
*初始化自己开发板对应的网卡(主要是GPIO等,驱动是通用的。)
dm9000_pre_init();
*填充bd成员的机器码和传递给内核参数在内存中存放的位置
gd->bd->bi_arch_number = MACH_TYPE;// 机器码(必须和内核的机器码一致)
gd->bd->bi_boot_params = (PHYS_SDRAM_1+0x100);// 参数位置
【3】int interrupt_init(void)
*初始化定时器。为bootdelay的倒计时打下基础。
【4】int env_init(void)
*环境变量的初始化,因为SOC的启动方式有多种,所以环境变量的存储方式也就
有多种,所以这么有多个 env_init 函数,比如我们是SD卡启动的,类属于iNand
所以选择env_movi.c里面的int env_init(void)函数。当前只是在内存中初始化一些
环境变量必要的环境,实际上还没有从存储介质重定位到DDR中。
【5】int init_baudrate (void)
初始化串口的波特率填入gd,bd里面对应的波特率成员
gd->bd->bi_baudrate = gd->baudrate = ···
【6】int serial_init(void)
其实没做什么实际的东西,我们在第一阶段已经初始化串口相关的硬件
【7】int console_init_f (void)
控制台初始化,填充gd里面的have_console :gd->have_console = 1;。
【8】int display_banner (void)
显示uboot的信息:
printf ("\n\n%s\n\n", version_string);
const char version_string[] =
U_BOOT_VERSION" (" __DATE__ " - " __TIME__ ")"CONFIG_IDENT_STRING;
【9】int print_cpuinfo(void)
主要是自动获取开发板配置的时钟系统的情况并打印到串口:
CPU: S5PV210@1000MHz(OK)
APLL = 1000MHz, HclkMsys = 200MHz, PclkMsys = 100MHz
MPLL = 667MHz, EPLL = 96MHz
HclkDsys = 166MHz, PclkDsys = 83MHz
HclkPsys = 133MHz, PclkPsys = 66MHz
SCLKA2M = 200MHz
Serial = CLKUART
【10】int checkboard(void)
主要是打印开发板的名字信息(可以自己再次添加你想打印的)
printf("\nBoard: KayChan210\n");
【11】int init_func_i2c (void)
初始化IIC并打印
【12】int dram_init(void)
DDR的软件初始化,主要是填充bd里面和DDR相关的结构体成员
(几片DDR,起始地址,容量大小)
gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
【13】int display_dram_config (void)
主要是打印DDR的总大小:
puts("DRAM: ");
print_size(size, "\n");
也可以在uboot命令行里面使用命令bdinfo来获取DRAM的详细配置信息
(3)初始化堆管理器 mem_malloc_init
uboot中自己维护了一段堆内存,肯定自己就有一套代码来管理这个堆内存。
有了这些东西uboot中你也可以malloc、free这套机制来申请内存和释放内存
我们在DDR内存中给堆预留了(CFG_MALLOC_LEN)的内存。
(4)初始化对应的FLASH(自己开发板上有的,对应的。)
nor,nand,emmc/sd等等···自己写对应或者调用现成的对应于自己FLASH的
初始化函数。
(5)void env_relocate (void)
如果是第一次运行uboot,显然SD卡里面并没有环境变量分区,所以此次的启动,
CPU去SD卡对应的分区读取环境变量,读取不到,所以CPU会使用默认的环境变
量也就是我们在x210_sd.h中配置的,在命令行执行saveenv/save时会将环境变量
写入SD卡,下次启动的时候SD卡里面就有环境变量了。下次则会从SD卡读取,而
不是使用默认值。将SD卡里面的环境变量重定位到DDR。
gd->env_addr:环境变量在SD卡处的起始位置
gd->env_addr:环境变量在DDR处的起始位置
(6)填充bd中IP地址和MAC地址成员
/* IP Address */
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
/* MAC Address */
gd->bd->bi_enetaddr;
(7)int devices_init (void)
/* get the devices list going. */
继承内核中的一些设备初始化 好像没什么作用·····
(8)void jumptable_init (void)
实就是在用C语言实现面向对象编程,建立一个函数跳转表。
(9)console_init_r ();/* fully init console as a device */
控制台的第二次初始化
(10)void enable_interrupts (void)
中断初始化,配置CPSR罢了。如果没使用IRQ,FIQ,则该函数为空
(11)loadaddr、bootfile两个环境变量
/* 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内核时会参考这两个环境变量
的值。
(12)int eth_initialize(bd_t *bis)
这里不是SoC与网卡芯片连接时SoC这边的初始化,而是网卡芯片本身的一些初始化
对于X210(DM9000)来说,这个函数是空的。X210的网卡初始化在board_init函数
中,网卡芯片的初始化在驱动中。
(13)x210_preboot_init(LCD和logo显示)
开发板在启动起来之前的一些初始化,以及LCD屏幕上的logo显示。(自己添加的)
(14)check menukey to update from sd(是否进入更新状态)
uboot启动的最后阶段设计了一个自动更新的功能。就是:我们可以将要升级的
镜像放到SD卡的固定目录中,然后开机时在uboot启动的最后阶段检查升级标志
(是一个按键。按键中标志为"LEFT"的那个按键,这个按键如果按下则表示update
mode,如果启动时未按下则表示boot mode)。如果进入update mode则uboot会
自动从SD卡中读取镜像文件然后烧录到iNand中;如果进入boot mode则uboot
不执行update,直接启动正常运行。
这种机制能够帮助我们快速烧录系统,常用于量产时用SD卡进行系统烧录部署。
(14)main_loop(uboot的归宿)
/* main_loop() can return to retry autoboot, if so just run it again. */
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_initializeinand/SD卡的SoC控制器和卡的初始化
env_relocate 环境变量重定位
gd->bd->bi_ip_addrgd数据结构赋值
gd->bd->bi_enetaddrgd数据结构赋值
devices_init 空的
jumptable_init不用关注的
console_init_r真正的控制台初始化
enable_interrupts空的
loadaddr、bootfile 环境变量读出初始化全局变量
board_late_init空的
eth_initialize空的
x210_preboot_initLCD初始化和显示logo
check_menu_update_from_sd检查自动更新
main_loop 主循环
==========================================================
感谢 朱有鹏老师,总算对一直畏惧的uboot有了身体上的接触。思路越来越清晰了。
一个字 “爽” !!