版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012351051/article/details/87991517
start_armboot函数是u-boot执行的第一个C函数,在/lib_arm/board.c文件中,很明显,既然是第一个C函数,必然要做很多初始化的工作,自然其中肯定是要包含条件编译的,这一点还是要根据要移值的具体板子的宏定义来实现,我们根据
/include/configs/mx28_evk.h),分析如下:
void start_armboot (void)
{
init_fnc_t **init_fnc_ptr;
char *s;
unsigned long addr;
/* Pointer is writable since we allocated a register for it */
//分配内存空间给全局变量gd,这里其实就是制定gd的开始地址
gd = (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t));
/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__("": : :"memory");
//先初始化gd,也就是清0操作
memset ((void*)gd, 0, sizeof (gd_t));
//给bd赋值
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
memset (gd->bd, 0, sizeof (bd_t));
//代码已经重定位标志置位,此时代码已经搬迁到了内存中
gd->flags |= GD_FLG_RELOC;
//u-boot镜像大小获取
monitor_flash_len = _bss_start - _armboot_start;
//初始化函数序列,主要包括
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
//malloc内存空间清0
/* armboot_start is defined in the board-specific linker script */
mem_malloc_init (_armboot_start - CONFIG_SYS_MALLOC_LEN);
/*
* reserve memory for VFD display (always full pages)
*/
/* bss_end is defined in the board-specific linker script */
//u-boot预留的LCD 帧buf地址存放在gd->fb_base
addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
vfd_setmem (addr);
gd->fb_base = addr;
/* board init may have inited fb_base */
if (!gd->fb_base) {
/*
* reserve memory for LCD display (always full pages)
*/
/* bss_end is defined in the board-specific linker script */
addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
lcd_setmem (addr);
gd->fb_base = addr;
}
//nandflash初始化
puts ("NAND: ");
nand_init(); /* go init the NAND */
//mmc初始化
puts ("MMC: ");
mmc_initialize (gd->bd);
//环境变量的重定位,即从Flash中搬到RAM中
/* initialize environment */
env_relocate ();
//VFD设备初始化
/* must do this after the framebuffer is allocated */
drv_vfd_init();
//这条语句在原生态u-boot中是没有的,是致远电子追加的,
//目的是为了区分开发板的版本号,通过打印输出内存大小
//modified by luozhizhuo
getddr2_information();
//ip初始化
/* IP Address */
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
//标准初始化
stdio_init (); /* get the devices list going. */
//跳转表初始化,该表具体用途不清楚
jumptable_init ();
//API接口初始化
/* Initialize API */
api_init ();
//其他杂项初始化
console_init_r (); /* fully init console as a device */
/* miscellaneous arch dependent initialisations */
arch_misc_init ();
/* miscellaneous platform dependent initialisations */
misc_init_r ();
//打开终端
/* enable exceptions */
enable_interrupts ();
//调用单板后期初始化,主要是以太网初始化
board_late_init ();
//进入主循环,根据用户的选择启动Linux或者进入命令循环执行用户输入的命令
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;) {
main_loop ();
}
/* NOTREACHED - no way out of command loop except booting */
}
小结:start_armboot主要完成如下工作:
(1)全局数据结构的初始化,比如gd_t数据结构初始化,bd_t的初始化,内存 分配的初始化,这里所谓的“初始化”,其实就是给这些数据结构指定或定义一个“地址”,因为有了地址,我们就可以通过该地址去访问具体的数据了。
(2)条用通用初始化函数,主要是上篇中讲到的 init_sequence 函数指针数组。
(3)初始化具体设备,这部分主要包括Nand Flash、LCD等,i.mx没有提供网络初始化。
(4)初始化环境变量,虽然环境变量初始化已经在(2)中初始化了一次,这里又进一步的初始化了一次。
(5)进入主循环main_loop(),至此,u-boot具备了与程序员的交互功能, 既可以无操作的引导内核kernel,程序员也可以干涉,进行各种命令操作。