uboot main_loop函數分析


一、概述
    main_loop()函數做的都是與具體平台無關的工作。主要包括的工作如下:

(1)初始化啟動次數限制機制

(2)Modem功能

(3)設置軟件版本號

(4)啟動延遲

(5)讀取命令,解析命令

二、具體分析
void main_loop (void)
{
#ifndef CFG_HUSH_PARSER
static char lastcommand[CFG_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

(1)啟動次數限制功能,啟動次數限制可以被用戶設置一個啟動次數,然后保存在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 */

(2)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 */

(3)設置U-Boot的版本號,初始化命令自動完成功能等。動態版本號功能支持代碼,version_string變量是在其他文件定義的一個字符串變量,當用戶改變U-Boot版本的時候會更新該變量。打開動態版本支持功能后,U-Boot在啟動的時候會顯示最新的版本號。
#ifdef CONFIG_VERSION_VARIABLE
{
extern char version_string[];      //在lib_arm/board.c中定義有此字符串

setenv ("ver", version_string);     /* set version variable */ //將版本號寫入flash
}
#endif /* CONFIG_VERSION_VARIABLE */

#ifdef CFG_HUSH_PARSER
u_boot_hush_start ();
#endif

#ifdef CONFIG_AUTO_COMPLETE /// 初始化命令自動完成功能
install_auto_complete();
#endif

//設置命令行自動完成功能,該功能與Linux的shell類似,當用戶輸入一部分命令后,可以通過按下鍵盤上的Tab鍵   //補全命令的剩余部分。main_loop()函數不同的功能使用宏開關控制不僅能提高代碼模塊化,更主要的是針對嵌入  //式系統Flash存儲器大小設計的。在嵌入式系統上,不同的系統Flash存儲空間不同。對於一些Flash空間比較緊張  //的設備來說,通過宏開關關閉一些不是特別必要的功能如命令行自動完成,可以減小U-Boot編譯后的文件大小。

#ifdef CONFIG_PREBOOT
if ((p = getenv ("preboot")) != NULL) {
# ifdef CONFIG_AUTOBOOT_KEYED
int prev = disable_ctrlc(1); /* disable Control C checking */ // 關閉Crtl+C組合鍵
# endif

# ifndef CFG_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 */ // 恢復Ctrl+C組合鍵
# endif
}
#endif /* CONFIG_PREBOOT */

(4)啟動延遲功能,需要等待用戶從串口或者網絡接口輸入。如果用戶按下任意鍵打斷,啟動流程,會向終端打印出一個啟動菜單。
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
s = getenv ("bootdelay");//獲得啟動延時時間環境變量
bootdelay = s ? (int)simple_strtol(s, NULL, 10) : 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_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)) {
# ifdef CONFIG_AUTOBOOT_KEYED
int prev = disable_ctrlc(1); /* disable Control C checking *///關閉control+c組合鍵
# endif

# ifndef CFG_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 CFG_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

(5)讀取命令,解析命令。這是一個for死循環,該循環不斷使用readline()函數(第463行)從控制台(一般是串口)讀取用戶的輸入,然后解析。有關如何解析命令請參考U-Boot代碼中run_command()函數的定義。
/*
* Main Loop for Monitor Command Processing
*/
#ifdef CFG_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 (CFG_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 /*CFG_HUSH_PARSER*/

}

參考:main_loop分析 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM