weiqi7777

cortex-a8 uboot系列:第九章 uboot源码分析5-启动第二阶段

1
阅读(1901)

一、            start_armboot 4 解析

1. DATAFLASH初始化

clip_image002

CONFIG_HAS_DATAFLASH为串行接口的FLASH,如spi接口的FLASH或者IIC接口的FLASH。小容量的FLASH芯片。但是x210没有这个东西,这部分代码不执行。

2. 环境变量设置

clip_image004

环境变量的初始化,这里是对环境变量的重定位,将SD/MMC的环境变量读取到DDR中。

 

clip_image006

ENV_IS_EMBEDDED表示环境变量是内嵌到设备内部(也就是环境变量时内嵌到text段中)。该宏在程序中没有被定义。因此下面的代码是没有被执行的。

clip_image008

gd_t结构体中,有reloc_off变量,因为环境变量是内嵌在text段中的,所以这个变量指环境变量在相对于text段中首地址的偏移量。

clip_image010

env_ptr是第一个环境变量的地址。

clip_image012

 

clip_image014

这段代码是被执行的,为环境变量使用malloc分配CFG_ENV_SIZE大小(16K)的内存区域。分配了后,env_ptr就指向DDR中环境变量的首地址。

 

SD卡中有一些独立的扇区作为环境变量存储区域的。但是在烧录/部署系统时,只是烧录了uboot分区、kernel分区和rootfs分区,根本没有烧录env分区。当烧录完系统第一次启动时ENV分区是空的,本次uboot启动尝试去SD卡的ENV分区读取环境变量失败(读取回来后进行CRC校验时失败),uboot选择从uboot内部代码中设置的一套默认的环境变量用来使用(默认环境变量)。这套默认的环境变量在本次运行时会被读取到DDR中的环境变量中,然后被写入(可能是uboot自动写入,也可能是输入命令save写入)SD卡的ENV分区。下次再次启动时,uboot就会从SD卡的ENV分区读取环境变量到DDR中,读取就不会失败了。

clip_image016

Set_default_envcommon/env_common.c),就是设置默认的环境变量,将默认的环境变量的值拷贝到DDR中的环境变量中。

clip_image018

 

当第二次启动的时候,执行env_relocate_spec函数(common/env_movi.c

clip_image020

clip_image022

因为没有定义ENV_IS_EMBEDDED宏,所以这里什么都没有执行。这里是当环境变量是嵌入到text段中的话,从外部SD/MMC卡中读取环境变量的值,然后进行CRC判断。

virt_to_phys是虚拟地址转物理地址的函数。

movi_read_envcommon/env_movi.c)是从外部MMC设备读取环境变量到DDR中。实际上是调用movi_read函数(drivers/mmc/mmc.c)。

clip_image024

 

最后将全局变量gd的环境变量指向内存中的环境变量首地址。这样,以后通过gd->env_addr参数,就可以获知环境变量。

clip_image026

 

3. IP地址初始化

clip_image028

获取IP地址,使用getenv_IPaddr函数(net/net.c)从环境变量的ipaddr获取。

