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。
一、具體實現步驟:
- 在./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,從而完成了命令的執行。
完事兒。