u-boot-1.1.6實現自定義命令
學習目標:
1、了解u-boot-1.1.6中命令的實現機制
2、掌握如何在u-boot-1.1.6中添加自定義命令
1、命令的實現機制
uboot運行在命令行解析模式時,在串口終端輸入uboot命令,按下回車後,系統將執行命令的相應操作。以help命令為例,當輸入help命令,並按下回車時,串口終端打印當前uboot支持的所有命令的幫助信息,如下圖所示(圖片僅截取部分):
到這裏我們應該很好奇uboot的命令是如何實現的呢?想要知道命令如何實現,最簡單的辦法就是在uboot工程中搜索“help”關鍵詞。通過查找在common/command.c源碼文件中找到了uboot命令的定義:
U_BOOT_CMD( help, CFG_MAXARGS, 1, do_help, "help - print online help\n", "[command ...]\n" " - show help information (for ‘command‘)\n" "‘help‘ prints online help for the monitor commands.\n\n" "Without arguments, it prints a short usage message for all commands.\n\n" "To get detailed help information for specific commands you can type\n" "‘help‘ with one or more command names as arguments.\n" );
這裏我們並不知道U_BOOT_CMD是什麽,還需再進行查找。通過進一步查找,可以發現U_BOOT_CMD是一個宏,這個宏在include/command.h頭文件中定義,U_BOOT_CMD宏的原型如下:
#define Struct_Section __attribute__ ((unused,section (".u_boot_cmd")))
#ifdef CFG_LONGHELP #define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \ cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help} #else /* no long help info */ #define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \ cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage} #endif /* CFG_LONGHELP */
這裏采用條件編譯的方式,如果宏CFG_LONGHELP被定義,#ifdef 到#else之間的語句被編譯,否者#else到#endif之間的語句被編譯。這裏我們假設宏CFG_LONGHELP(表示是否支持長的幫助信息)在其他處被定義,按照#ifdef和#else之間的宏定義格式將上述的help命令實現U_BOOT_CMD(help,....)展開,展開後的形式如下:
cmd_tbl_t __u_boot_cmd_help __attribute__ ((unused,section (".u_boot_cmd"))) = {help, CFG_MAXARGS, 1, do_help, "help - print online help\n", "[command ...]\n" " - show help information (for ‘command‘)\n" "‘help‘ prints online help for the monitor commands.\n\n" "Without arguments, it prints a short usage message for all commands.\n\n" "To get detailed help information for specific commands you can type\n" "‘help‘ with one or more command names as arguments.\n" }
將help命令實現U_BOOT_CMD(help,....)展開,可以看出其實U_BOOT_CMD(help,....)就是定義了一個cmd_tbl_t類型的結構體變量,變量名為__u_boot_cmd_help,比較特別的是這個變量被強加了__attribute__屬性,編譯器在進行鏈接時,將該變量放在了名為".u_boot_cmd"自定義段的地址中。下面來看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;
name:命令的名稱(很重要)
maxargs :命令所支持的最大參數
repeatable :命令是否可重復
cmd:回調函數,執行命令便是調用該回調函數
usage:對應短的幫助信息
help :對應長的幫助信息
那麽這些定義的命令是如何被調用呢?通過再次查找我們找到了最底層的命令查找函數find_cmd,其源碼如下:
cmd_tbl_t *find_cmd (const char *cmd) { cmd_tbl_t *cmdtp; cmd_tbl_t *cmdtp_temp = &__u_boot_cmd_start; /*Init value */ const char *p; int len; int n_found = 0; /* * Some commands allow length modifiers (like "cp.b"); * compare command name only until first dot. */ len = ((p = strchr(cmd, ‘.‘)) == NULL) ? strlen (cmd) : (p - cmd); for (cmdtp = &__u_boot_cmd_start; cmdtp != &__u_boot_cmd_end; cmdtp++) { if (strncmp (cmd, cmdtp->name, len) == 0) { if (len == strlen (cmdtp->name)) return cmdtp; /* full match */ cmdtp_temp = cmdtp; /* abbreviated command ? */ n_found++; } } if (n_found == 1) { /* exactly one match */ return cmdtp_temp; } return NULL; /* not found or ambiguous command */ }
通過find_cmd命令我們可以大概猜測出uboot命令實現機制:
- uboot進入命令行解析模式時,首先會等待命令的輸入,當使用者輸入命令,按下回車,uboot開始解析命令行,找到命令的名稱和命令的參數。然後它會通過層層調用,調用find_cmd函數,並將命令的名稱作為參數傳遞給find_cmd函數。
- find_cmd函數對uboot自定義的存放命令相關變量的".u_boot_cmd"段進行遍歷,逐個將命令變量的名稱和傳入的函數參數名稱相互比較。如果兩者名稱比較匹配,則返回指向該變量初始地址的指針變量cmdtp_temp;如果未匹配成功,返回空。
- 上層函數緊接著根據find_cmd函數返回結果執行不同調用,如果返回cmdtp_temp非空,則調用該命令的回調函數,否則,打印找不到相應命令的信息。
2、添加自定義命令
通過上面的一步步分析,我們知道了uboot命令的實現機制,現在就動手添加一個簡單的自定義命令custom。自定義命令實現功能:執行該命令打印“This is a custom command”語句。
①在uboot根目錄下common文件夾中新建一個名為cmd_custom.c的文件,添加文件內容如下:
#include <common.h> #include <command.h> /* *No utility functions, only for testing */ int do_custom (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) { printf("This is a custom command\n"); printf("argc = %d\n", argc); } U_BOOT_CMD( custom, CFG_MAXARGS, 1, do_custom, "User-defined functions\n", "User-defined functions, the function is implemented in the cmd_custon.c file\n" );
②將代碼上傳服務器,修改uboot根目錄下的Makefile文件,將cmd_custom.o添加到Makefile中COBJS變量裏
③執行make命令,重新編譯uboot
④燒寫新的uboot到flash中
⑤進入uboot命令行解析模式,執行custom命令,結果如下圖所示:
⑥執行help custom命令打印custom命令行長的幫助信息
根據執行結果來看,添加自定義命令成功!
u-boot-1.1.6實現自定義命令