main_loop()函數做的都是與具體平台無關的工作。主要包括的工作如下:
(1)初始化啟動次數限制機制
(2)Modem功能
(3)設定軟體版本号
(4)啟動延遲
(5)讀取指令,解析指令
void main_loop (void)
{
#ifndef CONFIG_SYS_HUSH_PARSER
static char lastcommand[CONFIG_SYS_CBSIZE] = { 0, };
int len;
int rc = 1;
int flag;
#endif
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
char *s;
int bootdelay;
#endif
#ifdef CONFIG_PREBOOT
char *p;
#endif
/*
啟動次數限制功能,啟動次數限制可以被使用者設定一個啟動次數,然後儲存在Flash存儲器的特定位置,當到達啟動次數後,
U-Boot無法啟動。該功能适合一些商業産品,通過配置不同的License限制使用者重新啟動系統。
*/
#ifdef CONFIG_BOOTCOUNT_LIMIT //使能啟動次數限制功能,主要用于産品的限次使用
unsigned long bootcount = 0;
unsigned long bootlimit = 0;
char *bcs;
char bcs_set[16];
#endif /* CONFIG_BOOTCOUNT_LIMIT */
#if defined(CONFIG_VFD) && defined(VFD_TEST_LOGO)
ulong bmp = 0; /* default bitmap */
extern int trab_vfd (ulong bitmap);
#ifdef CONFIG_MODEM_SUPPORT
if (do_mdm_init)
bmp = 1; /* 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); //設定環境變量bootcount
bcs = getenv ("bootlimit"); //獲得啟動次數的上限
bootlimit = bcs ? simple_strtoul (bcs, NULL, 10) : 0;
#endif /* CONFIG_BOOTCOUNT_LIMIT */
/*
Modem功能。如果系統中有Modem,打開該功能可以接受其他使用者通過電話網絡的撥号請求。Modem功能通常供一些遠端控制的系統使用。
*/
#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 */
/*
設定U-Boot的版本号,初始化指令自動完成功能等。動态版本号功能支援代碼,version_string變量是在其他檔案定義的一個字元串變量,
當使用者改變U-Boot版本的時候會更新該變量。打開動态版本支援功能後,U-Boot在啟動的時候會顯示最新的版本号。
*/
#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
/*
設定指令行自動完成功能,該功能與Linux的shell類似,當使用者輸入一部分指令後,可以通過按下鍵盤上的Tab鍵 //補全指令的剩餘部分。
main_loop()函數不同的功能使用宏開關控制不僅能提高代碼子產品化,更主要的是針對嵌入 //式系統Flash存儲器大小設計的。在嵌入式系統
上,不同的系統Flash存儲空間不同。對于一些Flash空間比較緊張 //的裝置來說,通過宏開關關閉一些不是特别必要的功能如指令行自動完
成,可以減小U-Boot編譯後的檔案大小。
*/
#ifdef CONFIG_AUTO_COMPLETE // 初始化指令自動完成功能
install_auto_complete();
#endif
#ifdef CONFIG_PREBOOT
if ((p = getenv ("preboot")) != NULL) {
# ifdef CONFIG_AUTOBOOT_KEYED
int prev = disable_ctrlc(1); /* disable Control C checking */
# endif
# ifndef CONFIG_SYS_HUSH_PARSER
run_command (p, 0);
# 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, 10) : CONFIG_BOOTDELAY; //這段代碼是擷取環境變量bootdelay的值,bootdelay就是uboot啟動之後倒計時的時間
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>");
/*
在啟動指令非0(有啟動指令)的情況下,如果在啟動延時時間到之前按下鍵終止了,abortboot傳回1,否則如果一 //直沒有
鍵按下,直到啟動延時時間到,那麼函數傳回0。是以,如果按下鍵了,就可以跳過啟動作業系統;如果沒 //按就直接啟動作業系統了。
*/
if (bootdelay >= 0 && s && !abortboot (bootdelay)) { /*在啟動延遲期間是否有按鈕按下,按下則跳過啟動linux代碼*/
# ifdef CONFIG_AUTOBOOT_KEYED
int prev = disable_ctrlc(1); /* disable Control C checking *///關閉control+c組合鍵
# endif
# ifndef CONFIG_SYS_HUSH_PARSER
run_command (s, 0); //運作啟動指令,啟動作業系統
# else
parse_string_outer(s, FLAG_PARSE_SEMICOLON |
FLAG_EXIT_FROM_LOOP);
# endif
# ifdef CONFIG_AUTOBOOT_KEYED
disable_ctrlc(prev); /* restore Control C checking *///恢複control+c組合鍵功能
# endif
}
# 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 */
#ifdef CONFIG_AMIGAONEG3SE
{
extern void video_banner(void);
video_banner(); // 列印啟動圖示
}
#endif
// added by FriendlyARM
{
void FriendlyARMMenu(void);
FriendlyARMMenu();
}
/*
讀取指令,解析指令。這是一個for死循環,該循環不斷使用readline()函數(第463行)從控制台(一般是序列槽)讀取使用者的輸入,
然後解析。有關如何解析指令請參考U-Boot代碼中run_command()函數的定義。
*/
/*
* 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 >= 0) {
/* Saw enough of a valid command to
* restart the timeout.
*/
reset_cmd_timeout(); // 設定指令行逾時
}
#endif
len = readline (CONFIG_SYS_PROMPT); // 讀取指令,讀取到的指令存儲在全局變量console_buffer 中
flag = 0; /* assume no special flags for now */
if (len > 0) //指令長度大于0
strcpy (lastcommand, console_buffer); //将讀取到的指令copy到lastcommand中
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 run initialization code again */
do_reset (NULL, 0, 0, NULL);
# else
return; /* retry autoboot */
# endif
}
#endif
if (len == -1)
puts ("<INTERRUPT>\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*/
}