当前位置: 代码迷 >> 综合 >> U-Boot-2016.03启动分析
  详细解决方案

U-Boot-2016.03启动分析

热度:47   发布时间:2023-10-24 00:53:13.0

一:链接脚本分析启动入口

u-boot.bin:OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{. = 0x00000000;. = ALIGN(4);.text :{*(.__image_copy_start)*(.vectors)arch/arm/cpu/armv7/start.o (.text*)*(.text*)}... ...

由链接脚本可知入口函数为“_start”,位于\arch\arm\lib\vectors.S

二:U-Boot启动流程

1,\arch\arm\lib\vectors.S

.globl _start.section ".vectors", "ax"_start:#ifdef CONFIG_SYS_DV_NOR_BOOT_CFG.word	CONFIG_SYS_DV_NOR_BOOT_CFG
#endifb	resetldr	pc, _undefined_instructionldr	pc, _software_interruptldr	pc, _prefetch_abortldr	pc, _data_abortldr	pc, _not_usedldr	pc, _irqldr	pc, _fiq

 指令跳转:“b    reset” 位于\arch\arm\cpu\armv7\start.S

	.globl	reset.globl	save_boot_params_retreset:/* Allow the board to save important registers */b	save_boot_params
save_boot_params_ret:

save_boot_params:作用只是一个跳转,最终还是回到start.S文件中的save_boot_params_ret

void save_boot_params(u32 r0, u32 r1, u32 r2, u32 r3)
{from_spl = r0 != UBOOT_NOT_LOADED_FROM_SPL;save_boot_params_ret();
}

save_boot_params_ret:设置处理器模式

save_boot_params_ret:/** disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode,* except if in HYP mode already*/mrs	r0, cpsrand	r1, r0, #0x1f		@ mask mode bitsteq	r1, #0x1a		@ test for HYP modebicne	r0, r0, #0x1f		@ clear all mode bitsorrne	r0, r0, #0x13		@ set SVC modeorr	r0, r0, #0xc0		@ disable FIQ and IRQmsr	cpsr,r0

继续向下执行:清除SCTLR寄存器bit13目的向量表重定位,为1时不能重定位。将_start入口地址0x87800000写入VBAR寄存器达到向量表重定位的目的。

/** Setup vector:* (OMAP4 spl TEXT_BASE is not 32 byte aligned.* Continue to use ROM code vector only in OMAP4 spl)*/
#if !(defined(CONFIG_OMAP44XX) && defined(CONFIG_SPL_BUILD))/* Set V=0 in CP15 SCTLR register - for VBAR to point to vector */mrc	p15, 0, r0, c1, c0, 0	@ Read CP15 SCTLR Registerbic	r0, #CR_V		@ V = 0mcr	p15, 0, r0, c1, c0, 0	@ Write CP15 SCTLR Register/* Set vector address in CP15 VBAR register */ldr	r0, =_startmcr	p15, 0, r0, c12, c0, 0	@Set VBAR
#endif#define CR_V	(1 << 13)	/* Vectors relocated to 0xffff0000	*/

继续往下执行:“cpu_init_cp15”cp15寄存机相关的配置

	/* the mask ROM code should have PLL and others stable */
#ifndef CONFIG_SKIP_LOWLEVEL_INITbl	cpu_init_cp15bl	cpu_init_crit
#endifbl	_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)

2、\arch\arm\cpu\armv7\lowlevel_init.S:lowlevel_init

ENTRY(lowlevel_init)/** Setup a temporary stack. Global data is not available yet.*/ldr	sp, =CONFIG_SYS_INIT_SP_ADDRbic	sp, sp, #7 /* 8-byte alignment for ABI compliance */
#ifdef CONFIG_SPL_DMmov	r9, #0
#else/** Set up global data for boards that still need it. This will be* removed soon.*/
#ifdef CONFIG_SPL_BUILDldr	r9, =gdata
#elsesub	sp, sp, #GD_SIZEbic	sp, sp, #7mov	r9, sp
#endif
#endif/** Save the old lr(passed in ip) and the current lr to stack*/push	{ip, lr}bl	s_initpop	{ip, pc}
ENDPROC(lowlevel_init)

CONFIG_SYS_INIT_SP_ADDR地址分析:0x00900000+0x00020000-256 = 0x0091FF00

#define CONFIG_SYS_INIT_SP_OFFSET \(CONFIG_SYS_INIT_RAM_SIZE - GENERATED_GBL_DATA_SIZE)
#define CONFIG_SYS_INIT_SP_ADDR \(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET)\include\configs\Mx6sllevk.h
#define CONFIG_SYS_INIT_RAM_ADDR	IRAM_BASE_ADDR
#define CONFIG_SYS_INIT_RAM_SIZE	IRAM_SIZE\arch\arm\include\asm\arch-mx6\Imx-regs.h
#define IRAM_BASE_ADDR            0x00900000
#if !(defined(CONFIG_MX6SX) || defined(CONFIG_MX6UL) || \defined(CONFIG_MX6SLL) || defined(CONFIG_MX6SL))
#define IRAM_SIZE                    0x00040000
#else
#define IRAM_SIZE                    0x00020000/include/generated/generic-asm-offsets.h  此文件在uboot编译之后才会出现
#define GENERATED_GBL_DATA_SIZE 256 /* (sizeof(struct global_data) + 15) & ~15  @ */

GENERATED_GBL_DATA_SIZE与#GD_SIZE = 248在uboot编译之后会在/include/generated/generic-asm-offsets.h 文件中出现。

继续向下执行\arch\arm\cpu\armv7\mx6\Soc.c:s_init

针对mx6ull会直接返回相当于一个空函数

if (is_cpu_type(MXC_CPU_MX6SX) || is_cpu_type(MXC_CPU_MX6UL) ||is_cpu_type(MXC_CPU_MX6ULL) || is_cpu_type(MXC_CPU_MX6SLL))return;

一直返回至start.s文件“    bl    _main”

3、\arch\arm\lib\crt0.S:_main

设置sp指针为CONFIG_SYS_INIT_SP_ADDR = 0x0091FF00;

bic    sp, sp, #7 :8字节对齐。

ENTRY(_main)
/** Set up initial C runtime environment and call board_init_f(0).*/#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)ldr	sp, =(CONFIG_SPL_STACK)
#elseldr	sp, =(CONFIG_SYS_INIT_SP_ADDR)
#endif
#if defined(CONFIG_CPU_V7M)	/* v7M forbids using SP as BIC destination */mov	r3, spbic	r3, r3, #7mov	sp, r3
#elsebic	sp, sp, #7	/* 8-byte alignment for ABI compliance */
#endifmov	r0, spbl	board_init_f_alloc_reservemov	sp, r0/* set up gd here, outside any C code */mov	r9, r0bl	board_init_f_init_reservemov	r0, #0bl	board_init_f

调用board_init_f_alloc_reserve函数:设置sp指针0x0091FF00-0x40-248B-8B = 0x0091FA00

ulong board_init_f_alloc_reserve(ulong top)
{/* Reserve early malloc arena */
#if defined(CONFIG_SYS_MALLOC_F)top -= CONFIG_SYS_MALLOC_F_LEN;
#endif/* LAST : reserve GD (rounded up to a multiple of 16 bytes) */top = rounddown(top-sizeof(struct global_data), 16);return top;
}#define rounddown(x, y) (				\
{							\typeof(x) __x = (x);				\__x - (__x % (y));				\
}

说明一下“r9”:\arch\arm\include\asm\Global_data.h

gd指向r0:0x0091FA00

/* set up gd here, outside any C code */
mov	r9, r0#define DECLARE_GLOBAL_DATA_PTR        register volatile gd_t *gd asm ("r9")
typedef struct global_data {bd_t *bd;unsigned long flags;unsigned int baudrate;unsigned long cpu_clk;	/* CPU clock in Hz!		*/unsigned long bus_clk;/* We cannot bracket this with CONFIG_PCI due to mpc5xxx */unsigned long pci_clk;... ...#ifdef CONFIG_DM_VIDEOulong video_top;		/* Top of video frame buffer area */ulong video_bottom;		/* Bottom of video frame buffer area */
#endif
} gd_t;

继续向下执行board_init_f_init_reserve函数:初始化gd

void board_init_f_init_reserve(ulong base)
{struct global_data *gd_ptr;
#ifndef _USE_MEMCPYint *ptr;
#endif/** clear GD entirely and set it up.* Use gd_ptr, as gd may not be properly set yet.*/gd_ptr = (struct global_data *)base;/* zero the area */
#ifdef _USE_MEMCPYmemset(gd_ptr, '\0', sizeof(*gd));
#elsefor (ptr = (int *)gd_ptr; ptr < (int *)(gd_ptr + 1); )*ptr++ = 0;
#endif/* set GD unless architecture did it already */
#if !defined(CONFIG_ARM)arch_setup_gd(gd_ptr);
#endif/* next alloc will be higher by one GD plus 16-byte alignment */base += roundup(sizeof(struct global_data), 16);/** record early malloc arena start.* Use gd as it is now properly set for all architectures.*/#if defined(CONFIG_SYS_MALLOC_F)/* go down one 'early malloc arena' */gd->malloc_base = base;/* next alloc will be higher by one 'early malloc arena' size */base += CONFIG_SYS_MALLOC_F_LEN;
#endif
}

4、\common\Board_f.c:board_init_f

继续向下执行board_init_f函数:调用“init_sequence_f”数组中的所有成员函数,重定位uboot地址,初始化一些外设如定时器,看门口或打印一些消息等等

void board_init_f(ulong boot_flags)
{... ...if (initcall_run_list(init_sequence_f))hang();... ...
}static init_fnc_t init_sequence_f[] = {
#ifdef CONFIG_SANDBOXsetup_ram_buf,
#endifsetup_mon_len,
#ifdef CONFIG_OF_CONTROL... ...INIT_FUNC_WATCHDOG_RESETreloc_fdt,setup_reloc,NULL,
};

返回到“_main”函数中继续向下执行:重新设置sp和gd,gd->start_addr_sp = 0x9EF44E90该地址在“board_init_f”中有计算

	ldr	sp, [r9, #GD_START_ADDR_SP]	/* sp = gd->start_addr_sp */
#if defined(CONFIG_CPU_V7M)	/* v7M forbids using SP as BIC destination */mov	r3, spbic	r3, r3, #7mov	sp, r3
#elsebic	sp, sp, #7	/* 8-byte alignment for ABI compliance */
#endifldr	r9, [r9, #GD_BD]		/* r9 = gd->bd */sub	r9, r9, #GD_SIZE		/* new GD is below bd */adr	lr, hereldr	r0, [r9, #GD_RELOC_OFF]		/* r0 = gd->reloc_off */add	lr, lr, r0
#if defined(CONFIG_CPU_V7M)orr	lr, #1				/* As required by Thumb-only */
#endifldr	r0, [r9, #GD_RELOCADDR]		/* r0 = gd->relocaddr */b	relocate_code

执行“here”中的两个函数:

\arch\arm\lib\relocate.S:relocate_vectors 重定位向量表,加载重定位后的uboot首地址,将新的向量表首地址写入到VBAR寄存器中,设置向量表偏移;

\arch\arm\cpu\armv7\start.S:c_runtime_cpu_setup

here:
/** now relocate vectors*/bl	relocate_vectors/* Set up final (full) environment */bl	c_runtime_cpu_setup	/* we still call old routine here */
ENTRY(relocate_vectors)#ifdef CONFIG_CPU_V7M/** On ARMv7-M we only have to write the new vector address* to VTOR register.*/ldr	r0, [r9, #GD_RELOCADDR]	/* r0 = gd->relocaddr */ldr	r1, =V7M_SCB_BASEstr	r0, [r1, V7M_SCB_VTOR]
#else
#ifdef CONFIG_HAS_VBAR/** If the ARM processor has the security extensions,* use VBAR to relocate the exception vectors.*/ldr	r0, [r9, #GD_RELOCADDR]	/* r0 = gd->relocaddr */mcr     p15, 0, r0, c12, c0, 0  /* Set VBAR */
#else/** Copy the relocated exception vectors to the* correct address* CP15 c1 V bit gives us the location of the vectors:* 0x00000000 or 0xFFFF0000.*/ldr	r0, [r9, #GD_RELOCADDR]	/* r0 = gd->relocaddr */mrc	p15, 0, r2, c1, c0, 0	/* V bit (bit[13]) in CP15 c1 */ands	r2, r2, #(1 << 13)ldreq	r1, =0x00000000		/* If V=0 */ldrne	r1, =0xFFFF0000		/* If V=1 */ldmia	r0!, {r2-r8,r10}stmia	r1!, {r2-r8,r10}ldmia	r0!, {r2-r8,r10}stmia	r1!, {r2-r8,r10}
#endif
#endifbx	lrENDPROC(relocate_vectors)
ENTRY(c_runtime_cpu_setup)
/** If I-cache is enabled invalidate it*/
#ifndef CONFIG_SYS_ICACHE_OFFmcr	p15, 0, r0, c7, c5, 0	@ invalidate icachemcr     p15, 0, r0, c7, c10, 4	@ DSBmcr     p15, 0, r0, c7, c5, 4	@ ISB
#endifbx	lrENDPROC(c_runtime_cpu_setup)

返回here地址继续向下执行:

5、\arch\arm\lib\relocate.S:relocate_code代码拷贝

代码拷贝后导致链接地址与运行地址不同,解决方法就是采用位置无关码,在使用ld文件进行链接时使用“-pie”即可生成位置无关的可执行文件;生成.rel.dyn段,uboot就是靠.rel.dyn段来解决重定位的问题。

\arch\arm\config.mk:

# needed for relocation
LDFLAGS_u-boot += -pie

ENTRY(relocate_code)ldr	r1, =__image_copy_start	/* r1 <- SRC &__image_copy_start */subs	r4, r0, r1		/* r4 <- relocation offset */beq	relocate_done		/* skip relocation */ldr	r2, =__image_copy_end	/* r2 <- SRC &__image_copy_end */copy_loop:ldmia	r1!, {r10-r11}		/* copy from source address [r1]    */stmia	r0!, {r10-r11}		/* copy to   target address [r0]    */cmp	r1, r2			/* until source end address [r2]    */blo	copy_loop/** fix .rel.dyn relocations*/ldr	r2, =__rel_dyn_start	/* r2 <- SRC &__rel_dyn_start */ldr	r3, =__rel_dyn_end	/* r3 <- SRC &__rel_dyn_end */
fixloop:ldmia	r2!, {r0-r1}		/* (r0,r1) <- (SRC location,fixup) */and	r1, r1, #0xffcmp	r1, #23			/* relative fixup? */bne	fixnext/* relative fix: increase location by offset */add	r0, r0, r4ldr	r1, [r0]add	r1, r1, r4str	r1, [r0]
fixnext:cmp	r2, r3blo	fixlooprelocate_done:#ifdef __XSCALE__/** On xscale, icache must be invalidated and write buffers drained,* even with cache disabled - 4.2.7 of xscale core developer's manual*/mcr	p15, 0, r0, c7, c7, 0	/* invalidate icache */mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
#endif/* ARMv4- don't know bx lr but the assembler fails to see that */#ifdef __ARM_ARCH_4__mov	pc, lr
#elsebx	lr
#endifENDPROC(relocate_code)

继续向下执行:清除BSS段,设置函数board_init_r的两个参数:

	mov     r0, r9                  /* gd_t */ldr	r1, [r9, #GD_RELOCADDR]	/* dest_addr */

6、\common\Board_r.c:board_init_r。继board_init_f之后完成后续工作,初始化串口,NAND,EMMC等等任务。

void board_init_r(gd_t *new_gd, ulong dest_addr)
{... ...if (initcall_run_list(init_sequence_r))hang();/* NOTREACHED - run_main_loop() does not return */hang();
}init_fnc_t init_sequence_r[] = {initr_trace,initr_reloc,/* TODO: could x86/PPC have this also perhaps? */
#ifdef CONFIG_ARMinitr_caches,... ...#if defined(CONFIG_SPARC)prom_init,
#endif
#ifdef CONFIG_FSL_FASTBOOTinitr_check_fastboot,
#endifrun_main_loop,
};

run_main_loop:实现uboot启动kernel倒计时,进入uboot命令行功能

static int run_main_loop(void)
{
#ifdef CONFIG_SANDBOXsandbox_main_loop_init();
#endif/* main_loop() can return to retry autoboot, if so just run it again */for (;;)main_loop();return 0;
}void main_loop(void)
{const char *s;bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, "main_loop");#ifndef CONFIG_SYS_GENERIC_BOARDputs("Warning: Your board does not use generic board. Please read\n");puts("doc/README.generic-board and take action. Boards not\n");puts("upgraded by the late 2014 may break or be removed.\n");
#endif#ifdef CONFIG_VERSION_VARIABLEsetenv("ver", version_string);  /* set version variable */
#endif /* CONFIG_VERSION_VARIABLE */cli_init();run_preboot_environment_command();#if defined(CONFIG_UPDATE_TFTP)update_tftp(0UL, NULL, NULL);
#endif /* CONFIG_UPDATE_TFTP */s = bootdelay_process();if (cli_process_fdt(&s))cli_secure_boot_cmd(s);autoboot_command(s);cli_loop();
}

进入autoboot_command:如果没有按键自然结束则执行“run_command_list(s, -1, 0),否则返回之顶层执行cli_loop()进入uboot命令行模式

void autoboot_command(const char *s)
{debug("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");if (stored_bootdelay != -1 && s && !abortboot(stored_bootdelay)) {run_command_list(s, -1, 0);}
}static int abortboot(int bootdelay)
{return abortboot_normal(bootdelay);
}static int abortboot_normal(int bootdelay)
{do {if (tstc()) {	/* we got a key press	*/abort  = 1;	/* don't auto boot	*/bootdelay = 0;	/* no more delay	*/
# ifdef CONFIG_MENUKEYmenukey = getc();
# else(void) getc();  /* consume input	*/
# endifbreak;}udelay(10000);} while (!abort && get_timer(ts) < 1000);
}

cli_loop:uboot命令行解析

void cli_loop(void)
{parse_file_outer();/* This point is never reached */for (;;);
}int parse_file_outer(void)
{int rcode;struct in_str input;setup_file_in_str(&input);rcode = parse_stream_outer(&input, FLAG_PARSE_SEMICOLON);return rcode;
}

parse_stream_outer:parse_stream解析命令;run_list调运解析后的命令,通过“cmd_process”函数

static int parse_stream_outer(struct in_str *inp, int flag)
{do {... ...rcode = parse_stream(&temp, &ctx, inp,flag & FLAG_CONT_ON_NEWLINE ? -1 : '\n');
#ifdef __U_BOOT__if (rcode == 1) flag_repeat = 0;
#endifrun_list(ctx.list_head);
... ...} while (rcode != -1 && !(flag & FLAG_EXIT_FROM_LOOP) &&
}static int run_list(struct pipe *pi)
{rcode = run_list_real(pi);
}static int run_list_real(struct pipe *pi)
{... ...rcode = run_pipe_real(pi);debug_printf("run_pipe_real returned %d\n",rcode);... ...
}static int run_pipe_real(struct pipe *pi)
{return cmd_process(flag, child->argc, child->argv,&flag_repeat, NULL);
}

三:bootz引导linux内核启动流程

通过cmd指令调用do_bootz函数:

U_BOOT_CMD(bootz,	CONFIG_SYS_MAXARGS,	1,	do_bootz,"boot Linux zImage image from memory", bootz_help_text
);

在启动linux内核时需要用到的一个变量“images”

bootm_headers_t images;		/* pointers to os/initrd/fdt images */typedef struct bootm_headers {/** Legacy os image header, if it is a multi component image* then boot_get_ramdisk() and get_fdt() will attempt to get* data from second and third component accordingly.*/image_header_t	*legacy_hdr_os;		/* image header pointer */image_header_t	legacy_hdr_os_copy;	/* header copy */ulong		ep;		/* entry point of OS */... ...int		verify;		/* getenv("verify")[0] != 'n' */#define	BOOTM_STATE_START	(0x00000001)
#define	BOOTM_STATE_FINDOS	(0x00000002)#define	BOOTM_STATE_OS_PREP	(0x00000100)
#define	BOOTM_STATE_OS_FAKE_GO	(0x00000200)	/* 'Almost' run the OS */
#define	BOOTM_STATE_OS_GO	(0x00000400)int		state;#ifdef CONFIG_LMBstruct lmb	lmb;		/* for memory mgmt */
#endif
} bootm_headers_t;

1、执行do_bootz:关闭中断,设置系统镜像为linux。

int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{int ret;/* Consume 'bootz' */argc--; argv++;if (bootz_start(cmdtp, flag, argc, argv, &images))return 1;/** We are doing the BOOTM_STATE_LOADOS state ourselves, so must* disable interrupts ourselves*/bootm_disable_interrupts();images.os.os = IH_OS_LINUX;ret = do_bootm_states(cmdtp, flag, argc, argv,BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO |BOOTM_STATE_OS_GO,&images, 1);return ret;
}

2、执行bootz_start:

static int bootz_start(cmd_tbl_t *cmdtp, int flag, int argc,char * const argv[], bootm_headers_t *images)
{int ret;ulong zi_start, zi_end;ret = do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START,images, 1);/* Setup Linux kernel zImage entry point */
... ...ret = bootz_setup(images->ep, &zi_start, &zi_end);... ...if (bootm_find_images(flag, argc, argv))return 1;return 0;
}

bootz_setup:(1)判断当前系统镜像文件否为linux镜像文件,(2)并打印镜像相关的信息。

int bootz_setup(ulong image, ulong *start, ulong *end)
{struct zimage_header *zi;zi = (struct zimage_header *)map_sysmem(image, 0);if (zi->zi_magic != LINUX_ARM_ZIMAGE_MAGIC) {            /*(1)*/puts("Bad Linux ARM zImage magic!\n");return 1;}*start = zi->zi_start;                                    /*(2)*/*end = zi->zi_end;printf("Kernel image @ %#08lx [ %#08lx - %#08lx ]\n", image, *start,*end);return 0;
}

bootm_find_images:查找设备树文件

int bootm_find_images(int flag, int argc, char * const argv[])
{int ret;... ...#if defined(CONFIG_OF_LIBFDT)/* find flattened device tree */ret = boot_get_fdt(flag, argc, argv, IH_ARCH_DEFAULT, &images,&images.ft_addr, &images.ft_len);if (ret) {puts("Could not find a valid device tree\n");return 1;}set_working_fdt_addr((ulong)images.ft_addr);
... ...return 0;
}

3、do_bootm_states:根据boot不同的状态执行不同的代码,最终调用boot_selected_os函数启动linux内核

int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],int states, bootm_headers_t *images, int boot_progress)
{boot_os_fn *boot_fn;ulong iflag = 0;int ret = 0, need_boot_fn;images->state |= states;/** Work through the states and see how far we get. We stop on* any error.*/if (states & BOOTM_STATE_START)ret = bootm_start(cmdtp, flag, argc, argv);if (!ret && (states & BOOTM_STATE_FINDOS))ret = bootm_find_os(cmdtp, flag, argc, argv);if (!ret && (states & BOOTM_STATE_FINDOTHER)) {ret = bootm_find_other(cmdtp, flag, argc, argv);argc = 0;	/* consume the args */}... .../* From now on, we need the OS boot function */if (ret)return ret;boot_fn = bootm_os_get_boot_func(images->os.os);need_boot_fn = states & (BOOTM_STATE_OS_CMDLINE |BOOTM_STATE_OS_BD_T | BOOTM_STATE_OS_PREP |BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO);if (boot_fn == NULL && need_boot_fn) {if (iflag)enable_interrupts();printf("ERROR: booting os '%s' (%d) is not supported\n",genimg_get_os_name(images->os.os), images->os.os);bootstage_error(BOOTSTAGE_ID_CHECK_BOOT_OS);return 1;}/* From now on, we need the OS boot function */if (ret)return ret;boot_fn = bootm_os_get_boot_func(images->os.os);need_boot_fn = states & (BOOTM_STATE_OS_CMDLINE |BOOTM_STATE_OS_BD_T | BOOTM_STATE_OS_PREP |BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO);if (boot_fn == NULL && need_boot_fn) {if (iflag)enable_interrupts();printf("ERROR: booting os '%s' (%d) is not supported\n",genimg_get_os_name(images->os.os), images->os.os);bootstage_error(BOOTSTAGE_ID_CHECK_BOOT_OS);return 1;}/* Call various other states that are not generally used */if (!ret && (states & BOOTM_STATE_OS_CMDLINE))ret = boot_fn(BOOTM_STATE_OS_CMDLINE, argc, argv, images);if (!ret && (states & BOOTM_STATE_OS_BD_T))ret = boot_fn(BOOTM_STATE_OS_BD_T, argc, argv, images);if (!ret && (states & BOOTM_STATE_OS_PREP))ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, images);#ifdef CONFIG_TRACE/* Pretend to run the OS, then run a user command */if (!ret && (states & BOOTM_STATE_OS_FAKE_GO)) {char *cmd_list = getenv("fakegocmd");ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_FAKE_GO,images, boot_fn);if (!ret && cmd_list)ret = run_command_list(cmd_list, -1, flag);}
#endif/* Check for unsupported subcommand. */if (ret) {puts("subcommand not supported\n");return ret;}/* Now run the OS! We hope this doesn't return */if (!ret && (states & BOOTM_STATE_OS_GO))ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_GO,images, boot_fn);

4、bootm_os_get_boot_func:查找系统启动函数,传入参数os = IH_OS_LINUX,返回linux系统启动函数do_bootm_linux

boot_os_fn *bootm_os_get_boot_func(int os)
{
... ...return boot_os[os];
}

5、do_bootm_linux:(1)传递linux内核参数bootargs

int do_bootm_linux(int flag, int argc, char * const argv[],bootm_headers_t *images)
{/* No need for those on ARM */if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE)return -1;if (flag & BOOTM_STATE_OS_PREP) {boot_prep_linux(images);return 0;}if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) {boot_jump_linux(images, flag);return 0;}boot_prep_linux(images);               /*(1)*/boot_jump_linux(images, flag);         /*(2)*/return 0;
}

