1. 程式人生 > >u-boot分析 七 (新增u-boot命令,學習u-boot命令實現原理)

u-boot分析 七 (新增u-boot命令,學習u-boot命令實現原理)

u-boot分析 七

(新增u-boot命令,學習u-boot命令實現原理)

本文目標:

理解u-boot命令的實現原理。

上一篇文章分析了u-boot是如何啟動kernel的,其中就涉及到bootm命令,考慮到文章主題需要,當時並沒有對bootm命令做過多的解釋。然而,u-boot命令列又是u-boot及其重要的一部分。這篇文章,我們就通過實戰來理解u-boot命令的實現原理。

我們要做的很簡單,就是新增一條uboot command,希望在開發板上,uboot命令列中輸入itxiebo時,能夠從串列埠打印出一句log。

一、具體實現步驟:

  1. 在./common資料夾下新建cmd_itxiebo.c,並在此檔案中新增如下內容
#include <common.h>
#include <command.h>

static int do_itxiebo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
    printf("do_itxiebo command is ready now!");
    return 0;
}

U_BOOT_CMD(
    itxiebo,    2,  0,  do_itxiebo,
    "itxiebo - this is a itxiebo command, do nothing"
, "- this is a itxiebo command, do nothing" );

2.在./common/Makefile中新增:

obj-y += cmd_itxiebo.o

3.在linux環境下,重新編譯u-boot,得到u-boot.bin,並升級到自己的開發板中(如果你沒有開發板,沒有關係,你只需要明白我們要在開發板中驗證自己新增的命令itxiebo)

4.升級完後,在開發板啟動核心之前,按space鍵進入u-boot命令列模式。
這裡寫圖片描述

5.在串列埠終端中輸入help命令,回車,可以發現itxiebo命令列已經新增成功。
這裡寫圖片描述

6.在串列埠終端中輸入itxiebo命令,回車執行該命令,發現我們新增的列印log,可以正確打印出來:
這裡寫圖片描述

二、命令原理分析

實戰見效果了,我們繼續分析。不難發現,只要能搞清上面程式碼中的“U_BOOT_CMD”,就能弄明白uboot命令實現原理。

U_BOOT_CMD格式如下:

U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help)

其中,各個引數解釋如下:

引數名 說明
_name 命令名,非字串,但在U_BOOT_CMD中用“#”符號轉化為字串
_maxargs 命令的最大引數個數
_rep 是否自動重複(按Enter鍵是否會重複執行)
_cmd 該命令對應的響應函式
_usage 簡短的使用說明(字串)
_help 較詳細的使用說明(字串)

說明:
在記憶體中儲存命令的help欄位會佔用一定的記憶體,通過配置U-Boot可以選擇是否儲存help欄位。若在include/configs/s5p4418_urbetter.h 中定義了CONFIG_SYS_LONGHELP巨集,則在U-Boot中使用help命令檢視某個命令的幫助資訊時將顯示_usage和_help欄位的內容,否則就只顯示usage欄位的內容,而不顯示_help欄位的內容。

另外,在include/command.h中,對U_BOOT_CMD的define 如下:

#define ll_entry_declare(_type, _name, _list)               \
    _type _u_boot_list_2_##_list##_2_##_name __aligned(4) __attribute__((unused,    section(".u_boot_list_2_"#_list"_2_"#_name)))

#define U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, _comp) \
    ll_entry_declare(cmd_tbl_t, _name, cmd) =           \
        U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd,  _usage, _help, _comp);

#define U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help)      \
    U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, NULL)

最後,同樣在include/command.h中定義了一個結構體cmd_tbl_t

這裡寫圖片描述

如此,我們便可以將U_BOOT_COM解析,如下

U_BOOT_CMD(
    itxiebo,    2,  0,  do_itxiebo,
    "itxiebo - this is a itxiebo command, do nothing",
    "- this is a itxiebo command, do nothing"
);

解析為:

cmd_tbl_t _u_boot_list_2_do_itxiebo_2_itxiebo __aligned(4) __attribute__((unused,section(".u_boot_list_2_"do_itxiebo"_2_"itxiebo)))

其中,“u_boot_list”,《u-boot分析 三》分析u-boot.lds時解釋過。也就是說咱們新增的itxiebo command會被儲存在u_boot_list段內。

.u_boot_list : {
        KEEP(*(SORT(.u_boot_list*)));
        /*.data段結束後,緊接著存放u-boot自有的一些function,例如u-boot command等*/
    }

三、itxiebo命令的執行過程:

在U-Boot中輸入(串列埠終端)“itxiebo”命令執行時,U-Boot接收輸入的字串“itxiebo”,傳遞給run_command()函式。run_command()函式呼叫common/command.c中實現的find_cmd()函式在u_boot_list段內查詢命令,並返回itxiebo命令的cmd_tbl_t結構。然後run_command()函式使用返回的cmd_tbl_t結構中的函式指標呼叫itxiebo命令的響應函式do_itxiebo,從而完成了命令的執行。

完事兒。