加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

u-boot-2011.09在ST2410上启动流程分析

发布时间:2020-12-15 06:28:52 所属栏目:百科 来源:网络整理
导读:u-boot-2011.09在ST2410上启动流程分析 作者:mutes u-boot版本:u-boot-2011.09 分析时间:2011.10.26 源码下载地址:ftp://ftp.denx.de/pub/u-boot/u-boot-2011.09.tar.bz2 参考文献:http://www.linuxidc.com/Linux/2011-07/39310.htm?(源于该文件修改)
u-boot-2011.09在ST2410上启动流程分析

作者:mutes


u-boot版本:u-boot-2011.09
分析时间:2011.10.26

源码下载地址:ftp://ftp.denx.de/pub/u-boot/u-boot-2011.09.tar.bz2
参考文献:http://www.linuxidc.com/Linux/2011-07/39310.htm?(源于该文件修改)

?????? u-boot支持许多CPU,以及一些常见的开发板。在前面的文章中已经对u-boot1.1.6作了详细的分析,在本文以u-boot-2011.09这个最新版本为例,再来简要介绍一下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,#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????? /* Interrupt-Controller base addresses */
146 #? define CLKDIVN?????? 0x14800014????? /* clock divisor register */
147 #else
148 #? define pWTCON??????? 0x53000000
149 #? define INTMSK??????? 0x4A000008????? /* Interrupt-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函数。

269???????? /* Pointer is writable since we allocated a register for it */
270???????? gd = (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07);
271???????? /* compiler optimization barrier needed for GCC >= 3.4 */
272???????? __asm__ __volatile__("": : :"memory");
273?
274???????? memset((void *)gd,sizeof(gd_t));
275?
276???????? gd->mon_len = _bss_end_ofs;
277?
gd是一个保存在ARM的r8寄存器中的gd_t结构体的指针,该结构体包括了u-boot中所有重要的全局变量,它是在arch/arm/include/asm目录下的global_data.h文件内被定义的。上述代码的作用是为gd分配地址,并清零,最后得到整个u-boot的长度。

278???????? for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
279???????????????? if ((*init_fnc_ptr)() != 0) {
280???????????????????????? hang ();
281???????????????? }
282???????? }

上述代码的作用是循环调用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的大小。

?

303???????? addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size;

得到SDRAM的末位物理地址为0x3400 0000,即SDRAM的空间分布为0x3000 0000~0x33FF FFFF。

325 #if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
326???????? /* reserve TLB table */
327???????? addr -= (4096 * 4);
328?
329???????? /* round down to next 64 kB limit */
330???????? addr &= ~(0x10000 - 1);
331?
332???????? gd->tlb_addr = addr;
333???????? debug("TLB table at: %08lxn",addr);
334 #endif
335?
336???????? /* round down to next 4 kB limit */
337???????? addr &= ~(4096 - 1);
338???????? debug("Top of RAM usable for U-Boot at: %08lxn",addr);

分配SDRAM的高64kB区域作为TLB,即0x33FF 0000~0x33FF FFFF,并且该区域也被用于U-Boot。

350???????? /*
351????????? * reserve memory for U-Boot code,data & bss
352????????? * round down to next 4 kB limit
353????????? */
354???????? addr -= gd->mon_len;
355???????? addr &= ~(4096 - 1);
356?
357???????? debug("Reserving %ldk for U-Boot at: %08lxn",gd->mon_len >> 10,addr);
分配SDRAM的下一个单元为U-Boot代码段、数据段及BSS段。

