2017.09版uboot启动过程分析

2017.9版本uboot启动至命令行几个重要函数为:_start,_main,board_init_f,relocate_code,board_init_r

一 、程序的入口:_start

对于任何程序,入口函数是在链接时决定的,uboot的入口是由链接脚本决定的。uboot下armv7链接脚本默认目录为u-boot-2017.09\arch\arm\cpu\u-boot.lds

由链接文件u-boot.lds的ENTRY(_start)可知,程序的入口在_start。

OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
	......
	. = 0x00000000;
	. = ALIGN(4);
	.text :
	{
		*(.__image_copy_start)
		*(.vectors)
		CPUDIR/start.o (.text*)
		*(.text*)
	}

在u-boot-2017.09版本中,入口_start在u-boot-2017.09\arch\arm\lib\vectors.S中,

_start:
 
#ifdef CONFIG_SYS_DV_NOR_BOOT_CFG
	.word	CONFIG_SYS_DV_NOR_BOOT_CFG
#endif
 
	b	reset
	ldr	pc, _undefined_instruction
	ldr	pc, _software_interrupt
	ldr	pc, _prefetch_abort
	ldr	pc, _data_abort
	ldr	pc, _not_used
	ldr	pc, _irq
	ldr	pc, _fiq

在vectors.S中,可以看到,从_start入口进入后,立刻跳转到reset去执行。reset在u-boot-2017.09\arch\arm\cpu\armv7\start.S中。

在start.S中,顺序执行以下操作:

(1)单板保存一些boot重要参数

reset:
	/* Allow the board to save important registers */
	b	save_boot_params
save_boot_params_ret:
#ifdef CONFIG_ARMV7_LPAE<span style="white-space:pre">	/* 未定义,因此实际上什么也没做 */
/*
 * check for Hypervisor support
 */
	mrc	p15, 0, r0, c0, c1, 1		@ read ID_PFR1
	and	r0, r0, #CPUID_ARM_VIRT_MASK	@ mask virtualization bits
	cmp	r0, #(1 << CPUID_ARM_VIRT_SHIFT)
	beq	switch_to_hypervisor
switch_to_hypervisor_ret:
#endif
	......
ENTRY(save_boot_params)
    b	save_boot_params_ret		@ back to my caller
ENDPROC(save_boot_params)
	.weak	save_boot_params

(2)屏蔽中断,设置CPU进入SVC32模式

/*
 * disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode,
 * except if in HYP mode already
 */
mrs	r0, cpsr
and	r1, r0, #0x1f		@ mask mode bits
teq	r1, #0x1a		@ test for HYP mode
bicne	r0, r0, #0x1f		@ clear all mode bits
orrne	r0, r0, #0x13		@ set SVC mode
orr	r0, r0, #0xc0		@ disable FIQ and IRQ
msr	cpsr,r0

(3)配置cp15,初始化mmu cache tlb;然后cpu_init_crit调用lowlevel_init(与特定开发板相关的初始化函数)函数,在这个函数里会做一些pll和memory的初始化;从cpu_init_crit返回后,_start的工作基本完成,接下来就是调用_main。

#ifndef CONFIG_SKIP_LOWLEVEL_INIT
	bl	cpu_init_cp15
#ifndef CONFIG_SKIP_LOWLEVEL_INIT_ONLY
	bl	cpu_init_crit
#endif
#endif
 
	bl	_main
	......
ENTRY(cpu_init_crit)
	/*
	 * Jump to board specific initialization...
	 * The Mask ROM will have already initialized
	 * basic memory. Go here to bump up clock rate and handle
	 * wake up conditions.
	 */
	b	lowlevel_init		@ go setup pll,mux,memory
ENDPROC(cpu_init_crit)

二 _main

_main函数在u-boot-2017.09\arch\arm\lib\crt0.S中,代码如下,其中有三个比较重要的函数:

(1)board_init_f

         从_main处顺序执行,遇到的第一个重要的函数就是board_init_f。之前部分代码的作用是设置运行环境,为调用board_init_f做准备。

         board_init_f函数在common/board_f.c 里面;函数通过调用initcall_run_list(init_sequence_f)执行一系列前半部分板级的初始化工作

ENTRY(_main)
 
/*
 * Set up initial C runtime environment and call board_init_f(0).
 */
 
#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
	ldr	r0, =(CONFIG_SPL_STACK)
#else
	ldr	r0, =(CONFIG_SYS_INIT_SP_ADDR)
#endif
	bic	r0, r0, #7	/* 8-byte alignment for ABI compliance */
	mov	sp, r0
	bl	board_init_f_alloc_reserve
	mov	sp, r0
	/* set up gd here, outside any C code */
	mov	r9, r0
	bl	board_init_f_init_reserve
 
	mov	r0, #0
	bl	board_init_f	/* u-boot-2017.05\common\board_f.c  */

(2)relocate_code

         第二部分重定位u-boot代码,复制u-boot代码到SDRAM中;

         relocate_code定义在u-boot-2017.09\arch\arm\lib\relocate.S中;

ldr	r0, [r9, #GD_RELOCADDR]		/* r0 = gd->relocaddr */
b	relocate_code	/* u-boot-2017.05\arch\arm\lib\relocate.S */

(3)board_init_r:         

        第三部分跳转到board_init_r,board_init_r在common\board_r.c中。

         在board_init_r中通过initcall_run_list(init_sequence_r)执行一系列后半部分的板级初始化函数。在这些板级初始化函数         最后调用的是run_main_loop函数 ,经过 main_loop函数后不再返回。

         main_loop函数在common\main.c中,其主要作用是进入命令行,接收并执行命令。

#if ! defined(CONFIG_SPL_BUILD)
	bl coloured_LED_init
	bl red_led_on
#endif
	/* call board_init_r(gd_t *id, ulong dest_addr) */
	mov     r0, r9                  /* gd_t */
	ldr	r1, [r9, #GD_RELOCADDR]	/* dest_addr */
	/* call board_init_r */
#if CONFIG_IS_ENABLED(SYS_THUMB_BUILD)
	ldr	lr, =board_init_r	/* this is auto-relocated! */
	bx	lr
#else
	ldr	pc, =board_init_r	/* u-boot-2017.05\common\board_r.c:this is auto-relocated! */
#endif
	/* we should not return here. */
#endif

  至此基本完成uboot的一个启动过程。

参考博文:https://blog.csdn.net/qq_38144425/article/details/73460095(2017.05版,分析过程简练)

                  https://blog.csdn.net/skyflying2012/article/details/25804209(2014.04版,分析得很深入)

                  两位写的非常好,值得好好学习!

原创文章 103 获赞 158 访问量 8万+

猜你喜欢

转载自blog.csdn.net/csdnxmj/article/details/98649304