u-boot的start_armboot函数解析

  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,程序员也可以干涉,进行各种命令操作。

你可能感兴趣的:(U-boot)