1. 程式人生 > >uboot啟動linux核心小結(boot,bootd,boom,bootcmd,bootargs)

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所定義的命令。因此,對這倆個變數的定義很重要,如果定義不對就不能正確的載入核心和檔案系統。尤其是必須確保檔案系統所在分割槽。