getenv函数(common/cmd_nvedit.c)就是获取环境变量的值(字符串形式),使用string_to_ip函数(net/net.c

clip_image030

IPaddr_t就是一个ulong类型的别名。

clip_image032

使用string_to_ip函数(net/net.c)将IP形式的字符串转化为ulong型。

clip_image034

如,对于192.168.0.1 转化之后的结果为

C0

A8

00

01

192的十六进制

168的十六进制

0的十六进制

1的十六进制

         所以addr = 0xc0a80001

         使用htonl函数将addr转化为网络字节序。

 

         IP地址由40-255之间的数字组成,因此一个IP地址在程序中最简单的存储方法就是一个unsigned int。但是这种对于我们不易读,使用点分十进制类型(192.168.0.1),两种方式可以相互转化。

         在计算机中,使用IPaddr_t类型来存储IP地址,以节省空间。而对于我们,使用点分十进制类型来表示。所以在存储的时候,要进行转化,将点分十进制类型转化为IPaddr_t类型保存,显示的时候要将IPaddr_t类型转化为点分十进制类型。

4. 物理网卡设置

         clip_image036

设置网卡物理地址。    

通过getenv_r函数获取ethaddr环境变量的值,保存在tmp数组中。然后通过处理,将变量的值写入到gd->bd->bi_enetaddr数组变量中。

没有使用第二块网卡,所以CONFIG_HAS_ETH1宏没有定义,对第二块网卡的物理地址就没有设置。

5. 设备初始化

clip_image038

设备的初始化。这里的设备指开发板上的硬件设备。这里的初始化设备都是驱动设备,这个函数是从驱动框架从衍生出了的。Uboot中很多设备的驱动是直接移植linux内核的(如网卡、SD卡),linux内核中的驱动都有相应的设备初始化函数。Linux内核在启动过程中就有一个devices_init函数,作用就是集中执行各种硬件驱动的init函数。

Uboot的这个函数其实就是从linux内核中移植过来,作用也是去执行所有的从linux内核中继承来的那些硬件驱动的初始化函数。

clip_image040

对设备创建列表,然后各自调用硬件的初始化。device_t是一个结构体,表征所有的设备。

clip_image042

clip_image044

jumptable跳转表,本身是一个函数指针数组,里面记录了很多函数的函数名。应该是实现一个函数指针到具体函数的映射关系,将来通过跳转表中的函数指针就可以执行具体的函数。这个其实就是用C语言实现面向对象编程。Linux内核中有很多这种技巧。        

这个函数就是对gd中的jt变量赋值,不过赋值了之后没有被使用。因此在uboot中没有对jumptable进行使用。

clip_image046

6. 控制台初始化

clip_image048

控制台的第二阶段初始化。console_init_r是第二阶段初始化,console_init_f是第一阶段初始化。之前分析第一阶段没有做什么实质性工作。

console_init_r函数(common/console.c中)

clip_image050

对输入输出设备进行扫描。

clip_image052

设置输入输出设备。

clip_image054

判断输入输出设备是否设置正确。正确的话打印信息。所以在uboot启动信息可以看到上述打印信息。

clip_image055

所以console_init_r函数,做的事就是console纯软件架构方面的初始化(就是给console相关的数据结构中填充相应的值),所以属于纯软件配置类型的初始化。

Ubootconsole实际上没有做有意义的转化,就是直接调用串口通信的函数。所以用不用console实际并没有什么分别。(linuxconsole可以提供缓冲机制等)。

7. 中断设置

clip_image057

设置中断的使能,其实就是设置CPSR寄存器的I位。但是在这里是没有设置的。

clip_image059

因为uboot中没有使用中断,所以CONFIG_USE_IRQ宏是无定义的,所以enable_interrupts函数(cpu/s5pc11x/interrupts.c)就是一个空函数。

8. 获取loadaddrbootfile环境变量

clip_image061

获取两个环境变量值,这两个环境变量都是和内核启动有关的,在启动linux内核是会参考这两个环境变量的值。

9. board_late_init

clip_image063

board_late_init函数(board/samsung/x210/x210.c)是开发板级别的一些晚期初始化。此时说明开发板级别的硬件软件初始化结束了。

clip_image065

因为不满足预编译条件,所以这个函数是空的。

clip_image067

没有定义CONFIG_NET_MULTI宏,所以puts不被编译。

10.   网卡初始化

clip_image069

网卡相关的初始化。eth_initialize函数(net/eth.c)。

这里不是soc的网卡控制器的初始化,而是外部网卡芯片本身的一些初始化。

对于x210DM9000网卡)来说,这个函数是空的。X210的网卡控制器初始化在board_init函数中,网卡芯片的初始化在驱动中。

clip_image071

宏编译条件都不成立,该函数直接返回0

 

clip_image073

phy复位

11.   IDE设备初始化

clip_image075

如果开发板有接IDE接口硬盘,对硬盘进行初始化。

12.   LCD初始化

clip_image077

声明x210_preboot_initboard/samsung/x210/x210.c)为外部函数,这里直接调用该函数。

clip_image079

而这个函数又是去调用了一个外部函数mpadfb_initdrivers/video/mpadfb.c

clip_image081

LCD进行初始化,并将logo显示在LCD上。

fb_init函数(drivers/video/mpadfb.c),对显存设置

lcd_port_init函数(drivers/video/mpadfb.c),对LCDport设置

lcd_reg_init函数(drivers/video/mpadfb.c),对LCD控制器的内部寄存器设置

display_logo函数(drivers/video/logo.c),将指定的log图片信息保存到显存中,从而LCD显示图片。

13.   自动升级

clip_image083

Uboot启动的最后阶段,设计了自动更新的功能。就是:可以将要升级的镜像放到SD卡的固定目录中,然后开机时,在uboot启动的最后阶段检查升级标志(是一个按键,按键中标志为“LEFT“的按键,这个按键如果按下则表示update mode,如启动时未按下则表示boot mode)。如果进入了update modeuboot会自动从SD卡中读取镜像文件然后烧录到iNand中;如果进入了boot modeuboot不执行update,直接启动正常运行

这种机制能够帮助我们快速烧录系统,常用于量产时用SD卡进行系统烧录部署。

14.   进入main_loop

clip_image085

进入到了uboot中的命令模式下了。等待命令输入,然后解析命令,最后执行命令。