在start.s代码的414行跳转到start_armboot函数
start_armboot函数简介
一个很长的函数
(1)这个函数在uboot/lib_arm/board.c的第444行到908行结束
(2)450行还不是全部,里面还调用了别的函数
(3)这个函数整体构成了uboot启动的第二阶段
一个函数组成uboot的第二阶段
(1)uboot的第一阶段主要就是初始化了Soc内部的一些部件(譬如看门狗,系统时钟),然后初始化DDR并且完成重定位。
(2)宏观来说,uboot的第二阶段就是要初始化剩下的还没被初始化的硬件。主要是Soc外部硬件(譬如iNand,忘啦芯片)。最终初始化完必要的东西后进入uboot的命令行尊卑接收命令
uboot第二阶段完结何处?
(1)uboot启动后自动运行打印出来的信息(这些信息就是uboot在第一和第二阶段不断进行初始化时,打印出来的信息)。然后uboot进入了倒数bootdelay,然后执行bootcmd对应的启动命令
(2)如果用户没有干涉则会执行bootcmd进入自动启动内核流程(uboot就死掉了);此时用户可以按下回车键大端uboot的自动启动进入uboot的命令行下。然后uboot就一直工作在命令行下。
(3)uboot的命令行就是一个死循环,循环体内不断重复:接收命令,解析命令,执行命令
start_armboot函数源码解析
在开头发现的init_fnc_t
init_fnc_t
(1)typedef int (init_fnc_t) (void);这是一个函数类型
(2)init_fnc_ptr,这是一二重指针。二重指针的作用(其中一个指向一个一重指针,或者一个是指向一个数组)
gd_t
(1)在start_armboot的465行,定义了一个gd_t,查找gd_t,发现是在DECLARE_GLOBAL_DATA_PTR宏中,
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")
这个宏定义了一个全局变量,名字叫gd,这个全局变量是一个指针类型,占4字节。用volatile 修饰,代表是可变的,register 修饰,代表是用寄存器去执行,速度更快。asm (“r8”)是gcc支持的语法,意思是要把gd放到寄存器r8中。
(2)综合分析,DECLARE_GLOBAL_DATA_PTR就是定义了一个要放在寄存器r8中的全局变量,名字叫gd,类型是一个指向gd_s类型变量的指针。
(3)为什么要定义为register?因为这个全局变量gd(global data的简称)是uboot中很重要的一个全局变量(准确的说这个全局变量是一个结构体,里面有很多内容,这些内容加起来构成的结构体即使uboot中常用的所有的全局变量),这个gd在程序中经常被访问,因此放在register中提升效率。因此纯粹是运行效率方面考虑,和功能要求无关。
(4)在global data这个结构体中,
bd_t *bd; //bd_t,这个又定义了变量,这里面存的是我们开发板的硬件信息unsigned long flags; //存的是我们的一些标志位的unsigned long baudrate; //存的是我们的控制台波特率的unsigned long have_console; /* serial_init() was called */unsigned long reloc_off; /* Relocation Offset */unsigned long env_addr; /* Address of Environment struct */unsigned long env_valid; /* Checksum of Environment valid? */unsigned long fb_base; /* base address of frame buffer */
(5)下面是在bd这个结构体中的代码,定义在inlcude/asm-arm/global_data.h中
int bi_baudrate; /* 我们开发板的波特率 */unsigned long bi_ip_addr; /* 板子的IP地址 */unsigned char bi_enetaddr[6]; /* Ethernet adress */struct environment_s *bi_env; //环境变量的指针ulong bi_arch_number; /* 板子的机器码 */ulong bi_boot_params; /* 启动参数的地址 */struct /* RAM configuration */{
ulong start;ulong size;} bi_dram[CONFIG_NR_DRAM_BANKS];//板子的地址从什么地方开始,有多大,这里告诉的
总结:gd中定义了很多的全局变量,整个uboot使用的;其中有一个bd_t类型的指针,执行一个bd_t类型的变量,这个bd是开发板的板级信息的结构体,里面有不少硬件相关的参数,譬如波特率,IP地址,机器码,DDR内存分布。
从469行开始对gd分配内存
内存使用排布
为什么要分配内存
(1)DECLARE_GLOBAL_DATA_PTR 只是定义了一个指针,也就是说gd里的这些全局变量并没有分配内存,我们在使用gd之前要给他分配内存,否则gd也只是一个野指针。
(2)gd和bd需要内存,内存当前没有被人管理(因为没有操作系统同一管理内存),大片的DDR内存散放着可以随意使用(只要使用内存地址直接去访问内存即可)。但是因为uboot中后续很多操作还需要大片的连着内存,采用紧凑排布的原则
内存排布
UBOOT区 | CFG_UBOOT_BASE-XX(长度为uboot的实际长度) |
---|---|
堆区 | 长度为CFG_MALLOC_LEN ,实际为912kb |
栈区 | 长度为CFG_STACK_SIZE ,实际为512KB |
gd | 长度为sizeof(gd_t),实际为36字节 |
bd | 长度为sizeof(bd-t),实际为44字节左右 |
内存间隔 | 是为了避免gcc的优化,导致程序错误 |
gd_base = CFG_UBOOT_BASE + CFG_UBOOT_SIZE - CFG_MALLOC_LEN - CFG_STACK_SIZE - sizeof(gd_t);//计算我们的基地址的值
#ifdef CONFIG_USE_IRQgd_base -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ);
#