super man的笔记 https://bbs.21ic.com/?228812 [收藏] [复制] [RSS] 2012期待龙子的诞生

日志

转赵春江老师的u-boot-2011.06启动流程分析

已有 1590 次阅读2012-3-28 05:44 |系统分类:嵌入式系统| u-boot, 流程

 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循环体内。


路过

鸡蛋

鲜花

握手

雷人

评论 (0 个评论)