UBOOT代碼分析 (2011.06版)

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

發佈了10 篇原創文章 · 獲贊 4 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章