UBOOT之源码分析(X4412)——main_loop函数分析

void main_loop (void)
{

#ifndefCONFIG_SYS_HUSH_PARSER
 
staticchar lastcommand[CONFIG_SYS_CBSIZE] = { 0, };
int len;
int rc= 1;
int flag;
#endif
//
声明一些hush 参数变量

 
#ifdefined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
char*s;
int bootdelay;
#endif

/*uboot启动后会倒计时CONFIG_BOOTDELAY,如果沒有收到用户的输入则自动去执行宏CONFIG_BOOTCOMMAND中设置的命令。这里声明倒计时使用的变量*/

#ifdefCONFIG_SYS_HUSH_PARSER

u_boot_hush_start ();
#endif

//使用hush命令解析器。u_boot_hush_start()common/hush.c中实现

#ifdefCONFIG_AUTO_COMPLETE//自动补全命令,这里未定义使用

install_auto_complete();

#endif

#ifdefined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)

s= getenv ("bootdelay");

bootdelay= s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;

//从环境变量中获取bootdelay参数(倒计时参数),得到自动启动缺省镜像文件的延时(单位是秒)。CONFIG_BOOTDELAYx4412.h中设置为3

debug("### main_loop entered: bootdelay=%d\n\n", bootdelay);

s= getenv ("bootcmd");

//从环境变量中获取bootcmd参数,得到在启动延时过程中自动执行的命令。

debug("### main_loop: bootcmd=\"%s\"\n", s ? s :"");

if(bootdelay >= 0 && s && !abortboot (bootdelay)){//判断延时时间和是否有按键

#ifndef CONFIG_SYS_HUSH_PARSER // 定义

run_command(s, 0);

#else
parse_string_outer(s, FLAG_PARSE_SEMICOLON |
FLAG_EXIT_FROM_LOOP);

#endif
//
当得到了bootcmd参数,bootdelay参数也是大于等于0,并且在启动延时过程中没有按下
//
任意键时,执行parse_string_outer函数,该函数的作用是解释bootcmd参数并执行,它是
//
common目录下的hush.c文件内定义的。

}


#ifdef CONFIG_MENUKEY //未定义

if(menukey == CONFIG_MENUKEY) {
s = getenv("menucmd");
if (s) {
# ifndef CONFIG_SYS_HUSH_PARSER
run_command (s,0);

#else
parse_string_outer(s, FLAG_PARSE_SEMICOLON |
FLAG_EXIT_FROM_LOOP);

#endif

}

}

#endif/* CONFIG_MENUKEY */

#endif/* CONFIG_BOOTDELAY */



/*
* Main Loop for Monitor Command Processing
*/

#ifdefCONFIG_SYS_HUSH_PARSER
parse_file_outer();

/*This point is never reached */

for(;;);

//parse_file_outer函数是在common目录下的hush.c文件中定义的,它的含义是依次读取命令序列中的命令并执行之,其中在该函数还调用了parse_stream_outer函数,这个函数体内有一个do-while环,只有发生语法错误的时候才会跳出该循环,因此一般情况下永远也不会执行for(;;);代码,而是始终在那个do-while循环体内。

#else
for(;;) {

#ifdefCONFIG_BOOT_RETRY_TIME

if(rc >= 0) {

/*Saw enough of a valid command to
* restart the timeout.
*/

reset_cmd_timeout();

}
#endif

len= readline (CONFIG_SYS_PROMPT);
flag = 0; /* assume no specialflags for now */
if (len > 0)
strcpy (lastcommand,console_buffer);
else if (len == 0)
flag |=CMD_FLAG_REPEAT;
#ifdef CONFIG_BOOT_RETRY_TIME
else if (len== -2) {
/* -2 means timed out, retry autoboot
*/

puts("\nTimed out waiting for command\n");

#ifdef CONFIG_RESET_TO_RETRY
/* Reinit board to runinitialization code again */
do_reset (NULL, 0, 0, NULL);
#else
return; /* retry autoboot */
# endif
}
#endif

if(len == -1)

puts("\n");
else
rc = run_command(lastcommand, flag);

if(rc <= 0) {
/* invalid command or not repeatable, forget it*/
lastcommand[0] = 0;
}
}
#endif/*CONFIG_SYS_HUSH_PARSER*/
}

1.abortboot函数的分析
//abortboot
uboot在引导期间的延时函数。期间可以按键进入uboot的命令行。
//common/main.c

static__inline__ int abortboot(int bootdelay)
{
int abort = 0;

#ifdefCONFIG_MENUPROMPT
printf(CONFIG_MENUPROMPT);
#else
printf("Hitany key to stop autoboot: %2d ", bootdelay); //
打印提示信息
#endif

#ifdefined CONFIG_ZERO_BOOTDELAY_CHECK//未定义。
//
如果定义了这个宏,即使定义延时为0,也会检查一次是否有按键按下。只要在
//
这里执行之前按键,还是能进入uboot的命令行。
/*
* Check if key already pressed
* Don't check if bootdelay <0
*/

if(bootdelay >= 0) {
if (tstc()) { /* we got a keypress */
(void) getc(); /* consume input */
puts("\b\b\b 0");
abort = 1; /* don't auto boot */
}
}

#endif

//如果延时大于零并且停止标记没有赋值则进入延时循环,直到延时完或者接收到了按键
while((bootdelay > 0) && (!abort)) {
inti;
--bootdelay;
/* delay 100 * 10ms
每秒中测试按键100次,之后延时10ms*/
for(i=0; !abort && i<100; ++i) {
if (tstc()) { /* wegot a key press */
abort = 1; /* don't auto boot
有键按下修改标识停止自动引导*/
bootdelay= 0; /* no more delay
延时清0*/
#ifdef CONFIG_MENUKEY
menukey = getc();
# else
(void)getc(); /* consume input
获取按键*/
#endif
break;
}
udelay(10000);//
延时10000us,也就是10ms
}
printf("\b\b\b%2d", bootdelay); //
打印当前剩余时间
}

putc('\n');

#ifdefCONFIG_SILENT_CONSOLE //未定义

if(abort)

gd->flags&= ~GD_FLG_SILENT;

#endif

returnabort; //返回结果:1-停止引导,进入命令行;0-引导内核。

}
//
可以看到uboot延时的单位是秒,如果想提高延时的精度,比如想进行10ms级的延时,将
//udelay(10000
)改为udelay(100)就可以了。

