1. 程式人生 > >u-boot-1.1.6實現自定義命令

u-boot-1.1.6實現自定義命令

can utili .com 幫助信息 下回 查找 boot img repeat

學習目標:

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實現自定義命令