weiqi7777

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

0
阅读(1803)

第一阶段结束后,调用了start_armboot函数。开始第二阶段。

start_armboot函数在lib_arm/board.c文件里。

一、            uboot第二阶段

uboot第一阶段主要就是初始化了soc内部的部件(如看门狗,时钟),然后初始化DDR并且完成重定位,建立MMU映射表,启动MMU

Uboot第二阶段就是要初始化剩下的还没有被初始化的硬件。主要是soc外部的硬件(如iNand,网卡芯片……),uboot本身的一些东西(uboot命令,环境变量……)。然后最终初始化完必要的东西后进入uboot的命令行准备接收命令。

1.         uboot的完结

uboot启动后自动运行打印很多信息(这些信息就是uboot在第一和第二阶段不断进行初始化时,打印出来的信息)。然后uboot进入了倒数bootdelay秒然后执行bootcmd对应的启动命令。

如果用户没有干涉,则会执行bootcmd进入自动启动内核流程(uboot就死掉了)。此时用户可以按下空格键打断uboot的自启动进入uboot的命令行下。然后uboot就一直工作在命令行下。

Uboot的命令行就是一个死循环,循环体内不断重复:接收命令、解析命令、执行命令。这就是uboot最终的归宿。

clip_image002

start_armboot函数最后就是一个无限for循环,执行main_loop函数。这个函数就是读取命令,然后执行命令。

二、            start_armboot解析1

init_fnc_t定义

clip_image004

这是一个函数类型,

typedef  int (*init_fnc_t) (void)  这个是函数指针。参数是void,函数返回值是int型。

 

clip_image006

init_fnq_ptr 是一个二重函数指针。

二重指针作用两个:一个是用来指向一重指针,另一个是指向指针数组。

因此这里的init_fnq_ptr可以用来指向函数指针数组。

 

clip_image008

该宏在include\asm-asm目录下的global_data.h文件中。

clip_image010

这个宏定义了一个全局变量,名字叫gd,这个全局变量是一个指针类型,占用4个字节,用volatile修饰表示可变,用register修饰表示这个变量要尽量放到寄存器中,后面的asm(“r8”),是gcc支持的一种语法,意思是要把gd放到寄存器r8中。

综合分析,DECLARE_GLOBAL_DATA_PTR就是定义了一个要放在寄存器r8中的全局变量,名字叫gd,类型是一个指向gd_t类型变量的指针。

为什么要把这个变量定义为register?因为这个全局变量gdglobal data的简称)是uboot中很重要的一个全局变量(这个全局变量是一个结构体,里面有很多内容,这些内容加起来构成的结构体就是uboot中常用的所有的全局变量),这个gd在程序中经常被访问,因此放在register中提升效率。因此纯粹是运行效率方面的考虑,和功能要求无关,并不是必须。

 

gd_t定义在include/asm-armglobal_data.h中。该结构体将uboot会用到的全局变量封装到一起。

clip_image012

bd_t:存放开发板的一些信息。

flags 存放标志位

baudrate 控制台的波特率

have_console:  bool类型,表示控制台是否使用。

reloc_off:  重定位的偏移量

env_addr:  环境变量的地址

env_valid:  bool类型,表明内存中的环境变量是否有效

fb_base:   fram buffer的基地址

vfd_type:  

jt   跳转表

 

对于bd_t结构体,保存的是板子的信息。

clip_image014

bi_baudrate: 开发板的波特率,和控制台的波特率一样。

bi_ip_add  开发板的ip地址

bi_enetaddr 开发板的物理地址

bi_env                     环境变量的指针

bi_arch_number   板子的机器码

bi_boot_params   启动参数(将来传给linux的参数)地址

bi_dram  外部dram信息结构体,内部两个变量,一个起始地址,一个大小。程序通过这个参数可以知道开发板外部接的DRAM信息

bi_enet1addr       第二个网卡的物理地址(一般都不用)

 

总之,gd_t中定义了很多全局变量,都是整个uboot使用的,其中有一个bd_t类型的结构体,指向一个bd_t类型的变量,这个bd是开发板的板级信息的结构体,里面有不少硬件相关的参数,如波特率、IP地址、机器码、DDR内存分布。

 

内存使用排布:

DECLARE_GLOBAL_DATA_PTR只是定义了一个指针,也就是说gd里的全局变量并没有分配内存,所以在使用gd之前要给他分配内存,否则gd也只是个野指针而已。

gdbd需要内存,内存当前没有被管理(因为没有操作系统统一管理内存),大片的DDR内存可以随意使用(只要使用内存地址直接访问内存即可)。但是也不能太随意使用,要考虑uboot其他地方用到的内存。

因此在uboot中需要有一个整体规划。

 

内存排布:

1. uboot

CFG_UBOOT_BASE  +   XXX,长度为uboot的实际长度

clip_image016

Uboot中定义CFG_UBOOT_BASE0x33e0_0000

CFG_UBOOT_SIZE 2M

2. 堆区

CFG_MALLOC_LEN为堆区的长度,计算可知为912K,大致1M左右。

clip_image018

CFG_ENV_SIZE为环境变量的大小。为16K

clip_image020

所以malloc长度为 16 + 896 = 912K

 

3. 栈区

CFG_STACK_SIZE大小为512K

clip_image022

4. gd

长度为sizeof(gd_t),为36个字节。

5. bd

长度为sizeof(bd_t),实际大小大占44个字节。

 

 

根据gd_base的计算:

clip_image024

所以gd_base = 0x33e00000 + 0x200000(2M) – 912k – 512k – 36(gd_t结构体的大小为36字节)

clip_image026

这样,就知道了gd指针的地址。也就是全局变量存放的首地址。

所以此时内存分布为:

clip_image028

 

 

clip_image030

gd区域全部给初始化为0。同时给gd中的bd确定内存地址。bd的地址就是gd的地址向下偏移sizeof(bd_t)大小.

clip_image032

 

 

clip_image034

为了防止高版本GCC的优化对内存造成的错误,要加这一句代码。

clip_image036