一:链接脚本分析启动入口
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
}