u-boot支持很多CPU,以及一些常见的开发板。
本文以u-boot-2011.06这个最新版本号为例,简要介绍一下u-boot在smdk2410上的启动流程。
首先系统是从arch/arm/cpu/arm920t文件夹下的start.s文件開始运行,而且实际開始运行的代码是从第117行開始: 117:start_code: 118: /* 119: * set the cpu to SVC32 mode 120: */ 121: mrs r0, cpsr 122: bic r0, r0, #0x1f 123: orr r0, r0, #0xd3 124: msr cpsr, r0 上述代码的含义是设置cpu为SVC32模式,即超级保护模式。用于操作系统使用。 140:#ifdef CONFIG_S3C24X0 141: /* turn off the watchdog */ 142: 143:# if defined(CONFIG_S3C2400) 144:# define pWTCON 0x15300000 145:# define INTMSK 0x14400008 /* Interupt-Controller base addresses */ 146:# define CLKDIVN 0x14800014 /* clock divisor register */ 147:#else 148:# define pWTCON 0x53000000 149:# define INTMSK 0x4A000008 /* Interupt-Controller base addresses */ 150:# define INTSUBMSK 0x4A00001C 151:# define CLKDIVN 0x4C000014 /* clock divisor register */ 152:# endif 153: 154: ldr r0, =pWTCON 155: mov r1, #0x0 156: str r1, [r0] 157: 158: /* 159: * mask all IRQs by setting all bits in the INTMR - default 160: */ 161: mov r1, #0xffffffff 162: ldr r0, =INTMSK 163: str r1, [r0] 164:# if defined(CONFIG_S3C2410) 165: ldr r1, =0x3ff 166: ldr r0, =INTSUBMSK 167: str r1, [r0] 168:# endif 169: 170: /* FCLK:HCLK:PCLK = 1:2:4 */ 171: /* default FCLK is 120 MHz ! */ 172: ldr r0, =CLKDIVN 173: mov r1, #3 174: str r1, [r0] 175:#endif /* CONFIG_S3C24X0 */ 该段代码的含义为,先定义几个须要的寄存器,然后关闭开门狗定时器,以及屏蔽全部中断和子中断,最后设置三个时钟频率之间的比值。
181:#ifndef CONFIG_SKIP_LOWLEVEL_INIT 182: bl cpu_init_crit 183:#endif 在第182行中,程序跳转到cpu_init_crit中,它也是在start.s文件里。函数的位置在第328行至第356行,它的作用是设置一些重要的寄存器(如MMU和caches等)以及内存时序。当中在第353行,程序又跳转到了lowlevel_init函数。它是在board/samsung/smdk2410文件夹下的lowlevel_init.s文件里定义的。这个文件的目的就是为了设置内存的时序。 186:call_board_init_f: 187: ldr sp, =(CONFIG_SYS_INIT_SP_ADDR) 188: bic sp, sp, #7 /* 8-byte alignment for ABI compliance */ 189: ldr r0,=0x00000000 190: bl board_init_f 从cpu_init_crit返回后,来到了调用board_init_f的函数处。首先进行堆栈的设置。然后就跳转到board_init_f函数,当中传递给该函数的參数为0。board_init_f这个函数是在arch/arm/lib文件夹下的board.c文件内定义的,函数的位置是在第268行至第422行,它的作用是初始化开发板。须要注意的是,此时程序是在flash中运行的。 以下我们就来分析board_init_f函数。
275: /* Pointer is writable since we allocated a register for it */ 276: gd = (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07); 277: /* compiler optimization barrier needed for GCC >= 3.4 */ 278: __asm__ __volatile__("": : :"memory"); 279: 280: memset ((void*)gd, 0, sizeof (gd_t)); 281: 282: gd->mon_len = _bss_end_ofs; gd是一个保存在ARM的r8寄存器中的gd_t结构体的指针,该结构体包含了u-boot中全部重要的全局变量,它是在arch/arm/include/asm文件夹下的global_data.h文件内被定义的。上述代码的作用是为gd分配地址。并清零。最后得到整个u-boot的长度。 284: for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { 285: if ((*init_fnc_ptr)() != 0) { 286: hang (); 287: } 288: } 上述代码的作用是循环调用init_sequence函数指针数组中的成员。该数组成员函数主要完毕一些初始化的工作。如: board_early_init_f函数(在board/samsung/smdk2410文件夹下的smdk2410.c文件内)完毕ARM的时钟频率和IO的设置; timer_init函数(在arch/arm/cpu/arm920t/s3c24x0文件夹下的timer.c文件内)完毕定时器4的设置。 env_init函数(在common文件夹下的env_flash.c文件内,由于include/configs/smdk2410.h中定义了CONFIG_ENV_IS_IN_FLASH)完毕环境变量的设置; init_baudrate函数(在arch/arm/lib文件夹下的board.c文件内)完毕波特率的设置。 serial_init函数(在drivers/serial文件夹下的serial_s3c24x0.c文件内,由于include/configs/smdk2410.h中定义了CONFIG_S3C24X0_SERIAL)完毕串口通讯的设置; console_init_f函数(在common文件夹下的console.c文件内)完毕第一阶段的控制台初始化; display_banner函数(在arch/arm/lib文件夹下的board.c文件内)用来打印输出一些信息。 dram_init函数(在board/samsung/smdk2410文件夹下的smdk2410.c文件内)用来配置SDRAM的大小。
309: addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size; 得到SDRAM的末位物理地址为0x3400 0000,即SDRAM的空间分布为0x3000 0000~0x33FF FFFF。 329:#if !(defined(CONFIG_SYS_NO_ICACHE) && defined(CONFIG_SYS_NO_DCACHE)) 330: /* reserve TLB table */ 331: addr -= (4096 * 4); 332: 333: /* round down to next 64 kB limit */ 334: addr &= ~(0x10000 - 1); 335: 336: gd->tlb_addr = addr; 337: debug ("TLB table at: %08lx\n", addr); 338:#endif 339: 340: /* round down to next 4 kB limit */ 341: addr &= ~(4096 - 1); 342: debug ("Top of RAM usable for U-Boot at: %08lx\n", addr); 分配SDRAM的高64kB区域作为TLB,即0x33FF 0000~0x33FF FFFF。而且该区域也被用于U-Boot。 354: /* 355: * reserve memory for U-Boot code, data & bss 356: * round down to next 4 kB limit 357: */ 358: addr -= gd->mon_len; 359: addr &= ~(4096 - 1); 360: 361: debug ("Reserving %ldk for U-Boot at: %08lx\n", gd->mon_len >> 10, addr); 分配SDRAM的下一个单元为U-Boot代码段、数据段及BSS段。 363:#ifndef CONFIG_PRELOADER 364: /* 365: * reserve memory for malloc() arena 366: */ 367: addr_sp = addr - TOTAL_MALLOC_LEN; 368: debug ("Reserving %dk for malloc() at: %08lx\n", 369: TOTAL_MALLOC_LEN >> 10, addr_sp); 370: /* 371: * (permanently) allocate a Board Info struct 372: * and a permanent copy of the "global" data 373: */ 374: addr_sp -= sizeof (bd_t); 375: bd = (bd_t *) addr_sp; 376: gd->bd = bd; 377: debug ("Reserving %zu Bytes for Board Info at: %08lx\n", 378: sizeof (bd_t), addr_sp); 379: addr_sp -= sizeof (gd_t); 380: id = (gd_t *) addr_sp; 381: debug ("Reserving %zu Bytes for Global Data at: %08lx\n", 382: sizeof (gd_t), addr_sp); 383: 384: /* setup stackpointer for exeptions */ 385: gd->irq_sp = addr_sp; 386:#ifdef CONFIG_USE_IRQ 387: addr_sp -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ); 388: debug ("Reserving %zu Bytes for IRQ stack at: %08lx\n", 389: CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ, addr_sp); 390:#endif 391: /* leave 3 words for abort-stack */ 392: addr_sp -= 12; 393: 394: /* 8-byte alignment for ABI compliance */ 395: addr_sp &= ~0x07; 396:#else 397: addr_sp += 128; /* leave 32 words for abort-stack */ 398: gd->irq_sp = addr_sp; 399:#endif 第367行的意思为在SDRAM中又开辟了一块malloc空间,该区域是紧挨着上面定义的U-Boot区域的以下。然后在SDRAM中又分别依次定义了bd结构体空间、gd结构体空间和3个字大小的异常中断堆空间。
当中bd结构体的数据原型为bd_t数据结构,它表示的是“板级信息”结构体。这些信息包含开发板的波特率、IP地址、ID、以及DRAM等信息,它是在arch/arm/include/asm文件夹下的u-boot.h文件里定义的。下图具体描写叙述了SDRAM的空间分配情况: 408: gd->bd->bi_baudrate = gd->baudrate; 409: /* Ram ist board specific, so move it to board code ... */ 410: dram_init_banksize(); 411: display_dram_config(); /* and display it */ 412: 413: gd->relocaddr = addr; 414: gd->start_addr_sp = addr_sp; 415: gd->reloc_off = addr - _TEXT_BASE; 上述代码基本的作用是为gd结构体赋值,当中display_dram_config函数的作用是计算SDRAM的大小,并把它通过串口显示在控制台上。
417: memcpy (id, (void *)gd, sizeof (gd_t)); 418: 419: relocate_code (addr_sp, id, addr); 在board_init_f函数的最后是跳转到relocate_code函数体内,这个函数是在arch/arm/cpu/arm920t文件夹下的start.s文件内。也就是说从最開始的start.s跳到board.c,又从board.c跳回到了start.s中,这是由于此时程序须要重定向,即把代码从flash中搬运到ram中,这个过程是须要汇编这个低级语言来完毕的。
传递给relocate_code函数的三个參数分别栈顶地址、数据ID(即全局结构gd)在SDRAM中的起始地址和在SDRAM中存储U-Boot的起始地址。须要注意的是relocate_code函数运行完后,并不会返回到relocate_code (addr_sp, id, addr);的下一条语句继续运行。 以下我们再回到start.s文件: 201: .globl relocate_code 202:relocate_code: 203: mov r4, r0 /* save addr_sp */ 204: mov r5, r1 /* save addr of gd */ 205: mov r6, r2 /* save addr of destination */ 取得三个參数。分别放入寄存器r4、r5和r6。
208:stack_setup: 209: mov sp, r4 设置堆栈地址。 211: adr r0, _start 212: cmp r0, r6 213: beq clear_bss /* skip relocation */ 214: mov r1, r6 /* r1 <- scratch for copy_loop */ 215: ldr r3, _bss_start_ofs 216: add r2, r0, r3 /* r2 <- source end address */ 217: 218:copy_loop: 219: ldmia r0!, {r9-r10} /* copy from source address [r0] */ 220: stmia r1!, {r9-r10} /* copy to target address [r1] */ 221: cmp r0, r2 /* until source end address [r2] */ 222: blo copy_loop 推断U-Boot是在什么位置上,假设在SDRAM中,则直接跳到BSS段清零函数处就可以;假设在FLASH中,则要把U-Boot拷贝到SDRAM中指定的位置处。 224:#ifndef CONFIG_PRELOADER 225: /* 226: * fix .rel.dyn relocations 227: */ 228: ldr r0, _TEXT_BASE /* r0 <- Text base */ 229: sub r9, r6, r0 /* r9 <- relocation offset */ 230: ldr r10, _dynsym_start_ofs /* r10 <- sym table ofs */ 231: add r10, r10, r0 /* r10 <- sym table in FLASH */ 232: ldr r2, _rel_dyn_start_ofs /* r2 <- rel dyn start ofs */ 233: add r2, r2, r0 /* r2 <- rel dyn start in FLASH */ 234: ldr r3, _rel_dyn_end_ofs /* r3 <- rel dyn end ofs */ 235: add r3, r3, r0 /* r3 <- rel dyn end in FLASH */ 236:fixloop: 237: ldr r0, [r2] /* r0 <- location to fix up, IN FLASH! */ 238: add r0, r0, r9 /* r0 <- location to fix up in RAM */ 239: ldr r1, [r2, #4] 240: and r7, r1, #0xff 241: cmp r7, #23 /* relative fixup? */ 242: beq fixrel 243: cmp r7, #2 /* absolute fixup? */ 244: beq fixabs 245: /* ignore unknown type of fixup */ 246: b fixnext 247:fixabs: 248: /* absolute fix: set location to (offset) symbol value */ 249: mov r1, r1, LSR #4 /* r1 <- symbol index in .dynsym */ 250: add r1, r10, r1 /* r1 <- address of symbol in table */ 251: ldr r1, [r1, #4] /* r1 <- symbol value */ 252: add r1, r1, r9 /* r1 <- relocated sym addr */ 253: b fixnext 254:fixrel: 255: /* relative fix: increase location by offset */ 256: ldr r1, [r0] 257: add r1, r1, r9 258:fixnext: 259: str r1, [r0] 260: add r2, r2, #8 /* each rel.dyn entry is 8 bytes */ 261: cmp r2, r3 262: blo fixloop 263:#endif 上述代码的含义是对rel.dyn进行重定向。 265:clear_bss: 266:#ifndef CONFIG_PRELOADER 267: ldr r0, _bss_start_ofs 268: ldr r1, _bss_end_ofs 269: mov r4, r6 /* reloc addr */ 270: add r0, r0, r4 271: add r1, r1, r4 272: mov r2, #0x00000000 /* clear */ 273: 274:clbss_l:str r2, [r0] /* clear loop... */ 275: add r0, r0, #4 276: cmp r0, r1 277: bne clbss_l 278: 279: bl coloured_LED_init 280: bl red_LED_on 281:#endif 对BSS段进行清零的函数。 287:#ifdef CONFIG_NAND_SPL 288: ldr r0, _nand_boot_ofs 289: mov pc, r0 290: 291:_nand_boot_ofs: 292: .word nand_boot 293:#else 294: ldr r0, _board_init_r_ofs 295: adr r1, _start 296: add lr, r0, r1 297: add lr, lr, r9 298: /* setup parameters for board_init_r */ 299: mov r0, r5 /* gd_t */ 300: mov r1, r6 /* dest_addr */ 301: /* jump to it ... */ 302: mov pc, lr 303: 304:_board_init_r_ofs: 305: .word board_init_r - _start 306:#endif 由于未定义CONFIG_NAND_SPL,所以程序是从第294行開始运行。
该段代码的作用是跳转到board_init_r函数。而且给该函数传递了两个參数:全局结构gd在SDRAM中的起始地址和在SDRAM中存储U-Boot的起始地址。board_init_r函数是在arch/arm/lib文件夹下的board.c文件里,也就是又回到了上面运行过的board_init_f函数所在的board.c文件里。
以后。程序就開始在SDRAM中运行了。 以下我们来分析board_init_r函数: 447: gd = id; 448: bd = gd->bd; 449: gd->flags |= GD_FLG_RELOC; /* tell others: relocation done */ 450: 451: monitor_flash_len = _end_ofs; 452: debug ("monitor flash len: %08lX\n", monitor_flash_len); 453: board_init(); /* Setup chipselects */ 上述代码的作用是对gd和bd进行赋值,当中monitor_flash_len为整个U-Boot的长度。 469: /* The Malloc area is immediately below the monitor copy in DRAM */ 470: malloc_start = dest_addr - TOTAL_MALLOC_LEN; 471: mem_malloc_init (malloc_start, TOTAL_MALLOC_LEN); 对SDRAM中的malloc空间进行清零初始化。 473:#if !defined(CONFIG_SYS_NO_FLASH) 474: puts ("Flash: "); 475: 476: if ((flash_size = flash_init ()) > 0) { 477:# ifdef CONFIG_SYS_FLASH_CHECKSUM 478: print_size (flash_size, ""); 479: /* 480: * Compute and print flash CRC if flashchecksum is set to 'y' 481: * 482: * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX 483: */ 484: s = getenv ("flashchecksum"); 485: if (s && (*s == 'y')) { 486: printf (" CRC: %08X", 487: crc32 (0, (const unsigned char *) CONFIG_SYS_FLASH_BASE, flash_size) 488: ); 489: } 490: putc ('\n'); 491:# else /* !CONFIG_SYS_FLASH_CHECKSUM */ 492: print_size (flash_size, "\n"); 493:# endif /* CONFIG_SYS_FLASH_CHECKSUM */ 494: } else { 495: puts (failed); 496: hang (); 497: } 498:#endif 上述代码的作用是计算FLASH的大小,并把它通过串口显示在控制台上。由于未定义CONFIG_SYS_FLASH_CHECKSUM,所以没有运行CRC的校验和。当中flash_init函数是在drivers/mtd文件夹下的cfi_flash.c文件内(由于include/configs/smdk2410.h中定义了CONFIG_FLASH_CFI_DRIVER)。 500:#if defined(CONFIG_CMD_NAND) 501: puts ("NAND: "); 502: nand_init(); /* go init the NAND */ 503:#endif 上述代码的作用是初始化NANDFLASH。并把NANDFLASH的大小通过串口显示在控制台上。当中nand_init函数是在divers/mtd/nand文件夹下的nand.c文件内定义的。 505:#if defined(CONFIG_CMD_ONENAND) 506: onenand_init(); 507:#endif 初始化ONENAND FLASH 519: /* initialize environment */ 520: env_relocate (); 初始化环境变量。由于gd->env_valid等于0。所以在这里设置的是缺省环境变量。env_relocate函数是在common文件夹下的env_common.c文件里定义的。 522:#if defined(CONFIG_CMD_PCI) || defined(CONFIG_PCI) 523: arm_pci_init(); 524:#endif 初始化PCI。 526: /* IP Address */ 527: gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr"); 设置IP地址。 529: stdio_init (); /* get the devices list going. */ 初始化各类外设,如IIC、LCD、键盘、USB等,当然仅仅有在定义了这些外设的前提下,才对这些外设进行初始化。该函数是在common文件夹下的stdio.c文件里定义的。 531: jumptable_init (); 初始化跳转表gd->jt。该跳转表是一个函数指针数组。它定义了U-Boot中基本的经常使用函数库。该函数是在common文件夹下的exports.c文件里定义的。 538: console_init_r (); /* fully init console as a device */ 初始化控制台,即标准输入、标准输出和标准错误,在这里都是串口。该函数是在common文件夹下的console.c文件里定义的。 549: /* set up exceptions */ 550: interrupt_init (); 551: /* enable exceptions */ 552: enable_interrupts (); interrupt_init函数是建立IRQ中断堆栈,enable_interrupts函数是使能IRQ中断,它们都是在arch/arm/lib文件夹下的interrupts.c文件里定义的。
564: /* Initialize from environment */ 565: if ((s = getenv ("loadaddr")) != NULL) { 566: load_addr = simple_strtoul (s, NULL, 16); 567: } 从环境变量中获取loadaddr參数,得到须要载入的地址。
568:#if defined(CONFIG_CMD_NET) 569: if ((s = getenv ("bootfile")) != NULL) { 570: copy_filename (BootFile, s, sizeof (BootFile)); 571: } 572:#endif 从环境变量中获取bootfile參数,得到通过TFTP载入的镜像文件名称。 581:#if defined(CONFIG_CMD_NET) 582:#if defined(CONFIG_NET_MULTI) 583: puts ("Net: "); 584:#endif 585: eth_initialize(gd->bd); 586:#if defined(CONFIG_RESET_PHY_R) 587: debug ("Reset Ethernet PHY\n"); 588: reset_phy(); 589:#endif 590:#endif 上面代码基本的作用是初始化以太网,当中eth_initialize函数是在net文件夹下的eth.c文件的第209行至第298行定义的。 626: /* main_loop() can return to retry autoboot, if so just run it again. */ 627: for (;;) { 628: main_loop (); 629: } board_init_r函数的最后就是运行一个死循环,调用main_loop函数。该函数是在common文件夹下的main.c文件内定义的。 以下我们就来分析main_loop函数 270:#ifndef CONFIG_SYS_HUSH_PARSER 271: static char lastcommand[CONFIG_SYS_CBSIZE] = { 0, }; 272: int len; 273: int rc = 1; 274: int flag; 275:#endif 声明一些hush參数。 277:#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) 278: char *s; 279: int bootdelay; 280:#endif 声明启动延时须要的參数。
320:#ifdef CONFIG_SYS_HUSH_PARSER 321: u_boot_hush_start (); 322:#endif 初始化hush功能。
351:#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) 352: s = getenv ("bootdelay"); 353: bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY; 354: 355: debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay); 356: 357:# ifdef CONFIG_BOOT_RETRY_TIME 358: init_cmd_timeout (); 359:# endif /* CONFIG_BOOT_RETRY_TIME */ 360: 361:#ifdef CONFIG_POST 362: if (gd->flags & GD_FLG_POSTFAIL) { 363: s = getenv("failbootcmd"); 364: } 365: else 366:#endif /* CONFIG_POST */ 367:#ifdef CONFIG_BOOTCOUNT_LIMIT 368: if (bootlimit && (bootcount > bootlimit)) { 369: printf ("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n", 370: (unsigned)bootlimit); 371: s = getenv ("altbootcmd"); 372: } 373: else 374:#endif /* CONFIG_BOOTCOUNT_LIMIT */ 375: s = getenv ("bootcmd"); 376: 377: debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>"); 378: 379: if (bootdelay >= 0 && s && !abortboot (bootdelay)) { 380:# ifdef CONFIG_AUTOBOOT_KEYED 381: int prev = disable_ctrlc(1); /* disable Control C checking */ 382:# endif 383: 384:# ifndef CONFIG_SYS_HUSH_PARSER 385: run_command (s, 0); 386:# else 387: parse_string_outer(s, FLAG_PARSE_SEMICOLON | 388: FLAG_EXIT_FROM_LOOP); 389:# endif 390: 391:# ifdef CONFIG_AUTOBOOT_KEYED 392: disable_ctrlc(prev); /* restore Control C checking */ 393:# endif 394: } 395: 396:# ifdef CONFIG_MENUKEY 397: if (menukey == CONFIG_MENUKEY) { 398: s = getenv("menucmd"); 399: if (s) { 400:# ifndef CONFIG_SYS_HUSH_PARSER 401: run_command (s, 0); 402:# else 403: parse_string_outer(s, FLAG_PARSE_SEMICOLON | 404: FLAG_EXIT_FROM_LOOP); 405:# endif 406: } 407: } 408:#endif /* CONFIG_MENUKEY */ 409:#endif /* CONFIG_BOOTDELAY */ 第352行和第353行的含义是从环境变量中获取bootdelay參数。得到自己主动启动缺省镜像文件的延时(单位是秒)。第358行的含义是初始化命令行超时机制。
第375行的含义是从环境变量中获取bootcmd參数。得到在启动延时过程中自己主动运行的命令。
当我们得到了bootcmd參数。bootdelay參数也是大于等于0,而且在启动延时过程中没有按下随意键时,运行第387行的parse_string_outer函数。该函数的作用是解释bootcmd參数并运行,它是在common文件夹下的hush.c文件内定义的。 414:#ifdef CONFIG_SYS_HUSH_PARSER 415: parse_file_outer(); 416: /* This point is never reached */ 417: for (;;); 418:#else 419: for (;;) { 420:#ifdef CONFIG_BOOT_RETRY_TIME 421: if (rc >= 0) { 422: /* Saw enough of a valid command to 423: * restart the timeout. 424: */ 425: reset_cmd_timeout(); 426: } 427:#endif 428: len = readline (CONFIG_SYS_PROMPT); 429: 430: flag = 0; /* assume no special flags for now */ 431: if (len > 0) 432: strcpy (lastcommand, console_buffer); 433: else if (len == 0) 434: flag |= CMD_FLAG_REPEAT; 435:#ifdef CONFIG_BOOT_RETRY_TIME 436: else if (len == -2) { 437: /* -2 means timed out, retry autoboot 438: */ 439: puts ("\nTimed out waiting for command\n"); 440:# ifdef CONFIG_RESET_TO_RETRY 441: /* Reinit board to run initialization code again */ 442: do_reset (NULL, 0, 0, NULL); 443:# else 444: return; /* retry autoboot */ 445:# endif 446: } 447:#endif 448: 449: if (len == -1) 450: puts ("<INTERRUPT>\n"); 451: else 452: rc = run_command (lastcommand, flag); 453: 454: if (rc <= 0) { 455: /* invalid command or not repeatable, forget it */ 456: lastcommand[0] = 0; 457: } 458: } 459:#endif /*CONFIG_SYS_HUSH_PARSER*/ 由于在include/configs/smdk2410.h文件里定义了CONFIG_SYS_HUSH_PARSER,所以上面的代码仅仅运行的是第415行至第417行的内容。第415行的parse_file_outer函数是在common文件夹下的hush.c文件里定义的,它的含义是依次读取命令序列中的命令并运行之,当中在该函数还调用了parse_stream_outer函数。这个函数体内有一个do-while循环,仅仅有发生语法错误的时候才会跳出该循环,因此普通情况下永远也不会运行上面代码中的第417行内容,而是始终在那个do-while循环体内。
原文地址: