1> main_loop  common/main.c

/****************************************************************************/

void main_loop (void)
{
#ifndef CONFIG_SYS_HUSH_PARSER
static char lastcommand[CONFIG_SYS_CBSIZE] = { , };
int len;
int rc = ;
int flag;
#endif #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
char *s;
int bootdelay;
#endif
#ifdef CONFIG_PREBOOT
char *p;
#endif
#ifdef CONFIG_BOOTCOUNT_LIMIT
unsigned long bootcount = ;
unsigned long bootlimit = ;
char *bcs;
char bcs_set[];
#endif /* CONFIG_BOOTCOUNT_LIMIT */ #if defined(CONFIG_VFD) && defined(VFD_TEST_LOGO)
ulong bmp = ; /* default bitmap */
extern int trab_vfd (ulong bitmap); #ifdef CONFIG_MODEM_SUPPORT
if (do_mdm_init)
bmp = ; /* alternate bitmap */
#endif
trab_vfd (bmp);
#endif /* CONFIG_VFD && VFD_TEST_LOGO */ #ifdef CONFIG_BOOTCOUNT_LIMIT
bootcount = bootcount_load();
bootcount++;
bootcount_store (bootcount);
sprintf (bcs_set, "%lu", bootcount);
setenv ("bootcount", bcs_set);
bcs = getenv ("bootlimit");
bootlimit = bcs ? simple_strtoul (bcs, NULL, ) : ;
#endif /* CONFIG_BOOTCOUNT_LIMIT */ #ifdef CONFIG_MODEM_SUPPORT
debug ("DEBUG: main_loop: do_mdm_init=%d\n", do_mdm_init);
if (do_mdm_init) {
char *str = strdup(getenv("mdm_cmd"));
setenv ("preboot", str); /* set or delete definition */
if (str != NULL)
free (str);
mdm_init(); /* wait for modem connection */
}
#endif /* CONFIG_MODEM_SUPPORT */ #ifdef CONFIG_VERSION_VARIABLE
{
extern char version_string[]; setenv ("ver", version_string); /* set version variable */
}
#endif /* CONFIG_VERSION_VARIABLE */ #ifdef CONFIG_SYS_HUSH_PARSER
u_boot_hush_start ();
#endif #if defined(CONFIG_HUSH_INIT_VAR)
hush_init_var ();
#endif #ifdef CONFIG_AUTO_COMPLETE
install_auto_complete(); //安装自动补全的函数,分析如下
#endif #ifdef CONFIG_PREBOOT
if ((p = getenv ("preboot")) != NULL) {
# ifdef CONFIG_AUTOBOOT_KEYED
int prev = disable_ctrlc(); /* disable Control C checking */
# endif # ifndef CONFIG_SYS_HUSH_PARSER
run_command (p, );
# else
parse_string_outer(p, FLAG_PARSE_SEMICOLON |
FLAG_EXIT_FROM_LOOP);
# endif # ifdef CONFIG_AUTOBOOT_KEYED
disable_ctrlc(prev); /* restore Control C checking */
# endif
}
#endif /* CONFIG_PREBOOT */ #if defined(CONFIG_UPDATE_TFTP)
update_tftp ();
#endif /* CONFIG_UPDATE_TFTP */ #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
s = getenv ("bootdelay");
bootdelay = s ? (int)simple_strtol(s, NULL, ) : CONFIG_BOOTDELAY; debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay); # ifdef CONFIG_BOOT_RETRY_TIME
init_cmd_timeout ();
# endif /* CONFIG_BOOT_RETRY_TIME */ #ifdef CONFIG_POST
if (gd->flags & GD_FLG_POSTFAIL) {
s = getenv("failbootcmd");
}
else
#endif /* CONFIG_POST */
#ifdef CONFIG_BOOTCOUNT_LIMIT
if (bootlimit && (bootcount > bootlimit)) {
printf ("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n",
(unsigned)bootlimit);
s = getenv ("altbootcmd");
}
else
#endif /* CONFIG_BOOTCOUNT_LIMIT */
s = getenv ("bootcmd"); //获取引导命令。分析见下面。 debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>"); if (bootdelay >= && s && !abortboot (bootdelay)) {
//如果延时大于等于零,并且没有在延时过程中接收到按键,则引导内核。abortboot函数的分析见下面。
# ifdef CONFIG_AUTOBOOT_KEYED
int prev = disable_ctrlc(); /* disable Control C checking */
# endif # ifndef CONFIG_SYS_HUSH_PARSER
run_command (s, );//运行引导内核的命令。这个命令是在配置头文件中定义的。run_command的分析在下面。
# else
parse_string_outer(s, FLAG_PARSE_SEMICOLON |
FLAG_EXIT_FROM_LOOP);
# endif # ifdef CONFIG_AUTOBOOT_KEYED
disable_ctrlc(prev); /* restore Control C checking */
# endif
} # ifdef CONFIG_MENUKEY
if (menukey == CONFIG_MENUKEY) {
s = getenv("menucmd");
if (s) {
# ifndef CONFIG_SYS_HUSH_PARSER
run_command (s, );
# else
parse_string_outer(s, FLAG_PARSE_SEMICOLON |
FLAG_EXIT_FROM_LOOP);
# endif
}
}
#endif /* CONFIG_MENUKEY */
#endif /* CONFIG_BOOTDELAY */ #ifdef CONFIG_AMIGAONEG3SE
{
extern void video_banner(void);
video_banner();
}
#endif /*
* Main Loop for Monitor Command Processing
*/
#ifdef CONFIG_SYS_HUSH_PARSER
parse_file_outer();
/* This point is never reached */
for (;;);
#else
for (;;) {
#ifdef CONFIG_BOOT_RETRY_TIME
if (rc >= ) {
/* Saw enough of a valid command to
* restart the timeout.
*/
reset_cmd_timeout();
}
#endif
len = readline (CONFIG_SYS_PROMPT); //CONFIG_SYS_PROMPT的意思是回显字符,一般是“>”。这是由配置头文件定义的
flag = ; /* assume no special flags for now */
if (len > )
strcpy (lastcommand, console_buffer); //保存输入的数据。
else if (len == )
flag |= CMD_FLAG_REPEAT; ;//如果输入数据为零,则重复执行上次的命令,如果上次输入的是一个命令的话
#ifdef CONFIG_BOOT_RETRY_TIME
else if (len == -) {
/* -2 means timed out, retry autoboot
*/
puts ("\nTimed out waiting for command\n");
# ifdef CONFIG_RESET_TO_RETRY
/* Reinit board to run initialization code again */
do_reset (NULL, , , NULL);
# else
return; /* retry autoboot */
# endif
}
#endif if (len == -)
puts ("<INTERRUPT>\n");
else
rc = run_command (lastcommand, flag); //执行命令 if (rc <= ) {//执行失败,则清空记录
/* invalid command or not repeatable, forget it */
lastcommand[] = ;
}
}
#endif /*CONFIG_SYS_HUSH_PARSER*/
}

