uboot 的命令體系


1、代碼位置

(1)uboot命令體系的實現代碼在uboot/common/cmd_xxx.c中。有若干個.c文件和命令體系有關。(還有command.c  main.c也是和命令有關的)

2、傳參方式

命令參數以argc&argv傳給函數
(1)有些uboot的命令還支持傳遞參數。也就是說命令背后對應的函數接收的參數列表中有argc和argv,然后命令體系會把我們執行命令時的命令+參數(md 30000000 10)以argc(3)和argv(argv[0]=md, argv[1]=30000000 argv[2]=10)的方式傳遞給執行命令的函數。

3、uboot命令解析和執行過程分析

(1)uboot啟動的第二階段,在初始化了所有該初始化的東西后,進入了一個死循環,死循環的循環體就是main_loop。
(2)main_loop函數執行一遍,就是一個獲取命令、解析命令、執行命令的過程。
(3)run_command函數就是用來執行命令的函數。

關鍵點分析
(1)控制台命令獲取
(2)命令解析。parse_line函數把"md 30000000 10"解析成argv[0]=md, argv[1]=30000000 argv[2]=10;
(3)命令集中查找命令。find_cmd(argv[0])函數去uboot的命令集合當中搜索有沒有argv[0]這個命令,
(4)執行命令。最后用函數指針的方式調用執行了對應函數。

3、存儲方式

uboot沒有使用數組或者鏈表,而是使用了一種新的方式來實現這個功能。指定起始地址與結束地址,將命令依次排布(在鏈接腳本中實現。)

__u_boot_cmd_start = .;
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;

命令結構體cmd_tbl_t

struct cmd_tbl_s {
char    *name;    /* Command Name    */
int    maxargs;    /* maximum number of arguments    */
int    repeatable;    /* autorepeat allowed?    */
/* Implementation function    */
int    (*cmd)(struct cmd_tbl_s *, int, int, char *[]);
char    *usage;    /* Usage message    (short)    */
#ifdef    CFG_LONGHELP
char    *help;    /* Help message    (long)    */
#endif
#ifdef CONFIG_AUTO_COMPLETE
/* do auto completion on the arguments */
int    (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]);
#endif
};
typedef struct cmd_tbl_s    cmd_tbl_t;

(1)name:命令名稱,字符串格式。
(2)maxargs:命令最多可以接收多少個參數
(3)repeatable:指示這個命令是否可重復執行。重復執行是uboot命令行的一種工作機制,就是直接按回車則執行上一條執行的命令。
(4)cmd:函數指針,命令對應的函數的函數指針,將來執行這個命令的函數時使用這個函數指針來調用。
(5)usage:命令的短幫助信息。對命令的簡單描述。
(6)help:命令的長幫助信息。細節的幫助信息。
(7)complete:函數指針,指向這個命令的自動補全的函數。
總結:uboot的命令體系在工作時,一個命令對應一個cmd_tbl_t結構體的一個實例,然后uboot支持多少個命令,就需要多少個結構體實例。uboot的命令體系把這些結構體實例管理起來,當用戶輸入了一個命令時,uboot會去這些結構體實例中查找(查找方法和存儲管理的方法有關)。如果找到則執行命令,如果未找到則提示命令未知。

4、uboot實現命令管理的思路

(1)填充1個結構體實例構成一個命令
(2)給命令結構體實例附加特定段屬性(用戶自定義段),鏈接時將帶有該段屬性的內容鏈接在一起排列(挨着的,不會夾雜其他東西,也不會丟掉一個帶有這種段屬性的,但是順序是亂序的)。
(3)uboot重定位時將該段整體加載到DDR中。加載到DDR中的uboot鏡像中帶有特定段屬性的這一段其實就是命令結構體的集合,有點像一個命令結構體數組。
(4)段起始地址和結束地址(鏈接地址、定義在u-boot.lds中)決定了這些命令集的開始和結束地址。

uboot命令定義具體實現分析
(1)U_BOOT_CMD宏基本分析
這個宏定義在uboot/common/command.h中。

U_BOOT_CMD(
version,    1,    1,    do_version,
"version - print monitor version\n",
NULL
);
這個宏替換后變成:
cmd_tbl_t __u_boot_cmd_version __attribute__ ((unused,section (".u_boot_cmd"))) = {#name, maxargs, rep, cmd, usage, help}

總結:這個U_BOOT_CMD宏的理解,關鍵在於結構體變量的名字和段屬性。名字使用##作為連字符,附加了用戶自定義段屬性,以保證鏈接時將這些數據結構鏈接在一起排布。

5、.uboot中增加自定義命令

1、在已有的c文件中直接添加命令
(1)在uboot/common/command.c中添加一個命令,叫:mycmd
(2)在已有的.c文件中添加命令比較簡單,直接使用U_BOOT_CMD宏即可添加命令,給命令提供一個do_xxx的對應的函數這個命令就齊活了。
(3)添加完成后要重新編譯工程(make distclean; make x210_sd_config; make),然后燒錄新的uboot去運行即可體驗新命令。
(4)還可以在函數中使用argc和argv來驗證傳參。

2、自建一個c文件並添加命令
(1)在uboot/common目錄下新建一個命令文件,叫cmd_aston.c(對應的命令名就叫aston,對應的函數就叫do_aston函數),然后在c文件中添加命令對應的U_BOOT_CMD宏和函數。注意頭文件包含不要漏掉。
(2)在uboot/common/Makefile中添加上aston.o,目的是讓Make在編譯時能否把cmd_aston.c編譯鏈接進去。
(3)重新編譯燒錄。重新編譯步驟是:make distclean; make x210_sd_config; make

3、體會:uboot命令體系的優點
(1)uboot的命令體系本身稍微復雜,但是他寫好之后就不用動了。我們后面在移植uboot時也不會去動uboot的命令體系。我們最多就是向uboot中去添加命令,就像本節課所做的這樣。
(2)向uboot中添加命令非常簡單。

#include <common.h>
#include <command.h>

int
do_mycmd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
    extern char version_string[];
    printf ("\n%s\n", version_string);
    return 0;
}

U_BOOT_CMD(
    mycmd,    1,        1,    do_mycmd,
    "version - print monitor version\n",
    NULL
);

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM