天天看點

uboot的main_loop()函數解析

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*/
}