359 #ifndef CONFIG_SPL_BUILD
360???????? /*
361????????? * reserve memory for malloc() arena
362????????? */
363???????? addr_sp = addr - TOTAL_MALLOC_LEN;
364???????? debug("Reserving %dk for malloc() at: %08lxn",
365???????????????????????? TOTAL_MALLOC_LEN >> 10,addr_sp);
366???????? /*
367????????? * (permanently) allocate a Board Info struct
368????????? * and a permanent copy of the "global" data
369????????? */
370???????? addr_sp -= sizeof (bd_t);
371???????? bd = (bd_t *) addr_sp;
372???????? gd->bd = bd;
373???????? debug("Reserving %zu Bytes for Board Info at: %08lxn",
374???????????????????????? sizeof (bd_t),addr_sp);
375?
376 #ifdef CONFIG_MACH_TYPE
377???????? gd->bd->bi_arch_number = CONFIG_MACH_TYPE; /* board id for Linux */
378 #endif
379?
380???????? addr_sp -= sizeof (gd_t);
381???????? id = (gd_t *) addr_sp;
382???????? debug("Reserving %zu Bytes for Global Data at: %08lxn",
383???????????????????????? sizeof (gd_t),addr_sp);
384?
385???????? /* setup stackpointer for exeptions */
386???????? gd->irq_sp = addr_sp;
387 #ifdef CONFIG_USE_IRQ
388???????? addr_sp -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ);
389???????? debug("Reserving %zu Bytes for IRQ stack at: %08lxn",
390???????????????? CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ,addr_sp);
391 #endif
392???????? /* leave 3 words for abort-stack??? */
393???????? addr_sp -= 12;
394?
395???????? /* 8-byte alignment for ABI compliance */
396???????? addr_sp &= ~0x07;
397 #else
398???????? addr_sp += 128; /* leave 32 words for abort-stack?? */
399???????? gd->irq_sp = addr_sp;
400 #endif

401?
402???????? debug("New Stack Pointer is: %08lxn",addr_sp);

第363行的意思为在SDRAM中又开辟了一块malloc空间,该区域是紧挨着上面定义的U-Boot区域的下面。然后在SDRAM中又分别依次定义了bd结构体空间、gd结构体空间和3个字大小的异常中断堆空间。其中bd结构体的数据原型为bd_t数据结构,它表示的是“板级信息”结构体,这些信息包括开发板的波特率、IP地址、ID、以及DRAM等信息,它是在arch/arm/include/asm目录下的u-boot.h文件中定义的。下图详细描述了SDRAM的空间分配情况:

409???????? gd->bd->bi_baudrate = gd->baudrate;
410???????? /* Ram ist board specific,so move it to board code ... */
411???????? dram_init_banksize();
412???????? display_dram_config();? /* and display it */
413?
414???????? gd->relocaddr = addr;
415???????? gd->start_addr_sp = addr_sp;
416???????? gd->reloc_off = addr - _TEXT_BASE;
417???????? debug("relocation Offset is: %08lxn",gd->reloc_off);

上述代码主要的作用是为gd结构体赋值,其中display_dram_config函数的作用是计算SDRAM的大小,并把它通过串口显示在控制台上。