2> 自动补全

int var_complete(int argc, char *argv[], char last_char, int maxv, char *cmdv[])
{
static char tmp_buf[];
int space; space = last_char == '\0' || last_char == ' ' || last_char == '\t'; if (space && argc == )
return env_complete("", maxv, cmdv, sizeof(tmp_buf), tmp_buf); if (!space && argc == )
return env_complete(argv[], maxv, cmdv, sizeof(tmp_buf), tmp_buf); return ;
} static void install_auto_complete_handler(const char *cmd,
int (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]))
{
cmd_tbl_t *cmdtp; cmdtp = find_cmd(cmd);
if (cmdtp == NULL)
return; cmdtp->complete = complete; //命令结构体的complete指针指向传入的函数。
} void install_auto_complete(void)
{
#if defined(CONFIG_CMD_EDITENV)
install_auto_complete_handler("editenv", var_complete);
#endif
install_auto_complete_handler("printenv", var_complete);
install_auto_complete_handler("setenv", var_complete);
#if defined(CONFIG_CMD_RUN)
install_auto_complete_handler("run", var_complete);
#endif
}

可以看到将editenv、printenv、setenv和run的自动补全函数安装为 var_complete。var_complete的功能是根据给出的前缀字符串,找出所有前缀相同的命令。

每个命令在内存中用一个cmd_tbl_t 表示。include/command.h

