uboot的第一阶段结束于start_armboot,第二阶段的uboot代码主要负责soc外部硬件(inand、网卡、......)、uboot本身构建(uboot指令、环境变量、......)最后进入命令行,等待命令然后倒数,等待bootcmd,进入内核(uboot结束)。
倒数期间通过回车打断进入如下代码,通过循环不去进入bootcmd。
for(;;)
{
main_loop();
}
typedef int (init_fnc_t) (void);这是一个函数类型。对于一个int(void)类型的函数类型取别名为init_fnc_t,可用这个别名进行创建这个类型的函数对象。
init_fnc_t **init_fnc_ptr; init_fnc_ptr是一个二重指针,其无非是能指向两种东西。
1.指向一重指针的指针。2.指向指针数组。所以可以用于指向一个函数指针数组。
DECLARE_GLOBAL_DATA_PTR宏
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm("r8")
这里定义了一个全局变量名为gd,类型为指针,volatile表示可变的,register表示存放在寄存器中,asm("r8")在gcc语法中,存放在r8寄存器里,gd_t一个结构体类型的别名。
综合分析一下,指向gd_t类型的指针,是一个全局的结构体,这个结构体里有uboot所有常用的全局变量,通过将其存放在寄存器的方式提高效率。gd_t中封装了另一个结构体,结构体里封装了板卡信息和一堆常用变量。
控制台基于串口实现,但比串口高级许多。
global_data的主要内容:
global_data{
unsigned long flags; //标志位
unsigned long baudrate; //比特率
unsigned long have_console; //控制台(标准输入/输出控制,能printf与scantf)(bool)
unsigned long reloc_off; //重定位偏移量
unsigned long env_addr; //环境变量地址(八成是结构体)
unsigned long env_valid; //内存中环境是否准备完成(DDR)(bool)
unsigned long fd_base; //缓存地址
void xxit; //跳转表
bd_t *bt; //板卡信息
}
DECLARE_GLOBAL_DATA_PTR只是一个指针,gd并没有被分配内存,在裸机下没有malloc分配内存(暂无) ,不给gd分内存gd就是野指针。
gd与bd要内存,但内存没有被管理,uboot也要使用大片的内存,使用要有整体的内存规划。
内存排布:
gd_base=CFG_UBOOT_BASE+CFG_UBOOT_SIZE-\
CFC_MALLOC_LEN-CFG_STACK_SIZE-sizeof(gd_t)
其中:GFG_UBOOT_BASE 为uboot区域,长为uboot大小。
CFG_UBOOT_SIZE 为uboot大小 2M(2*1024*1024)
CFC_MALLOC_LEN 为malloc(堆)长度。CFG_ENV_SIZE(大小为0x4000=16k)+896(也就是896k)*1024。
CFG_STACK_SIZE 堆区,长度512*1024=512k。
CFG_GBL_DATA_SIZE 全局变量128字节。
sizeof(gd_t)36字节(4*9)。
sizeof(bd_t)44到50字节。
gd=(gd_t*)gd_base 强换c,指针指向gd_base。
memset((void*)gd,0,sizeof(gd_t));内存清零。
gd->bd=(bd_t*)((char*)gd-sizeof(bd_t)) gd,bd指向bd_base。
内存向上生长,栈分满增满减。
__asm__volatile__("":::"memory");对内存进行了修改,防止gcc过度优化。这叫内存间隔,防止优化后造成错误。__asm__volatile__属于内嵌汇编。
这一章先写到这,下一章将对uboot的板级初始化进行说明,敬请期待。