uboot啟動linux核心小結(boot,bootd,boom,bootcmd,bootargs)
uboot在進行系統啟動和核心載入的時候被分為倆個階段,
第一階段主要是寫彙編程式碼,我沒有仔細研究,只是看了看移植好的針對mini2440的tekkman的uboot程式碼。
第二個階段為由C寫成,易於研究和學習。掌握了基本的流程。
(1)第一階段的功能
Ø 硬體裝置初始化
Ø 載入U-Boot第二階段程式碼到RAM空間
Ø 設定好棧
Ø 跳轉到第二階段程式碼入口
(2)第二階段的功能
Ø 初始化本階段使用的硬體裝置
Ø 檢測系統記憶體對映
Ø 將核心從Flash讀取到RAM中
Ø 為核心設定啟動引數
Ø 呼叫核心
第二階段的C出口函式為:
由於在cpu/arm920t/start.S的最後階段有如下程式碼:
ldr pc, _start_armboot
_start_armboot: .word start_armboot 此時pc指標將會跳轉到lib_arm/board.c中定義的函式start_armboot().因此start_armboot().函式是c程式碼的入口程式碼,分析就從這裡起航。
而在函式start_armboot()中有個死迴圈,
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;)
{
main_loop ();接受使用者在uboot命令列輸入的命令。
}
在uboot啟動的時候,如果在#define CONFIG_BOOTDELAY 1超時之前使用者沒有輸入,uboot就會自動載入linux核心,
其載入時將使用變數“bootcmd”和 “bootargs”在uboot程式碼所定義的變數值進行啟動程式碼。
變數“bootcmd”和 “bootargs”的值可以在在載入linux核心前,uboot的命令列中進行修改。
我這倆個引數的值如下:
bootcmd=nfs 0x30008000 192.168.1.149:/opt/FriendlyARM/uImage;bootm ------ 需要注意的是再bootcmd變數的最後添加了bootm命令。
bootargs=noinitrd root=/dev/nfs proto=tcp,nolock,nfsvers=3, rw nfsroot=192.168.1.149:/mini2440/rootfs ip=192.168.1.144:192.168.1.149::255.255.255.0 console=ttySAC0,115200 init=/linuxrc mem=64M
首先看看啟動核心是倆種比較簡單明白的方式,boot,bootd命令的實現。
現實程式碼如下:
/*******************************************************************/
/* bootd - boot default image */
/*******************************************************************/
#if defined(CONFIG_CMD_BOOTD)
int do_bootd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
int rcode = 0;
#ifndef CONFIG_SYS_HUSH_PARSER
if (run_command (getenv ("bootcmd"), flag) < 0)
rcode = 1;
#else
if (parse_string_outer (getenv ("bootcmd"),
FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0)
rcode = 1;
#endif
return rcode;
}
U_BOOT_CMD(
boot, 1, 1, do_bootd,
"boot default, i.e., run 'bootcmd'",
""
);
/* keep old command name "bootd" for backward compatibility */
U_BOOT_CMD(
bootd, 1, 1, do_bootd,
"boot default, i.e., run 'bootcmd'",
""
);
#endif
從上面的對命令boot,bootd命令實現可以知道,其命令的最終執行的是“bootcmd”命令列引數所定義的值
即"nfs 0x30008000 192.168.1.149:/opt/FriendlyARM/uImage;bootm ":
在上面的函式main_loop ()中又如下程式碼片段
s = getenv ("bootcmd");
debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
if (bootdelay >= 0 && s && !abortboot (bootdelay))
{
# ifdef CONFIG_AUTOBOOT_KEYED
int prev = disable_ctrlc(1); /* disable Control C checking */
# 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 */
# 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 */
上的程式碼中在函式abortboot (bootdelay))
執行的過程中已經超時,則自動的執行"bootcmd" 所定義的命令。
現在看看命令"bootm"命令式如何實現的?
"boot application image from memory",這句話很重要,表明bootm執行是必須確保uImage已經在內從中,
在"bootm addr"中當addr省略的時候bootm載入巨集#define CONFIG_SYS_LOAD_ADDR 0x30008000 /* default load address */定義處的核心image。
"bootm"命令的實現函式為do_bootm(),在do_bootm()中完成對linux核心的載入啟動。
其載入函式為:do_bootm_linux()函式中獲取了"bootargs"環境變數的值。最終將此值傳遞給linux核心,用來載入檔案系統時候使用。
對do_bootm()和do_bootm_linux()函式的分析可以找到看其他朋友的分析。
總結
在uboot中每一個命令都對應一個其實現的函式,在啟動linux核心過程中,主要是執行環境變數bootcmd和bootargs所定義的命令。因此,對這倆個變數的定義很重要,如果定義不對就不能正確的載入核心和檔案系統。尤其是必須確保檔案系統所在分割槽。