struct cmd_tbl_s {
char *name; /* 命令名,输入的就是它 */
int maxargs; /* 最大参数个数 */
int repeatable; /* 允许自动重发,也就是在按下空格键之后执行最后一条命令。 */ int (*cmd)(struct cmd_tbl_s *, int, int, char *[]); /* 实现命令的参数 */
char *usage; /* 短的提示信息 */
#ifdef CONFIG_SYS_LONGHELP
char *help; /* 详细的帮助信息。 */
#endif
#ifdef CONFIG__AUTO_COMPLETE
/* do auto completion on the arguments */
int (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]);
#endif
}; typedef struct cmd_tbl_s cmd_tbl_t; extern cmd_tbl_t __u_boot_cmd_start;
extern cmd_tbl_t __u_boot_cmd_end; #define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) /
cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help} #define U_BOOT_CMD_MKENT(name,maxargs,rep,cmd,usage,help) /
{#name, maxargs, rep, cmd, usage, help} /*uboot中的命令使用U_BOOT_CMD这个宏声明来注册进系统,链接脚本会把所有的cmd_tbl_t结构体放在相邻的地方。
链接脚本中的一些内容如下: */
. = .;
__u_boot_cmd_start = .;
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;
/*可见,__u_boot_cmd_start 和__u_boot_cmd_end 分别对应命令结构体在内存中开始和结束的地址。 */

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

static __inline__ int abortboot(int bootdelay)
{
int abort = ; #ifdef CONFIG_MENUPROMPT
printf(CONFIG_MENUPROMPT);
#else
printf("Hit any key to stop autoboot: %2d ", bootdelay);
#endif #if defined CONFIG_ZERO_BOOTDELAY_CHECK
//如果定义了这个宏,即使定义延时为0,也会检查一次是否有按键按下。
//只要在这里执行之前按键,还是能进入uboot的命令行。
/*
* Check if key already pressed
* Don't check if bootdelay < 0
*/
if (bootdelay >= ) {
if (tstc()) { // 测试是否有按键按下
(void) getc(); //接收按键值
puts ("\b\b\b 0");
abort = ; //修改标记,停止自动引导
}
}
#endif while ((bootdelay > ) && (!abort)) {
//如果延时大于零并且停止标记没有赋值则进入延时循环,直到延时完或者接收到了按 键
int i; --bootdelay;
/* delay 100 * 10ms */
//每秒中测试按键100次,之后延时10ms。
for (i=; !abort && i<; ++i) {
if (tstc()) { /* we got a key press */
abort = ; //修改标记,停止自动引导
bootdelay = ; //延时归零
# ifdef CONFIG_MENUKEY
menukey = getc();
# else
(void) getc(); /* 获取按键*/
# endif
break;
}
udelay(); //延时10000us,也就是10ms
} printf("\b\b\b%2d ", bootdelay);//打印当前剩余时间
//可以看到uboot延时的单位是秒,如果想提高延时的精度,
//比如想进行10ms级的延时,将udelay(10000)改为udelay(100)就可以了 。 } putc('\n'); #ifdef CONFIG_SILENT_CONSOLE
if (abort)
gd->flags &= ~GD_FLG_SILENT;
#endif return abort;//返回结果:1-停止引导,进入命令行; 0-引导内核。
}
# endif /* CONFIG_AUTOBOOT_KEYED */
#endif /* CONFIG_BOOTDELAY >= 0 */

4> 引导命令

/****************************************************************************
* returns:
* 1 - command executed, repeatable
* 0 - command executed but not repeatable, interrupted commands are
* always considered not repeatable
* -1 - not executed (unrecognized, bootd recursion or too many args)
* (If cmd is NULL or "" or longer than CONFIG_SYS_CBSIZE-1 it is
* considered unrecognized)
*
* WARNING:
*
* We must create a temporary copy of the command since the command we get
* may be the result from getenv(), which returns a pointer directly to
* the environment data, which may change magicly when the command we run
* creates or modifies environment variables (like "bootp" does).
*/ int run_command (const char *cmd, int flag)
{
cmd_tbl_t *cmdtp;
char cmdbuf[CONFIG_SYS_CBSIZE]; /* working copy of cmd */
char *token; /* start of token in cmdbuf */
char *sep; /* end of token (separator) in cmdbuf */
char finaltoken[CONFIG_SYS_CBSIZE];
char *str = cmdbuf;
char *argv[CONFIG_SYS_MAXARGS + ]; /* NULL terminated */
int argc, inquotes;
int repeatable = ;
int rc = ; #ifdef DEBUG_PARSER
printf ("[RUN_COMMAND] cmd[%p]=\"", cmd);
puts (cmd ? cmd : "NULL"); /* use puts - string may be loooong */
puts ("\"\n");
#endif clear_ctrlc(); /* forget any previous Control C */ if (!cmd || !*cmd) {
return -; /* 空命令 */
} if (strlen(cmd) >= CONFIG_SYS_CBSIZE) { //命令太长
puts ("## Command too long!\n");
return -;
} strcpy (cmdbuf, cmd);//将命令拷贝到临时命令缓冲cmdbuf /* Process separators and check for invalid
* repeatable commands
*/ #ifdef DEBUG_PARSER
printf ("[PROCESS_SEPARATORS] %s\n", cmd);
#endif
while (*str) { /*
* Find separator, or string end
* Allow simple escape of ';' by writing "\;"
*/
for (inquotes = , sep = str; *sep; sep++) { //寻找分割符或者命令尾部。相邻的句子之间是用;隔开的。每次处理一句命令
if ((*sep=='\'') &&
(*(sep-) != '\\'))
inquotes=!inquotes; if (!inquotes &&
(*sep == ';') && /* separator */
( sep != str) && /* past string start */
(*(sep-) != '\\')) /* and NOT escaped */
break;
} /*
* Limit the token to data between separators
*/
token = str; //token指向命令的开头
if (*sep) { //如果是分隔符的话,将分隔符替换为空字符
str = sep + ; /* str指向下一句的开头*/
*sep = '\0';
}
else
str = sep; /* 如果没有其它命令了,str指向命令尾部 */
#ifdef DEBUG_PARSER
printf ("token: \"%s\"\n", token);
#endif /* find macros in this token and replace them */
process_macros (token, finaltoken); //将token指向的命令中的宏替换掉,如把$(kernelsize)替换成内核的大小 /* Extract arguments */
if ((argc = parse_line (finaltoken, argv)) == ) {
//将每一个参数用‘/0’隔开,argv中的每一个指针指向一个参数的起始地址。
//返回值为参数的个数
rc = -; /* no command at all */
continue;
} /* Look up command in command table */
if ((cmdtp = find_cmd(argv[])) == NULL) {
//第一个参数就是要运行的命令,首先在命令表中找到它的命令结构体的指针
printf ("Unknown command '%s' - try 'help'\n", argv[]);
rc = -; /* give up after bad command */
continue;
} /* found - check max args */
if (argc > cmdtp->maxargs) {//检查参数个数是否过多
cmd_usage(cmdtp);
rc = -;
continue;
} #if defined(CONFIG_CMD_BOOTD)
/* avoid "bootd" recursion */
if (cmdtp->cmd == do_bootd) {
#ifdef DEBUG_PARSER
printf ("[%s]\n", finaltoken);
#endif
if (flag & CMD_FLAG_BOOTD) {
puts ("'bootd' recursion detected\n");
rc = -;
continue;
} else {
flag |= CMD_FLAG_BOOTD;
}
}
#endif /* OK - call function to do the command */
if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != ) {//调用命令执行函数。这是最重要的一步。
rc = -;
} repeatable &= cmdtp->repeatable;;//设置命令自动重复执行的标志。也就是只按下enter键是否可以执行最近执行的命令 . /* Did the user stop this? */
if (had_ctrlc ())
//检查是否有ctrl+c按键按下,如果有,结束当前命令。
//本函数并没有从中断接收字符,接收ctrl+c的是一些执行命令的函数。
return -; /* if stopped then not repeatable */
} return rc ? rc : repeatable;
}