418???????? memcpy(id,(void *)gd,sizeof(gd_t));
419?
420???????? 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,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,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_SPL_BUILD
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,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,LSR #4????????? /* r1 <- symbol index in .dynsym */
250???????? add???? r1,r1???????????? /* r1 <- address of symbol in table */
251???????? ldr???? r1,[r1,#4]??????????? /* r1 <- symbol value */
252???????? add???? 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,r9
258 fixnext:
259???????? str???? r1,[r0]
260???????? add???? 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_SPL_BUILD
267???????? ldr???? r0,_bss_start_ofs
268???????? ldr???? r1,_bss_end_ofs
269???????? mov???? r4,r6????????????????? /* reloc addr */
270???????? add???? r0,r4
271???????? add???? r1,r4
272???????? mov???? r2,#0x00000000???????? /* clear??????????????????????????? */
273?
274 clbss_l:str???? r2,[r0]??????????????? /* clear loop...??????????????????? */
275???????? add???? 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,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函数:

440 void board_init_r(gd_t *id,ulong dest_addr)
441 {
442???????? char *s;
443???????? bd_t *bd;
444???????? ulong malloc_start;
445 #if !defined(CONFIG_SYS_NO_FLASH)
446???????? ulong flash_size;
447 #endif
448?
449???????? gd = id;
450???????? bd = gd->bd;
451?
452???????? gd->flags |= GD_FLG_RELOC;????? /* tell others: relocation done */
453?
454???????? monitor_flash_len = _end_ofs;
455?
456???????? /* Enable caches */
457???????? enable_caches();
458?
459???????? debug("monitor flash len: %08lXn",monitor_flash_len);
460???????? board_init();?? /* Setup chipselects */
461

上述代码的作用是对gd和bd进行赋值,其中monitor_flash_len为整个U-Boot的长度。

474?
475???????? /* The Malloc area is immediately below the monitor copy in DRAM */
476???????? malloc_start = dest_addr - TOTAL_MALLOC_LEN;
477???????? mem_malloc_init (malloc_start,TOTAL_MALLOC_LEN);
对SDRAM中的malloc空间进行清零初始化。

479 #if !defined(CONFIG_SYS_NO_FLASH)
480???????? puts("Flash: ");
481?
482???????? flash_size = flash_init();
483???????? if (flash_size > 0) {
484 # ifdef CONFIG_SYS_FLASH_CHECKSUM
485???????????????? print_size(flash_size,"");
486???????????????? /*
487????????????????? * Compute and print flash CRC if flashchecksum is set to 'y'
488????????????????? *
489????????????????? * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
490????????????????? */
491???????????????? s = getenv("flashchecksum");
492???????????????? if (s && (*s == 'y')) {
493???????????????????????? printf("? CRC: %08X",crc32(0,
494???????????????????????????????? (const unsigned char *) CONFIG_SYS_FLASH_BASE,
495???????????????????????????????? flash_size));
496???????????????? }
497???????????????? putc('n');
498 # else? /* !CONFIG_SYS_FLASH_CHECKSUM */
499???????????????? print_size(flash_size,"n");
500 # endif /* CONFIG_SYS_FLASH_CHECKSUM */

501???????? } else {
502???????????????? puts(failed);
503???????????????? hang();
504???????? }
505 #endif

?上述代码的作用是计算FLASH的大小,并把它通过串口显示在控制台上。由于没有定义CONFIG_SYS_FLASH_CHECKSUM,所以没有执行CRC的校验和。其中flash_init函数是在drivers/mtd目录下的cfi_flash.c文件内(因为include/configs/smdk2410.h中定义了CONFIG_FLASH_CFI_DRIVER)。

507 #if defined(CONFIG_CMD_NAND)
508???????? puts("NAND:? ");
509???????? nand_init();??????????? /* go init the NAND */
510 #endif

上述代码的作用是初始化NANDFLASH,并把NANDFLASH的大小通过串口显示在控制台上。其中nand_init函数是在divers/mtd/nand目录下的nand.c文件内定义的。

512 #if defined(CONFIG_CMD_ONENAND)
513???????? onenand_init();
514 #endif

初始化ONENAND FLASH

526???????? /* initialize environment */
527???????? env_relocate();

初始化环境变量,由于gd->env_valid等于0,所以在这里设置的是缺省环境变量。env_relocate函数是在common目录下的env_common.c文件中定义的。

529 #if defined(CONFIG_CMD_PCI) || defined(CONFIG_PCI)
530???????? arm_pci_init();
531 #endif

初始化PCI。
532?
533???????? /* IP Address */
534???????? gd->bd->bi_ip_addr = getenv_IPaddr("ipaddr");? 设置IP地址。
535

536???????? stdio_init();?? /* get the devices list going. */

初始化各类外设,如IIC、LCD、键盘、USB等,当然只有在定义了这些外设的前提下,才对这些外设进行初始化。该函数是在common目录下的stdio.c文件中定义的。

537?
538???????? jumptable_init();

初始化跳转表gd->jt,该跳转表是一个函数指针数组,它定义了U-Boot中基本的常用函数库。该函数是在common目录下的exports.c文件中定义的。

545???????? console_init_r();?????? /* fully init console as a device */

初始化控制台,即标准输入、标准输出和标准错误,在这里都是串口。该函数是在common目录下的console.c文件中定义的。
546?
547 #if defined(CONFIG_ARCH_MISC_INIT)
548???????? /* miscellaneous arch dependent initialisations */
549???????? arch_misc_init();
550 #endif
551 #if defined(CONFIG_MISC_INIT_R)
552???????? /* miscellaneous platform dependent initialisations */
553???????? misc_init_r();
554 #endif
555?
556????????? /* set up exceptions */
557???????? interrupt_init();
558???????? /* enable exceptions */
559???????? enable_interrupts();

interrupt_init函数是建立IRQ中断堆栈,enable_interrupts函数是使能IRQ中断,它们都是在arch/arm/lib目录下的interrupts.c文件中定义的。

571???????? /* Initialize from environment */
572???????? s = getenv("loadaddr");
573???????? if (s != NULL)
574???????????????? load_addr = simple_strtoul(s,NULL,16);

从环境变量中获取loadaddr参数,得到需要加载的地址。
575 #if defined(CONFIG_CMD_NET)

576???????? s = getenv("bootfile");
577???????? if (s != NULL)
578???????????????? copy_filename(BootFile,s,sizeof(BootFile));
579 #endif

从环境变量中获取bootfile参数,得到通过TFTP加载的镜像文件名。

589 #if defined(CONFIG_NET_MULTI)
590???????? puts("Net:?? ");
591 #endif
592???????? eth_initialize(gd->bd);
593 #if defined(CONFIG_RESET_PHY_R)
594???????? debug("Reset Ethernet PHYn");
595???????? reset_phy();
596 #endif
597 #endif

上面代码主要的作用是初始化以太网,其中eth_initialize函数是在net目录下的eth.c文件的第209行至第298行定义的。
633???????? /* main_loop() can return to retry autoboot,if so just run it again. */
634???????? for (;;) {
635???????????????? main_loop();
636???????? }

board_init_r函数的最后就是执行一个死循环,调用main_loop函数。该函数是在common目录下的main.c文件内定义的。

?

下面我们就来分析main_loop函数

?265 void main_loop (void)
?266 {
?267 #ifndef CONFIG_SYS_HUSH_PARSER
?268???????? static char lastcommand[CONFIG_SYS_CBSIZE] = { 0,};
?269???????? int len;
?270???????? int rc = 1;
?271???????? int flag;
?272 #endif

?声明一些hush参数。

?274 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
?275???????? char *s;
?276???????? int bootdelay;
?277 #endif

声明启动延时需要的参数。

?315 #ifdef CONFIG_SYS_HUSH_PARSER
?316???????? u_boot_hush_start ();
?317 #endif

初始化hush功能。

?346 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
?347???????? s = getenv ("bootdelay");
?348???????? bootdelay = s ? (int)simple_strtol(s,10) : CONFIG_BOOTDELAY;
?349?
?350???????? debug ("### main_loop entered: bootdelay=%dnn",bootdelay);
?351?
?352 # ifdef CONFIG_BOOT_RETRY_TIME
?353???????? init_cmd_timeout ();
?354 # endif /* CONFIG_BOOT_RETRY_TIME */
?355?
?356 #ifdef CONFIG_POST
?357???????? if (gd->flags & GD_FLG_POSTFAIL) {
?358???????????????? s = getenv("failbootcmd");
?359???????? }
?360???????? else
?361 #endif /* CONFIG_POST */
?362 #ifdef CONFIG_BOOTCOUNT_LIMIT
?363???????? if (bootlimit && (bootcount > bootlimit)) {
?364???????????????? printf ("Warning: Bootlimit (%u) exceeded. Using altbootcmd.n",
?365???????????????????????? (unsigned)bootlimit);
?366???????????????? s = getenv ("altbootcmd");
?367???????? }

?368???????? else
?369 #endif /* CONFIG_BOOTCOUNT_LIMIT */
?370???????????????? s = getenv ("bootcmd");
?371?
?372???????? debug ("### main_loop: bootcmd="%s"n",s ? s : "<UNDEFINED>");
?373?
?374???????? if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
?375 # ifdef CONFIG_AUTOBOOT_KEYED
?376???????????????? int prev = disable_ctrlc(1);??? /* disable Control C checking */
?377 # endif
?378?
?379 # ifndef CONFIG_SYS_HUSH_PARSER
?380???????????????? run_command (s,0);
?381 # else
?382???????????????? parse_string_outer(s,FLAG_PARSE_SEMICOLON |
?383???????????????????????????????????? FLAG_EXIT_FROM_LOOP);
?384 # endif
?385?
?386 # ifdef CONFIG_AUTOBOOT_KEYED
?387???????????????? disable_ctrlc(prev);??? /* restore Control C checking */
?388 # endif
?389???????? }

第347行和第348行的含义是从环境变量中获取bootdelay参数,得到自动启动缺省镜像文件的延时(单位是秒)。第353行的含义是初始化命令行超时机制。第370行的含义是从环境变量中获取bootcmd参数,得到在启动延时过程中自动执行的命令。当我们得到了bootcmd参数,bootdelay参数也是大于等于0,并且在启动延时过程中没有按下任意键时,执行第382行的parse_string_outer函数,该函数的作用是解释bootcmd参数并执行,它是在common目录下的hush.c文件内定义的。

?409 #ifdef CONFIG_SYS_HUSH_PARSER
?410???????? parse_file_outer();
?411???????? /* This point is never reached */
?412???????? for (;;);
?413 #else
?414???????? for (;;) {
?415 #ifdef CONFIG_BOOT_RETRY_TIME
?416???????????????? if (rc >= 0) {
?417???????????????????????? /* Saw enough of a valid command to
?418????????????????????????? * restart the timeout.
?419????????????????????????? */
?420???????????????????????? reset_cmd_timeout();
?421???????????????? }
?422 #endif
?423???????????????? len = readline (CONFIG_SYS_PROMPT);
?424?
?425???????????????? flag = 0;?????? /* assume no special flags for now */
?426???????????????? if (len > 0)
?427???????????????????????? strcpy (lastcommand,console_buffer);
?428???????????????? else if (len == 0)
?429???????????????????????? flag |= CMD_FLAG_REPEAT;
?430 #ifdef CONFIG_BOOT_RETRY_TIME

?431???????????????? else if (len == -2) {
?432???????????????????????? /* -2 means timed out,retry autoboot
?433????????????????????????? */
?434???????????????????????? puts ("nTimed out waiting for commandn");
?435 # ifdef CONFIG_RESET_TO_RETRY
?436???????????????????????? /* Reinit board to run initialization code again */
?437???????????????????????? do_reset (NULL,NULL);
?438 # else
?439???????????????????????? return;???????? /* retry autoboot */
?440 # endif
?441???????????????? }
?442 #endif
?443?
?444???????????????? if (len == -1)
?445???????????????????????? puts ("<INTERRUPT>n");
?446???????????????? else
?447???????????????????????? rc = run_command (lastcommand,flag);
?448?
?449???????????????? if (rc <= 0) {
?450???????????????????????? /* invalid command or not repeatable,forget it */
?451???????????????????????? lastcommand[0] = 0;
?452???????????????? }
?453???????? }

?454 #endif /*CONFIG_SYS_HUSH_PARSER*/
?455 }

由于在include/configs/smdk2410.h文件中定义了CONFIG_SYS_HUSH_PARSER,所以上面的代码仅仅执行的是第410行至第412行的内容。第410行的parse_file_outer函数是在common目录下的hush.c文件中定义的,它的含义是依次读取命令序列中的命令并执行之,其中在该函数还调用了parse_stream_outer函数,这个函数体内有一个do-while循环,只有发生语法错误的时候才会跳出该循环,因此一般情况下永远也不会执行上面代码中的第412行内容,而是始终在那个do-while循环体内。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读