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循環體內。