2.引导命令s= getenv ("bootcmd");引导命令定义在include/configs/x4412.h

/*
* BOOTP options
*/
#define CONFIG_BOOTP_SUBNETMASK
#defineCONFIG_BOOTP_GATEWAY
#define CONFIG_BOOTP_HOSTNAME
#defineCONFIG_BOOTP_BOOTPATH

#defineCONFIG_ETHADDR 00:40:5c:26:0a:5b
#define CONFIG_NETMASK 255.255.255.0
#define CONFIG_IPADDR 192.168.0.20
#defineCONFIG_SERVERIP 192.168.0.10
#defineCONFIG_GATEWAYIP 192.168.0.1

/*uboot启动后会倒计时CONFIG_BOOTDELAY,如果沒有收到用户的输入则自动去执行宏CONFIG_BOOTCOMMAND中设置的命令*/

#defineCONFIG_BOOTDELAY 3
/* Default boot commands for Android booting.*/
#define CONFIG_BOOTCOMMAND "movi read kernel 040008000;movi read rootfs 0 41000000 400000;bootm 40008000 41000000"

#defineCONFIG_BOOTARGS "lcd=vs070cxn tp=ft5x06-1024x600 cam=ov2655mac=00:09:c0:ff:ee:58"

#defineCONFIG_BOOTARGS_QT"root=/dev/mmcblk0p2 rw rootfstype=ext4lcd=vs070cxn tp=ft5x06-1024x600 cam=ov2655 mac=00:09:c0:ff:ee:58"

#defineCONFIG_BOOTCOMMAND2 "fdisk -c 0;sdfuse flashall;reset"
#defineCONFIG_BOOTCOMMAND3 "ext3format mmc 0:3;ext3format mmc0:4;" \
"movi read kernel 0 40008000;movi readrootfs 0 41000000 100000;bootm 40008000 41000000"

#defineCONFIG_BOOTCOMMAND_QT "movi read kernel 0 40008000;bootm40008000"

//*
可见,引导内核其实就是将内核读取到内存中然后再跳到那个地方引导.

CONFIG_BOOTARGS_QTCONFIG_BOOTCOMMAND_QTLINUX内核QT文件系统环境变量。
CONFIG_BOOTCOMMAND
CONFIG_BOOTARGSlinux内核android环境变量。
bootargs=lcd=vs070cxntp=ft5x06-1024x600 cam=ov2655 mac=00:09:c0:ff:ee:58
bootcmd=moviread kernel 0 40008000;movi read rootfs 0 41000000 400000;bootm40008000 41000000


CONFIG_BOOTCOMMAND2MMC分区,SD烧录,重启命令。这个命令在board_late_init()函数中使用,下面将作介绍。

CONFIG_BOOTCOMMAND3MMC格式化命令,暂未实现。

*/


3.第二阶段板子初始化函数board_late_init()函数在board/samsung/x4212/x4212.c中。此函数由第二阶段板级初始化函数调用。

int board_late_init (void)

{

#ifdefCONFIG_UPDATE_SOLUTION

GPIO_Init();//GPIO引脚初始化

GPIO_SetFunctionEach(eGPIO_X1,eGPIO_0, 0); //设置开发板左按键IO口输入

GPIO_SetPullUpDownEach(eGPIO_X1,eGPIO_0, 0);//关闭左按键IO口上下拉

udelay(10);

if(GPIO_GetDataEach(eGPIO_X1, eGPIO_0) == 0)//判断左按键是否按下

{

puts("LEFT MODE:[DOWN]\n");

setenv("bootcmd", CONFIG_BOOTCOMMAND2); //左按键按下,从SD卡烧写文件

}

else

puts("LEFT MODE:[UP]\n");

#endif

return0;

}

//也就是说,通过SD卡烧录从这个地方进入
 

4.parse_string_outer()函数在common/hush.c中实现

#ifndef__U_BOOT__

staticint parse_string_outer(const char *s, int flag)

#else

intparse_string_outer(char *s, int flag)

#endif /*__U_BOOT__ */

{

structin_str input;

#ifdef__U_BOOT__

char*p = NULL;

intrcode;

if( !s || !*s)

return1;

if(!(p = strchr(s, '\n')) || *++p) {

p= xmalloc(strlen(s) + 2);

strcpy(p,s);

strcat(p,"\n");

setup_string_in_str(&input,p);

rcode= parse_stream_outer(&input, flag);

free(p);

returnrcode;

}else {

#endif

setup_string_in_str(&input,s);

returnparse_stream_outer(&input, flag);

#ifdef__U_BOOT__

}

#endif

}

你可能感兴趣的:(linux内核,ARM,u-boot)