很详细的UBOOT解释: https://www.crifan.com/files/doc/docbook/uboot_starts_analysis/release/html/uboot_starts_analysis.html
U-BOOT主要作用和执行流程
①一句话描述
U-BOOT对硬件进行前期的初始化并准备堆栈,之后载入内核并向内核传递必要的参数,便于内核启动。
②执行流程概况
u-boot载入芯片后nor flash从0地址开始执行,nand flash会将前4K考入芯片的内存然后从0地址开始执行,程序最还是从_start标签开始(lds文件定义,start.s有具体实现)。
u-boot一般启动分为两阶段:1.硬件相关的用汇编实现,初始化及重定位代码完成后交给第二阶段 2.第二阶段较为通用,使用c代码编写。
1. UBoot内存划分, lds文件
内存划分存在于对应芯片架构中的u-boot.lds文件中,这个文件是用于连接器连接时对程序各个段空间进行划分之用。
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start) //程序开始标号,既程序从标号为_start的位置开始执行,这个标号在对应CPU(如arm920t)的start.s文件中,接下来程序分析将分析这个文件
SECTIONS { . = 0x00000000; //程序最开始的地址为0 . = ALIGN(4); //4字节地址对齐 .text : //文本段开始位置 { __image_copy_start = .; //拷贝image开始的地方(其实也是0) CPUDIR/start.o (.text) //保证start.s的text段放在最前面 *(.text) //u-boot中所有程序的文本段都会放到这个位置 } . = ALIGN(4); //4字节对齐 .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } //只读数据从这里开始存放 . = ALIGN(4); .data : { *(.data) //所有文件的数据段 } . = ALIGN(4); . = .; //不i知道,可能重定位一下定位器的位置比较好玩儿吧 __u_boot_cmd_start = .; //同上,定义了一个宏,保存当前位置信息 .u_boot_cmd : { *(.u_boot_cmd) } //存储u_boot_cmd __u_boot_cmd_end = .; . = ALIGN(4); __image_copy_end = .; .rel.dyn : { __rel_dyn_start = .; *(.rel*) __rel_dyn_end = .; } .dynsym : { __dynsym_start = .; *(.dynsym) } _end = .;/* * Deprecated: this MMU section is used by pxa at present but * should not be used by new boards/CPUs. */. = ALIGN(4096); .mmutable : { *(.mmutable) } .bss __rel_dyn_start (OVERLAY) : { __bss_start = .; *(.bss) . = ALIGN(4); __bss_end__ = .; } /DISCARD/ : { *(.dynstr*) } /DISCARD/ : { *(.dynamic*) } /DISCARD/ : { *(.plt*) } /DISCARD/ : { *(.interp*) } /DISCARD/ : { *(.gnu*) } }
2. 按代码执行流程分析各个函数
2.1 主要功能
设置CPU模式
关闭看门狗
关闭中断
设置堆栈sp指针
清除bss段
异常中断处理
2.2 主要函数
函数入口:
.globl _start //全局声明,在lds中定义为entry _start: b start_code //主要执行函数,进入代码后直接跳转到start_code ldr pc, _undefined_instruction //ldr,将地址导入寄存器,pc为程序指针。导入pc后会进行调用跳转 ldr pc, _software_interrupt ldr pc, _prefetch_abort ldr pc, _data_abort ldr pc, _not_used ldr pc, _irq ldr pc, _fiq
初始化函数:start_code
start_code:mrs r0, cpsr bic r0, r0, # orr r0, r0, # msr cpsr, r0 defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK)ldr r0, =_start ldr r1, = mov r2, # copyex: subs r2, r2, # ldr r3, [r0], # str r3, [r1], # bne copyex #ifdef CONFIG_S3C24X0# defined(CONFIG_S3C2400) # define pWTCON # define INTMSK # define CLKDIVN # define pWTCON # define INTMSK # define INTSUBMSK # define CLKDIVN # endif ldr r0, =pWTCON mov r1, # str r1, [r0] mov r1, #ldr r0, =INTMSK str r1, [r0] # defined(CONFIG_S3C2410) ldr r1, =ldr r0, =INTSUBMSK str r1, [r0] # endifldr r0, =CLKDIVN mov r1, #str r1, [r0] /* CONFIG_S3C24X0 */#ifndef CONFIG_SKIP_LOWLEVEL_INIT bl cpu_init_crit call_board_init_f: ldr sp, =(CONFIG_SYS_INIT_SP_ADDR) bic sp, sp, # ldr r0,=bl board_init_f cpu_init_crit最终也会调用这个函数
非从RAM启动的情况会执行这个函数:cpu_init_crit
cpu_init_crit:mov r0, #
mcr p15, 0, r0, c7, c7, 0 //关闭ICaches(指令缓存,关闭是为了降低MMU查表带来的开销)和DCaches(数据缓存,DCaches使用的是虚拟地址,开启MMU之前必须关闭) mcr p15, 0, r0, c8, c7, 0 //使无效整个数据TLB和指令TLB(TLB就是负责将虚拟内存地址翻译成实际的物理内存地址
/* * disable MMU stuff and caches */
mrc p15, 0, r0, c1, c0, 0 bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS) //bit8:系统不保护,bit9:ROM不保护,bit13:设置中断向量表的位置为0x0~0x1c,即异常模式基地址为0X0 bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM) //bit0~2:禁止MMU,禁止地址对齐检查,禁止数据Cache.bit7:设为小端模式 orr r0, r0, #0x00000002 @ set bit 2 (A) Align //bit2:开启数据Cache orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache //bit12:开启指令Cache mcr p15, 0, r0, c1, c0, 0
/* * before relocating, we have to setup RAM timing * because memory timing is board-dependend, you will * find a lowlevel_init.S in your board directory. */mov ip, lr //保存lr的值,用于返回调用cpu_init_crit的函数处,用于调用board_init_f
bl lowlevel_init //函数在对应的board文件夹中,第二阶段启动代码,主要作用是初始化两个重要数据结构,对SDRAM的内存分配设置,对各种需要用到的外设进行初始化,最后循环跳入main_loop()函数 mov lr, ip mov pc, lr
board_init_f函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 涉及到两个重要的数据结构:1)bd_t结构体,关于开发板信息(波特率,ip, 平台号,启动参数)。2)gd_t结构体成员主要是一些全局的系统初始化参数。需要用到时,用宏定义DECLARD_GLOBAL_DATA_PTT,指定占用寄存器r8,具体定义如下: typedef struct bd_info { int bi_baudrate; /* serial console baudrate串口波特率 */ unsigned long bi_ip_addr; /* IP Address IP 地址*/ ulong bi_arch_number; /* unique id for this board 板子的id */ ulong bi_boot_params; /* where this board expects params 启动参数*/ struct /* RAM configuration RAM 配置*/ { ulong start; ulong size; } bi_dram[CONFIG_NR_DRAM_BANKS]; } bd_t; Gd_t结构体定义,如下: typedef struct global_data { bd_t *bd; unsigned long flags; //指示标志,如设备已经初始化标志等 unsigned long baudrate; //串行口通信速率 unsigned long have_console; /* serial_init() was called */ #ifdef CONFIG_PRE_CONSOLE_BUFFER unsigned long precon_buf_idx; /* Pre-Console buffer index */ #endif unsigned long env_addr; /* Address of Environment struct 环境参数地址 */ unsigned long env_valid; /* Checksum of Environment valid? 环境参数CRC检验有效标志*/ unsigned long fb_base; /* base address of frame buffer 帧缓冲区基地址*/ …… } gd_t; |
c函数,计算重定位后地址分配,填充bd和gd数据:board_init_f
void board_init_f(ulong bootflag) { bd_t *bd; init_fnc_t **init_fnc_ptr; gd_t *id;ulong addr, addr_sp; #ifdef CONFIG_PRAMulong reg;#endifbootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_F, "board_init_f");/* Pointer is writable since we allocated a register for it */gd = (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07);/* compiler optimization barrier needed for GCC >= 3.4 */__asm__ __volatile__("": : :"memory"); /*内存屏障,防止编译器优化赋值顺序*/memset((void *)gd, 0, sizeof(gd_t)); gd->mon_len = _bss_end_ofs; /*_bss_end_ofs的定义在start.S中: .globl _bss_end_ofs,这里计算出来了U-BOOT的大小,用于后面做减法计算重定位的起始地址*/#ifdef CONFIG_OF_EMBED/* Get a pointer to the FDT */gd->fdt_blob = _binary_dt_dtb_start;#elif defined CONFIG_OF_SEPARATE/* FDT is at end of image */gd->fdt_blob = (void *)(_end_ofs + _TEXT_BASE);#endif/* Allow the early environment to override the fdt address */gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16, (uintptr_t)gd->fdt_blob);for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { /*初始化函数的数组,会逐个调用数组中的初始化函数*/if ((*init_fnc_ptr)() != 0) { hang (); } } #ifdef CONFIG_OF_CONTROL/* For now, put this check after the console is ready */if (fdtdec_prepare_fdt()) { panic("** CONFIG_OF_CONTROL defined but no FDT - please see ""doc/README.fdt-control"); }#endifdebug("monitor len: %08lX\n", gd->mon_len);/* * Ram is setup, size stored in gd !! */debug("ramsize: %08lX\n", gd->ram_size);#if defined(CONFIG_SYS_MEM_TOP_HIDE)/* * Subtract specified amount of memory to hide so that it won't * get "touched" at all by U-Boot. By fixing up gd->ram_size * the Linux kernel should now get passed the now "corrected" * memory size and won't touch it either. This should work * for arch/ppc and arch/powerpc. Only Linux board ports in * arch/powerpc with bootwrapper support, that recalculate the * memory size from the SDRAM controller setup will have to * get fixed. */gd->ram_size -= CONFIG_SYS_MEM_TOP_HIDE;#endifaddr = CONFIG_SYS_SDRAM_BASE + gd->ram_size; /*这样addr是内存的高地址,0x30000000+256M, 关于gd->ram_size,在初始化函数dram_init中,已经给过值了*/#ifdef CONFIG_LOGBUFFER #ifndef CONFIG_ALT_LB_ADDR/* reserve kernel log buffer */addr -= (LOGBUFF_RESERVE); debug("Reserving %dk for kernel logbuffer at %08lx\n", LOGBUFF_LEN, addr);#endif#endif#ifdef CONFIG_PRAM/* * reserve protected RAM */reg = getenv_ulong("pram", 10, CONFIG_PRAM); /*从环境变量获取代码地址,pram*/addr -= (reg << 10); /* size is in kB */debug("Reserving %ldk for protected RAM at %08lx\n", reg, addr);#endif /* CONFIG_PRAM */#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))/* reserve TLB table */addr -= (4096 * 4);/* round down to next 64 kB limit */addr &= ~(0x10000 - 1); //64K对齐gd->tlb_addr = addr; debug("TLB table at: %08lx\n", addr);#endif/* round down to next 4 kB limit */addr &= ~(4096 - 1); // K对齐,此处前面已经64K对齐了,就不需改动debug("Top of RAM usable for U-Boot at: %08lx\n", addr); #ifdef CONFIG_LCD #ifdef CONFIG_FB_ADDR gd->fb_base = CONFIG_FB_ADDR;#else/* reserve memory for LCD display (always full pages) */addr = lcd_setmem(addr); gd->fb_base = addr;#endif /* CONFIG_FB_ADDR */#endif /* CONFIG_LCD *//* * reserve memory for U-Boot code, data & bss * round down to next 4 kB limit */addr -= gd->mon_len; /*重定位地址再减去U-BOOT的大小,此时就是重定位时代码要拷贝到的目的位置*/addr &= ~(4096 - 1); debug("Reserving %ldk for U-Boot at: %08lx\n", gd->mon_len >> 10, addr); #ifndef CONFIG_SPL_BUILD/* * reserve memory for malloc() arena */addr_sp = addr - TOTAL_MALLOC_LEN; /*当前地址减去预留给堆的空间后,作为栈的初始地址*/debug("Reserving %dk for malloc() at: %08lx\n", TOTAL_MALLOC_LEN >> 10, addr_sp);/* * (permanently) allocate a Board Info struct * and a permanent copy of the "global" data */addr_sp -= sizeof (bd_t); /*栈中用于放bd_t的数据,预留出足够的空间*/bd = (bd_t *) addr_sp; gd->bd = bd; /*bd指向新分配的地址,代码重定位把数据copy过去后可以直接使用地址指针*/debug("Reserving %zu Bytes for Board Info at: %08lx\n",sizeof (bd_t), addr_sp); #ifdef CONFIG_MACH_TYPE gd->bd->bi_arch_number = CONFIG_MACH_TYPE; /* board id for Linux */#endifaddr_sp -= sizeof (gd_t); /*栈顶指针减法,预留出gd_t的空间,参考bd_t*/id = (gd_t *) addr_sp; debug("Reserving %zu Bytes for Global Data at: %08lx\n",sizeof (gd_t), addr_sp);/* setup stackpointer for exeptions */gd->irq_sp = addr_sp; /*此时栈顶的地址放入gd结构体,作为ird中断使用的栈顶地址*/#ifdef CONFIG_USE_IRQ addr_sp -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ); debug("Reserving %zu Bytes for IRQ stack at: %08lx\n", CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ, addr_sp);#endif/* leave 3 words for abort-stack */addr_sp -= 12; /*为中断预留的栈空间*//* 8-byte alignment for ABI compliance */addr_sp &= ~0x07;#elseaddr_sp += 128; /* leave 32 words for abort-stack */gd->irq_sp = addr_sp;#endifdebug("New Stack Pointer is: %08lx\n", addr_sp); #ifdef CONFIG_POST post_bootmode_init(); post_run(NULL, POST_ROM | post_bootmode_get(0));#endifgd->bd->bi_baudrate = gd->baudrate;/* Ram ist board specific, so move it to board code ... */dram_init_banksize(); display_dram_config(); /* and display it */gd->relocaddr = addr; /*u-boot重新搬运后的起始地址。*/gd->start_addr_sp = addr_sp; gd->reloc_off = addr - _TEXT_BASE; debug("relocation Offset is: %08lx\n", gd->reloc_off); memcpy(id, (void *)gd, sizeof(gd_t)); relocate_code(addr_sp, id, addr); /*relocate_code(addr_sp, id, addr);在start.S中定义,C又回到了汇编*//* NOTREACHED - relocate_code() does not return */}
被c函数调用,用于重定位代码,存在于start.s中:relocate_code
.globl relocate_code relocate_code: mov r4, r0 mov r5, r1 mov r6, r2 stack_setup: mov sp, r4 adr r0, _start cmp r0, r6 beq clear_bss mov r1, r6 ldr r3, _bss_start_ofs add r2, r0, r3 copy_loop: ldmia r0!, {r9-r10} stmia r1!, {r9-r10} cmp r0, r2 blo copy_loop#ifndef CONFIG_SPL_BUILDldr r0, _TEXT_BASE sub r9, r6, r0 ldr r10, _dynsym_start_ofs add r10, r10, r0 ldr r2, _rel_dyn_start_ofs add r2, r2, r0 ldr r3, _rel_dyn_end_ofs add r3, r3, r0 fixloop: ldr r0, [r2] add r0, r0, r9 ldr r1, [r2, #] and r7, r1, #cmp r7, # beq fixrel cmp r7, # beq fixabsb fixnext fixabs:mov r1, r1, LSR # add r1, r10, r1 ldr r1, [r1, #] add r1, r1, r9 b fixnext fixrel:ldr r1, [r0] add r1, r1, r9 fixnext: str r1, [r0] add r2, r2, # cmp r2, r3 blo fixloopclear_bss: #ifndef CONFIG_SPL_BUILD ldr r0, _bss_start_ofs ldr r1, _bss_end_ofs mov r4, r6 add r0, r0, r4 add r1, r1, r4 mov r2, # clbss_l:str r2, [r0] add r0, r0, #cmp r0, r1 bne clbss_l bl coloured_LED_init bl red_led_on#ifdef CONFIG_NAND_SPL ldr r0, _nand_boot_ofs mov pc, r0 _nand_boot_ofs: .word nand_boot ldr r0, _board_init_r_ofs adr r1, _start add lr, r0, r1 add lr, lr, r9mov r0, r5 mov r1, r6 mov pc, lr _board_init_r_ofs: .word board_init_r - _start_rel_dyn_start_ofs: .word __rel_dyn_start - _start _rel_dyn_end_ofs: .word __rel_dyn_end - _start _dynsym_start_ofs:ynsym_start - _start
第二阶段:board_init_r最终调用main_loop解析参数启动内核
void board_init_r(gd_t *id, ulong dest_addr) {ulong malloc_start;#if !defined(CONFIG_SYS_NO_FLASH)ulong flash_size;#endifgd = id; gd->flags |= GD_FLG_RELOC; /* tell others: relocation done */bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_R, "board_init_r"); monitor_flash_len = _end_ofs;/* Enable caches */enable_caches(); debug("monitor flash len: %08lX\n", monitor_flash_len); board_init(); /* Setup chipselects */ /*设置板级的初始化*//* * TODO: printing of the clock inforamtion of the board is now * implemented as part of bdinfo command. Currently only support for * davinci SOC's is added. Remove this check once all the board * implement this. */#ifdef CONFIG_CLOCKS set_cpu_clk_info(); /* Setup clock information */#endif#ifdef CONFIG_SERIAL_MULTI serial_initialize();#endifdebug("Now running in RAM - U-Boot at: %08lx\n", dest_addr); #ifdef CONFIG_LOGBUFFER logbuff_init_ptrs();#endif#ifdef CONFIG_POST post_output_backlog();#endif/* The Malloc area is immediately below the monitor copy in DRAM */malloc_start = dest_addr - TOTAL_MALLOC_LEN; /*剩余出堆内存的空间*/mem_malloc_init (malloc_start, TOTAL_MALLOC_LEN);#if !defined(CONFIG_SYS_NO_FLASH) puts("Flash: "); flash_size = flash_init();if (flash_size > 0) { # ifdef CONFIG_SYS_FLASH_CHECKSUMchar *s = getenv("flashchecksum"); print_size(flash_size, "");/* * Compute and print flash CRC if flashchecksum is set to 'y' * * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX */if (s && (*s == 'y')) { printf(" CRC: %08X", crc32(0, (const unsigned char *) CONFIG_SYS_FLASH_BASE, flash_size)); } putc('\n'); # else /* !CONFIG_SYS_FLASH_CHECKSUM */print_size(flash_size, "\n"); # endif /* CONFIG_SYS_FLASH_CHECKSUM */} else { puts(failed); hang(); }#endif#if defined(CONFIG_CMD_NAND) puts("NAND: "); nand_init(); /* go init the NAND */#endif#if defined(CONFIG_CMD_ONENAND) onenand_init();#endif#ifdef CONFIG_GENERIC_MMC puts("MMC: "); mmc_initialize(gd->bd);#endif#ifdef CONFIG_HAS_DATAFLASH AT91F_DataflashInit(); dataflash_print_info();#endif/* initialize environment */env_relocate();#if defined(CONFIG_CMD_PCI) || defined(CONFIG_PCI) arm_pci_init();#endif/* IP Address */gd->bd->bi_ip_addr = getenv_IPaddr("ipaddr"); stdio_init(); /* get the devices list going. */jumptable_init();#if defined(CONFIG_API)/* Initialize API */api_init();#endifconsole_init_r(); /* fully init console as a device */#if defined(CONFIG_ARCH_MISC_INIT)/* miscellaneous arch dependent initialisations */arch_misc_init();#endif#if defined(CONFIG_MISC_INIT_R)/* miscellaneous platform dependent initialisations */misc_init_r();#endif /* set up exceptions */interrupt_init();/* enable exceptions */enable_interrupts();/* Perform network card initialisation if necessary */#if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)/* XXX: this needs to be moved to board init */if (getenv("ethaddr")) { uchar enetaddr[6]; eth_getenv_enetaddr("ethaddr", enetaddr); smc_set_mac_addr(enetaddr); }#endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 *//* Initialize from environment */load_addr = getenv_ulong("loadaddr", 16, load_addr);#if defined(CONFIG_CMD_NET) {char *s = getenv("bootfile");if (s != NULL) copy_filename(BootFile, s, sizeof(BootFile)); }#endif#ifdef CONFIG_BOARD_LATE_INIT board_late_init();#endif#ifdef CONFIG_BITBANGMII bb_miiphy_init();#endif#if defined(CONFIG_CMD_NET) puts("Net: "); eth_initialize(gd->bd);#if defined(CONFIG_RESET_PHY_R) debug("Reset Ethernet PHY\n"); reset_phy();#endif#endif#ifdef CONFIG_POST post_run(NULL, POST_RAM | post_bootmode_get(0));#endif#if defined(CONFIG_PRAM) || defined(CONFIG_LOGBUFFER)/* * Export available size of memory for Linux, * taking into account the protected RAM at top of memory */{ulong pram = 0; uchar memsz[32]; #ifdef CONFIG_PRAM pram = getenv_ulong("pram", 10, CONFIG_PRAM);#endif#ifdef CONFIG_LOGBUFFER #ifndef CONFIG_ALT_LB_ADDR/* Also take the logbuffer into account (pram is in kB) */pram += (LOGBUFF_LEN + LOGBUFF_OVERHEAD) / 1024;#endif#endifsprintf((char *)memsz, "%ldk", (gd->ram_size / 1024) - pram); setenv("mem", (char *)memsz); }#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 */}
main.c中的main_loop函数
main_loop函数分析参考这里: https://blog.csdn.net/andy_wsj/article/details/8614905
执行到启动内核的调用流程:parse_file_outer->parse_stream_outer->run_list->run_list_real->run_pipe_real->cmd_process->(通过注册到u_boot_cmd结构的的do_bootm函数后向下继续调用)->do_bootm->do_bootm_linux->【boot_prep_linux(填充a_tag),boot_jump_linux(控制权移交内核,内核入口从image的laodaddr获取)】,到此u_boot寿终正寝,权限交给内核。
void main_loop (void) { #ifndef CONFIG_SYS_HUSH_PARSERstatic char lastcommand[CONFIG_SYS_CBSIZE] = { 0, };int len;int rc = 1;int flag;#endif#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)char *s;int bootdelay;#endif#ifdef CONFIG_PREBOOTchar *p;#endif#ifdef CONFIG_BOOTCOUNT_LIMIT unsigned long bootcount = 0; unsigned long bootlimit = 0;char *bcs;char bcs_set[16];#endif /* CONFIG_BOOTCOUNT_LIMIT */ #ifdef CONFIG_BOOTCOUNT_LIMIT bootcount = bootcount_load(); bootcount++; bootcount_store (bootcount); sprintf (bcs_set, "%lu", bootcount); setenv ("bootcount", bcs_set); bcs = getenv ("bootlimit"); bootlimit = bcs ? simple_strtoul (bcs, NULL, 10) : 0;#endif /* CONFIG_BOOTCOUNT_LIMIT */ #ifdef CONFIG_MODEM_SUPPORT debug ("DEBUG: main_loop: do_mdm_init=%d\n", do_mdm_init);if (do_mdm_init) {char *str = strdup(getenv("mdm_cmd")); setenv ("preboot", str); /* set or delete definition */if (str != NULL)free (str); mdm_init(); /* wait for modem connection */}#endif /* CONFIG_MODEM_SUPPORT */ #ifdef CONFIG_VERSION_VARIABLE { setenv ("ver", version_string); /* set version variable */}#endif /* CONFIG_VERSION_VARIABLE */ #ifdef CONFIG_SYS_HUSH_PARSER u_boot_hush_start ();#endif#if defined(CONFIG_HUSH_INIT_VAR) hush_init_var ();#endif#ifdef CONFIG_PREBOOTif ((p = getenv ("preboot")) != NULL) { # ifdef CONFIG_AUTOBOOT_KEYEDint prev = disable_ctrlc(1); /* disable Control C checking */# endif run_command(p, 0); # ifdef CONFIG_AUTOBOOT_KEYED disable_ctrlc(prev); /* restore Control C checking */# endif }#endif /* CONFIG_PREBOOT */#if defined(CONFIG_UPDATE_TFTP) update_tftp (0UL);#endif /* CONFIG_UPDATE_TFTP */#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) s = getenv ("bootdelay"); bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY; debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);#if defined(CONFIG_MENU_SHOW) bootdelay = menu_show(bootdelay);#endif# ifdef CONFIG_BOOT_RETRY_TIME init_cmd_timeout (); # endif /* CONFIG_BOOT_RETRY_TIME */#ifdef CONFIG_POSTif (gd->flags & GD_FLG_POSTFAIL) { s = getenv("failbootcmd"); }else#endif /* CONFIG_POST */ #ifdef CONFIG_BOOTCOUNT_LIMITif (bootlimit && (bootcount > bootlimit)) { printf ("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n", (unsigned)bootlimit); s = getenv ("altbootcmd"); }else#endif /* CONFIG_BOOTCOUNT_LIMIT */ s = getenv ("bootcmd"); debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");if (bootdelay >= 0 && s && !abortboot (bootdelay)) { # ifdef CONFIG_AUTOBOOT_KEYEDint prev = disable_ctrlc(1); /* disable Control C checking */# endif run_command(s, 0); # ifdef CONFIG_AUTOBOOT_KEYED disable_ctrlc(prev); /* restore Control C checking */# endif } # ifdef CONFIG_MENUKEYif (menukey == CONFIG_MENUKEY) { s = getenv("menucmd");if (s) run_command(s, 0); }#endif /* CONFIG_MENUKEY */#endif /* CONFIG_BOOTDELAY *//* * Main Loop for Monitor Command Processing */#ifdef CONFIG_SYS_HUSH_PARSER parse_file_outer(); /*2410走这里,最终通过cmd_process根据命令行的入参调用内核启动,启动函数定义在U_BOOT_CMD结构体定义的结构中*//* This point is never reached */for (;;);#elsefor (;;) { #ifdef CONFIG_BOOT_RETRY_TIMEif (rc >= 0) {/* Saw enough of a valid command to * restart the timeout. */reset_cmd_timeout(); }#endiflen = readline (CONFIG_SYS_PROMPT); flag = 0; /* assume no special flags for now */if (len > 0) strcpy (lastcommand, console_buffer);else if (len == 0) flag |= CMD_FLAG_REPEAT; #ifdef CONFIG_BOOT_RETRY_TIMEelse if (len == -2) {/* -2 means timed out, retry autoboot */puts ("\nTimed out waiting for command\n"); # ifdef CONFIG_RESET_TO_RETRY/* Reinit board to run initialization code again */do_reset (NULL, 0, 0, NULL); # elsereturn; /* retry autoboot */# endif }#endifif (len == -1) puts ("<INTERRUPT>\n");elserc = run_command(lastcommand, flag);if (rc <= 0) {/* invalid command or not repeatable, forget it */lastcommand[0] = 0; } }#endif /*CONFIG_SYS_HUSH_PARSER*/ }
联系客服