6、boot_jump_linux:(1)内核进入函数kernel_entry由linux内核,images->ep保存着linux内核镜像的起始地址即kernel_entry为linux内核的第一行代码;(2)打印一些启动信息并做清理工作;(3)结束uboot程序,进入linux内核。

static void boot_jump_linux(bootm_headers_t *images, int flag)
{
... ...unsigned long machid = gd->bd->bi_arch_number;char *s;void (*kernel_entry)(int zero, int arch, uint params);unsigned long r2;int fake = (flag & BOOTM_STATE_OS_FAKE_GO);kernel_entry = (void (*)(int, int, uint))images->ep;           /*(1)*/s = getenv("machid");if (s) {if (strict_strtoul(s, 16, &machid) < 0) {debug("strict_strtoul failed!\n");return;}printf("Using machid 0x%lx from environment\n", machid);}debug("## Transferring control to Linux (at address %08lx)" \"...\n", (ulong) kernel_entry);bootstage_mark(BOOTSTAGE_ID_RUN_OS);announce_and_cleanup(fake);                                      /*(2)*/if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len)r2 = (unsigned long)images->ft_addr;elser2 = gd->bd->bi_boot_params;if (!fake) {
#ifdef CONFIG_ARMV7_NONSECif (armv7_boot_nonsec()) {armv7_init_nonsec();secure_ram_addr(_do_nonsec_entry)(kernel_entry,0, machid, r2);} else
#endifkernel_entry(0, machid, r2);                              /*(3)*/}
#endif
}