最新文章

  1. session 存入数据库 php
  2. How to use FTP
  3. js学习随笔
  4. Debug program crash with dump file.
  5. ApplicationContext
  6. 检测SqlServer服务器IO是否瓶颈
  7. bzoj2124 等差子序列(hash+线段树)
  8. Java学习之equals和hashcode的关系
  9. Android studio dabao
  10. 【C语言】reverse_string(char * string)(递归)
  11. zabbix 布署实践【6 使用微信公众号-消息模版推送告警】
  12. 翻译Algorithms Unlocked
  13. java实现多线程使用多个代理ip的方式爬取网页页面内容
  14. Lansat8大气校正USGS-EROS项目espa-surface-reflectance中的LaSRC Version 1.3.0模块利用vs2010编译出windows64位版本的使用(三)
  15. Rocket MQ 2 - Namesrv
  16. c/c++ lambda 表达式 介绍
  17. python - 文件系统和文件
  18. Solaris 11配置IPS安装系统包(类似linux中的yum源)
  19. Spring IOC(一)概览
  20. [NN] 对于BackPropagation(BP, 误差反向传播)的一些理解

热门文章

  1. python实现二叉树和它的七种遍历
  2. [Hapi.js] View engines
  3. maven ClassNotFoundException: org.springframework.web.context.ContextLoader
  4. linux下使用非root账号安装zabbix-client
  5. 写个点击input框 下方弹出月份时间等
  6. 0122——UITabBarController
  7. AFNetWorking 关于manager.requestSerializer.timeoutInterval 不起作用的问题
  8. ARM入门实践(一)----Mini6410上最简单的LED点灯裸机程序
  9. 用Apache Ivy实现项目里的依赖管理
  10. javascript写的新闻滚动代码