uboot启动至引导kernel流程分析图

几个重要的文件:

u-boot.lds 链接脚本,可以知道整个程序的各个段是怎么存放的。

顶层config.mk,和板级config.mk,顶层里定义了LDFAGS变量,这是_start的值。而这个变量的真正定义是在板级的config.mk中的TEXT_BASE。如smdk2410是0x33f8000,Hi3516a是0x80800000。

编译好后,System.map可以看各个变量的值和地址。

arm-linux-objdump -D u-boot > u-boot.s  可以生成反汇编的uboot代码,方便查看流程

/********************************************************************************/

BL0:bl0程序在IROM中,功能:从启动设备(如nandflash, spiflash)加载BL1(uboot的前16k)到IRAM。

BL1:IRAM中16k代码执行,会完成内存控制器的初始化把uboot从nandflash拷贝到DRAM,即第一次搬运,经常设定搬到内存的0x27e00000地址。

u-boot运行在高端地址,所以,有时u-boot剩下的代码,把u-boot代码做了第二次搬运,搬到高端地址去。还把os镜像。拷贝到了内存中。

/********************************************************************************/

启动流程图

第一阶段,主要文件是start.s  和 lowlevel_init.s,  数据的拷贝,nand还是nor启动方式的决定点。

在start.s中的第一个b 由_start跳转到_reset,地址会有偏移(system.map查看),是因为b指令的相对跳转,与代码的位置无关。然后设置CPU为SVC(超级用户模式)模式。上电时的时钟是设置好的,所以要有设置时钟的过程,关键字可搜索CLK。第二个b跳转到cpu初始化,清cache,关mmu,因为这个时候不需要虚拟内存映射。这些都是协处理指令。再b到板级初始化。之后relocate是代码重定向部分,adr r0, _start 把当前代码存储的地址赋给r0,然后ldr r1, _TEXT_BASE,把TEXT_BASE的值作为地址,把这个地址的内容赋给r1, cmp r0, r1 比较两个是否相等,不同则加载,相同说明已经在内存中。ldr r2, _armboot_start如果不同执行_armboot_start,把其赋给r2,其定义刚好为_start,即把_start赋给r2,就是0x33f80000,也就是代码的起始地址。ldr r3, _bss_start,给r3赋值,lds里显示这就是代码的结尾。sub r2, r3, r2 ,确定代码的大小。 add r2, r0, r2 代码的开始加代码的大小,确定了地址, r2=nor flash里代码的结尾。 b到 copy_loop,开始拷贝。然后设置堆栈,清bss,最后ldr pc, _start_armboot,改变了pc指针,此时,跳转到sdram中执行代码。第一阶段结束。

uboot启动至引导kernel流程分析图_第1张图片

第二阶段,初始化一些外设,如LCD,NAND,ETH等。

 

uboot启动至引导kernel流程分析图_第2张图片

源码如下:

void start_armboot (void)
{
	init_fnc_t **init_fnc_ptr;
	char *s;
#ifndef CFG_NO_FLASH
	ulong size;
#endif
#if defined(CONFIG_VFD) || defined(CONFIG_LCD)
	unsigned long addr;
#endif

	/* Pointer is writable since we allocated a register for it */
	gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
	/* compiler optimization barrier needed for GCC >= 3.4 */
	__asm__ __volatile__("": : :"memory");

	memset ((void*)gd, 0, sizeof (gd_t));
	gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
	memset (gd->bd, 0, sizeof (bd_t));

	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 ();
		}
	}

#ifndef CFG_NO_FLASH
	/* configure available FLASH banks */
	size = flash_init ();
	display_flash_config (size);
#endif /* CFG_NO_FLASH */

#ifdef CONFIG_VFD
#	ifndef PAGE_SIZE
#	  define PAGE_SIZE 4096
#	endif
	/*
	 * reserve memory for VFD display (always full pages)
	 */
	/* bss_end is defined in the board-specific linker script */
	addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
	size = vfd_setmem (addr);
	gd->fb_base = addr;
#endif /* CONFIG_VFD */

#ifdef CONFIG_LCD
#	ifndef PAGE_SIZE
#	  define PAGE_SIZE 4096
#	endif
	/*
	 * 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);
	size = lcd_setmem (addr);
	gd->fb_base = addr;
#endif /* CONFIG_LCD */

	/* armboot_start is defined in the board-specific linker script */
	mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);

#if (CONFIG_COMMANDS & CFG_CMD_NAND)
	puts ("NAND:  ");
	nand_init();		/* go init the NAND */
#endif

#ifdef CONFIG_HAS_DATAFLASH
	AT91F_DataflashInit();
	dataflash_print_info();
#endif

	/* initialize environment */
	env_relocate ();

#ifdef CONFIG_VFD
	/* must do this after the framebuffer is allocated */
	drv_vfd_init();
#endif /* CONFIG_VFD */

	/* IP Address */
	gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");

	/* MAC Address */
	{
		int i;
		ulong reg;
		char *s, *e;
		char tmp[64];

		i = getenv_r ("ethaddr", tmp, sizeof (tmp));
		s = (i > 0) ? tmp : NULL;

		for (reg = 0; reg < 6; ++reg) {
			gd->bd->bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
			if (s)
				s = (*e) ? e + 1 : e;
		}

#ifdef CONFIG_HAS_ETH1
		i = getenv_r ("eth1addr", tmp, sizeof (tmp));
		s = (i > 0) ? tmp : NULL;

		for (reg = 0; reg < 6; ++reg) {
			gd->bd->bi_enet1addr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
			if (s)
				s = (*e) ? e + 1 : e;
		}
#endif
	}

	devices_init ();	/* get the devices list going. */

#ifdef CONFIG_CMC_PU2
	load_sernum_ethaddr ();
#endif /* CONFIG_CMC_PU2 */

	jumptable_init ();

	console_init_r ();	/* fully init console as a device */

#if defined(CONFIG_MISC_INIT_R)
	/* miscellaneous platform dependent initialisations */
	misc_init_r ();
#endif

	/* enable exceptions */
	enable_interrupts ();

	/* Perform network card initialisation if necessary */
#ifdef CONFIG_DRIVER_CS8900
	cs8900_get_enetaddr (gd->bd->bi_enetaddr);
#endif

#if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)
	if (getenv ("ethaddr")) {
		smc_set_mac_addr(gd->bd->bi_enetaddr);
	}
#endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */

	/* Initialize from environment */
	if ((s = getenv ("loadaddr")) != NULL) {
		load_addr = simple_strtoul (s, NULL, 16);
	}
#if (CONFIG_COMMANDS & CFG_CMD_NET)
	if ((s = getenv ("bootfile")) != NULL) {
		copy_filename (BootFile, s, sizeof (BootFile));
	}
#endif	/* CFG_CMD_NET */

#ifdef BOARD_LATE_INIT
	board_late_init ();
#endif
#if (CONFIG_COMMANDS & CFG_CMD_NET)
#if defined(CONFIG_NET_MULTI)
	puts ("Net:   ");
#endif
	eth_initialize(gd->bd);
#endif
	/* 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 */
}

下图为第一阶段后的情况:

uboot启动至引导kernel流程分析图_第3张图片

 

uboot最后,引导linux内核的过程。

uboot启动至引导kernel流程分析图_第4张图片

你可能感兴趣的:(Hi3516A,Linux)