uboot - 启动流程分析【第二阶段】

**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有了身体上的接触。思路越来越清晰了。

一个字   “爽” !!

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值