uboot中main_loop()階段分析


函數main_loop和u-boot命令執行

標簽: u-boot環境變量mainmain_loop
1179人閱讀 評論(0) 收藏 舉報
分類:
一.main_loop函數執行流程和命令解釋器
run_main_loop是board_r中函數運行列表init_fnc_t init_sequence_r[]最后一個函數,它又調用了main_loop,且run_main_loop永不返回。
  1. static int run_main_loop(void)  
  2. {  
  3.     /* main_loop() can return to retry autoboot, if so just run it again */  
  4.     for (;;)  
  5.         main_loop();  
  6.     return 0;  
  7. }  
static int run_main_loop(void)
{
    /* main_loop() can return to retry autoboot, if so just run it again */
    for (;;)
        main_loop();
    return 0;
}
main_loop定義在common/main.c中:
  1. void main_loop(void)  
  2. {  
  3.     const char *s;  
  4.     bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, "main_loop");  
  5.     modem_init();  
  6. #ifdef CONFIG_VERSION_VARIABLE  
  7.     setenv("ver", version_string);  /* set version variable */  
  8. #endif /* CONFIG_VERSION_VARIABLE */  
  9.     cli_init();  
  10.     run_preboot_environment_command();  
  11.     s = bootdelay_process();  
  12.     if (cli_process_fdt(&s))  
  13.         cli_secure_boot_cmd(s);  
  14.     autoboot_command(s);  
  15.     cli_loop();  
  16. }  
void main_loop(void)
{
    const char *s;
    bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, "main_loop");
    modem_init();
#ifdef CONFIG_VERSION_VARIABLE
    setenv("ver", version_string);  /* set version variable */
#endif /* CONFIG_VERSION_VARIABLE */
    cli_init();
    run_preboot_environment_command();
    s = bootdelay_process();
    if (cli_process_fdt(&s))
        cli_secure_boot_cmd(s);
    autoboot_command(s);
    cli_loop();
}
bootstage_mark_name函數調用了show_boot_progress,利用它顯示啟動進程(progress),此處為空函數。
setenv設置環境變量ver為version_string,后者在common/cmd_version.c中定義為:
  1. const char __weak version_string[] = U_BOOT_VERSION_STRING;  
const char __weak version_string[] = U_BOOT_VERSION_STRING;

U_BOOT_VERSION_STRING在version.h中定義為:

 

  1. #define U_BOOT_VERSION_STRING U_BOOT_VERSION " (" U_BOOT_DATE " - " \  
  2.     U_BOOT_TIME " " U_BOOT_TZ ")" CONFIG_IDENT_STRING  
#define U_BOOT_VERSION_STRING U_BOOT_VERSION " (" U_BOOT_DATE " - " \
    U_BOOT_TIME " " U_BOOT_TZ ")" CONFIG_IDENT_STRING
其中U_BOOT_VERSION ,U_BOOT_DATE,U_BOOT_TIME,U_BOOT_TZ均由u-boot構建系統自動產生,
它們分別代表u-boot版本號,編譯日期和時間,以及時間區。
如果定義了CONFIG_SYS_HUSH_PARSER,那么配置u-boot使用hush shell來作為執行器。hush shell是一種輕量型的shell。
cli_init用來初始化hush shell使用的一些變量。hush shell的實現機制比較復雜,以下的hush shell相關實現代碼都不做詳盡跟蹤分析。
有興趣的可參見源代碼和相關的網絡文章。

 

run_preboot_environment_command函數從環境變量中獲取"preboot"的定義,該變量包含了一些預啟動命令,
一般環境變量中不包含該項配置。
bootdelay_process從環境變量中取出"bootdelay"和"bootcmd"的配置值,將取出的"bootdelay"配置值轉換成整數,
賦值給全局變量stored_bootdelay,最后返回"bootcmd"的配置值。bootdelay為u-boot的啟動延時計數值,計數期間內
如無用戶按鍵輸入干預,那么將執行"bootcmd"配置中的命令。
由於沒有定義CONFIG_OF_CONTROL,函數cli_process_fdt返回false,接下來執行autoboot_command,
該函數在common/autoboot.c中實現:

  1. void autoboot_command(const char *s)  
  2. {  
  3.     if (stored_bootdelay != -1 && s && !abortboot(stored_bootdelay)) {  
  4.         run_command_list(s, -1, 0);  
  5.     }  
  6.   
  7. }  
void autoboot_command(const char *s)
{
    if (stored_bootdelay != -1 && s && !abortboot(stored_bootdelay)) {
        run_command_list(s, -1, 0);
    }

}
全局變量stored_bootdelay在上面已做說明。靜態函數abortboot中包含了CONFIG_AUTOBOOT_KEYED宏預處理分支,該宏定義用來使能用戶名密碼登錄,這里它沒有定義,而后調用了abortboot_normal,在執行的時間stored_bootdelay(秒)內,如無用戶按鍵輸入干預,那么abortboot_normal函數將返回0,否則返回1。 當無用戶按鍵干預時,接下來將調用run_command_list執行上述從環境變量中讀取的"bootcmd"配置值。注意該函數的參數s。run_command_list中調用了hush shell的命令解釋器(parse_stream_outer函數),解釋bootcmd中的啟動命令。環境變量bootcmd中的啟動命令,用來設置linux必要的啟動環境,然后加載和啟動linux內核。u-boot啟動linux內核后,將控制權交給linux內核,至此不再返回。
如用戶在設定的bootdelay內無按鍵輸入,那么將運行cli_loop執行hush shell命令解釋器:
  1. void cli_loop(void)  
  2. {  
  3.   
  4.     parse_file_outer();  
  5.     /* This point is never reached */  
  6.     for (;;);  
  7.   
  8. }  
void cli_loop(void)
{

    parse_file_outer();
    /* This point is never reached */
    for (;;);

}
parse_file_outer進行必要的初始化后,也將調用hush shell的命令解釋器,即parse_stream_outer函數:
  1. static int parse_stream_outer(structin_str*inp,intflag)  
  2. {  
  3.     do {  
  4.         ...  
  5.         ...  
  6.         run_list(...);  
  7.     } while (rcode != -1 && !(flag & FLAG_EXIT_FROM_LOOP) &&  //#define FLAG_EXIT_FROM_LOOP 1  
  8.             (inp->peek != static_peek || b_peek(inp)));  
  9. }  
static int parse_stream_outer(structin_str*inp,intflag)
{
    do {
        ...
        ...
        run_list(...);
    } while (rcode != -1 && !(flag & FLAG_EXIT_FROM_LOOP) &&  //#define FLAG_EXIT_FROM_LOOP 1
            (inp->peek != static_peek || b_peek(inp)));
}
上面的do-while會循環命令解析器的"命令輸入解析--執行"運行模式。
其中的函數run_list執行如下的函數調用流程:
run_list-->run_list_real-->run_pipe_real
最后在函數run_pipe_real中有:
return cmd_process(...);
函數cmd_process最后完成u-boot命令的定位和執行。
二.u-boot命令執行
命令處理函數均在common/command.c中實現,上述函數cmd_process定義如下:
  1. enum command_ret_t cmd_process(int flag, int argc, char * const argv[],  int *repeatable, ulong *ticks)  
  2. {  
  3.     enum command_ret_t rc = CMD_RET_SUCCESS;  
  4.     cmd_tbl_t *cmdtp;  
  5.     /* Look up command in command table */  
  6.     cmdtp = find_cmd(argv[0]);  
  7.     if (cmdtp == NULL) {  
  8.         printf("Unknown command '%s' - try 'help'\n", argv[0]);  
  9.         return 1;  
  10.     }  
  11.     /* found - check max args */  
  12.     if (argc > cmdtp->maxargs)  
  13.         rc = CMD_RET_USAGE;  
  14.     /* If OK so far, then do the command */  
  15.     if (!rc) {  
  16.         if (ticks)  
  17.             *ticks = get_timer(0);  
  18.         rc = cmd_call(cmdtp, flag, argc, argv);  
  19.         if (ticks)  
  20.             *ticks = get_timer(*ticks);  
  21.         *repeatable &= cmdtp->repeatable;  
  22.     }  
  23.     if (rc == CMD_RET_USAGE)  
  24.         rc = cmd_usage(cmdtp);  
  25.     return rc;  
  26. }  
enum command_ret_t cmd_process(int flag, int argc, char * const argv[],  int *repeatable, ulong *ticks)
{
    enum command_ret_t rc = CMD_RET_SUCCESS;
    cmd_tbl_t *cmdtp;
    /* Look up command in command table */
    cmdtp = find_cmd(argv[0]);
    if (cmdtp == NULL) {
        printf("Unknown command '%s' - try 'help'\n", argv[0]);
        return 1;
    }
    /* found - check max args */
    if (argc > cmdtp->maxargs)
        rc = CMD_RET_USAGE;
    /* If OK so far, then do the command */
    if (!rc) {
        if (ticks)
            *ticks = get_timer(0);
        rc = cmd_call(cmdtp, flag, argc, argv);
        if (ticks)
            *ticks = get_timer(*ticks);
        *repeatable &= cmdtp->repeatable;
    }
    if (rc == CMD_RET_USAGE)
        rc = cmd_usage(cmdtp);
    return rc;
}
u-boot中使用宏U_BOOT_CMD來定義命令,該宏在include/command.h中定義如下:
  1. #define U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help)      \  
  2.     U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, NULL)  
#define U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help)      \
    U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, NULL)
U_BOOT_CMD是宏U_BOOT_CMD_COMPLETE最后一個參數_comp為NULL的特例,_comp表示變量是否自動完成:
  1. #define U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, _comp) \  
  2.     ll_entry_declare(cmd_tbl_t, _name, cmd) =           \  /*注意這里是cmd而非_cmd*/  
  3.         U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd,  \  
  4.                         _usage, _help, _comp);  
#define U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, _comp) \
    ll_entry_declare(cmd_tbl_t, _name, cmd) =           \  /*注意這里是cmd而非_cmd*/
        U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd,  \
                        _usage, _help, _comp);
其中包含的宏U_BOOT_CMD_MKENT_COMPLETE定義為:
  1. #define U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd,      \  
  2.                 _usage, _help, _comp)           \  
  3.         { #_name, _maxargs, _rep, _cmd, _usage,         \  
  4.             _CMD_HELP(_help) _CMD_COMPLETE(_comp) }  
#define U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd,      \
                _usage, _help, _comp)           \
        { #_name, _maxargs, _rep, _cmd, _usage,         \
            _CMD_HELP(_help) _CMD_COMPLETE(_comp) }

上面的_CMD_HELP根據配置可選為使用完整或簡短幫助說明。_CMD_COMPLETE則根據配置決定是否使用自動完成函數。U_BOOT_CMD_MKENT_COMPLETE宏其實是組織輸入參數,對ll_entry_declare進行數據填充。ll_entry_declare在文件include/linker_lists.h中定義:

  1. #define ll_entry_declare(_type, _name, _list)               \  
  2.     _type _u_boot_list_2_##_list##_2_##_name __aligned(4)       \  
  3.             __attribute__((unused,              \  
  4.             section(".u_boot_list_2_"#_list"_2_"#_name)))  
#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)))
參數_type為cmd_tbl_t,這里定義一個cmd_tbl_t結構體,並把它放在符號段.u_boot_list_2_"#_list"_2_"#_name中,其中的_list和_name根據宏參數進行字符串替換。
下面,我們舉例說明上述宏的實現機制。比如有如下的定義:
  1. U_BOOT_CMD(  
  2.     env, CONFIG_SYS_MAXARGS, 1, do_env,  
  3.     "environment handling commands", env_help_text  
  4. );      
U_BOOT_CMD(
    env, CONFIG_SYS_MAXARGS, 1, do_env,
    "environment handling commands", env_help_text
);    

  1. U_BOOT_CMD_COMPLETE (  
  2.     env, CONFIG_SYS_MAXARGS, 1, do_env,  
  3.     "environment handling commands", env_help_text,NULL  
  4. );  
U_BOOT_CMD_COMPLETE (
    env, CONFIG_SYS_MAXARGS, 1, do_env,
    "environment handling commands", env_help_text,NULL
);
帶入宏參及其展開為 :
  1. U_BOOT_CMD_COMPLETE(env, CONFIG_SYS_MAXARGS , 1, do_env , "environment handling commands" , env_help_text , NULL ) \  
  2.     ll_entry_declare(cmd_tbl_t, env , cmd) =           \  
  3.         U_BOOT_CMD_MKENT_COMPLETE(env , CONFIG_SYS_MAXARGS , 1, do_env , "environment handling commands" , env_help_text , NULL);  
U_BOOT_CMD_COMPLETE(env, CONFIG_SYS_MAXARGS , 1, do_env , "environment handling commands" , env_help_text , NULL ) \
    ll_entry_declare(cmd_tbl_t, env , cmd) =           \
        U_BOOT_CMD_MKENT_COMPLETE(env , CONFIG_SYS_MAXARGS , 1, do_env , "environment handling commands" , env_help_text , NULL);
其中的ll_entry_declare帶入宏參及其展開為 :
  1. ll_entry_declare(cmd_tbl_t , env , cmd )            \  
  2.     cmd_tbl_t _u_boot_list_2_cmd_2_env __aligned(4)       \  
  3.             __attribute__((unused,              \  
  4.             section(".u_boot_list_2_cmd_2_env )))  
ll_entry_declare(cmd_tbl_t , env , cmd )            \
    cmd_tbl_t _u_boot_list_2_cmd_2_env __aligned(4)       \
            __attribute__((unused,              \
            section(".u_boot_list_2_cmd_2_env )))
其中的U_BOOT_CMD_MKENT_COMPLETE帶入宏參及其展開為:
  1. U_BOOT_CMD_MKENT_COMPLETE(env , CONFIG_SYS_MAXARGS , 1, do_env , _usage, _help, _comp)     \  
  2.         { "env", CONFIG_SYS_MAXARGS , 1, do_env , "environment handling commands" , env_help_text ,NULL}  
U_BOOT_CMD_MKENT_COMPLETE(env , CONFIG_SYS_MAXARGS , 1, do_env , _usage, _help, _comp)     \
        { "env", CONFIG_SYS_MAXARGS , 1, do_env , "environment handling commands" , env_help_text ,NULL}
那么上述U_BOOT_CMD_COMPLETE最終展開為:
  1. cmd_tbl_t _u_boot_list_2_cmd_2_env __aligned(4)       \  
  2.             __attribute__((unused, section(".u_boot_list_2_cmd_2_env ))) =  
  3. "env", CONFIG_SYS_MAXARGS , 1, do_env , "environment handling commands" , env_help_text ,NULL}  
cmd_tbl_t _u_boot_list_2_cmd_2_env __aligned(4)       \
            __attribute__((unused, section(".u_boot_list_2_cmd_2_env ))) =
{ "env", CONFIG_SYS_MAXARGS , 1, do_env , "environment handling commands" , env_help_text ,NULL}
其中的cmd_tbl_t定義為:
  1. <pre code_snippet_id="1890747" snippet_file_name="blog_20160921_20_3676404" name="code" class="cpp">struct cmd_tbl_s {  
  2.     char        *name;      /* Command Name         */  
  3.     int     maxargs;    /* maximum number of arguments  */  
  4.     int     repeatable; /* autorepeat allowed?      */  
  5.                     /* Implementation function  */  
  6.     int     (*cmd)(struct cmd_tbl_s *, intintchar * const []);  
  7.     char        *usage;     /* Usage message    (short) */  
  8. #ifdef  CONFIG_SYS_LONGHELP  
  9.     char        *help;      /* Help  message    (long)  */  
  10. #endif  
  11. #ifdef CONFIG_AUTO_COMPLETE  
  12.     /* do auto completion on the arguments */  
  13.     int     (*complete)(int argc, char * const argv[], char last_char, int maxv, char *cmdv[]);  
  14. #endif  
  15. };  
<pre code_snippet_id="1890747" snippet_file_name="blog_20160921_20_3676404" name="code" class="cpp">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 * const []);
    char        *usage;     /* Usage message    (short) */
#ifdef  CONFIG_SYS_LONGHELP
    char        *help;      /* Help  message    (long)  */
#endif
#ifdef CONFIG_AUTO_COMPLETE
    /* do auto completion on the arguments */
    int     (*complete)(int argc, char * const argv[], char last_char, int maxv, char *cmdv[]);
#endif
};
  1. typedef struct cmd_tbl_s    cmd_tbl_t;  
typedef struct cmd_tbl_s    cmd_tbl_t;
 
          

該結構體包含了命令名,命令實現函數,命令使用簡短說明usage的輸出字符串,幫助回調函數,參數變量自動完成函數等。u-boot使用該結構體來描述一個完整的命令。

U_BOOT_CMD_COMPLETE宏用來定義一個cmd_tbl_t結構體變量,初始化該結構體中的相應成員,並把該結構體變量存放在4字節對齊的.u_boot_list_2_cmd_2_env符號段中。如前所述,宏U_BOOT_CMD將最后一個參數_comp置為NULL,對U_BOOT_CMD_COMPLETE做了進一步的封裝。所有使用U_BOOT_CMD和U_BOOT_CMD_COMPLETE定義的命令最后都集中放在以.u_boot_list_2_cmd_2開頭的符號段中。即.u_boot_list_2_cmd_2_##name,這里的name是命令名。

我們回到函數上述的命令處理函數cmd_process,被其調用的find_cmd將根據命令名查找相應的cmd_tbl_t變量符號段,其實現如下:

  1. cmd_tbl_t *find_cmd(const char *cmd)  
  2. {  
  3.     cmd_tbl_t *start = ll_entry_start(cmd_tbl_t, cmd);  
  4.     const int len = ll_entry_count(cmd_tbl_t, cmd);  
  5.     return find_cmd_tbl(cmd, start, len);  
  6. }  
cmd_tbl_t *find_cmd(const char *cmd)
{
    cmd_tbl_t *start = ll_entry_start(cmd_tbl_t, cmd);
    const int len = ll_entry_count(cmd_tbl_t, cmd);
    return find_cmd_tbl(cmd, start, len);
}
ll_entry_start定義如下:
  1. #define ll_entry_start(_type, _list)                    \  
  2. ({                                  \  
  3.     static char start[0] __aligned(4) __attribute__((unused,    \  
  4.         section(".u_boot_list_2_"#_list"_1")));         \  
  5.     (_type *)&start;                        \  
  6. })  
#define ll_entry_start(_type, _list)                    \
({                                  \
    static char start[0] __aligned(4) __attribute__((unused,    \
        section(".u_boot_list_2_"#_list"_1")));         \
    (_type *)&start;                        \
})
那么,在上述函數find_cmd中,語句  
  1. cmd_tbl_t *start = ll_entry_start(cmd_tbl_t, cmd);  
cmd_tbl_t *start = ll_entry_start(cmd_tbl_t, cmd);
定義一個包含0個字節的數組start[0],且把它放在.u_boot_cmd_2_list_1段中,該段屬性為unsued。注意在u-boot.lds中有:
  1. .u_boot_list : {  
  2.  KEEP(*(SORT(.u_boot_list*)));      
 .u_boot_list : {
  KEEP(*(SORT(.u_boot_list*)));    
.u_boot_list中所有符號是按字符表的先后順序排列的,.u_boot_list_2_list_1會放在所有使用U_BOOT_CMD和U_BOOT_CMD_COMPLETE
定義的符號段的最前面,即.u_boot_cmd_2_list_1為以.u_boot_list_2_cmd_2開頭的符號段中的第一個。它定義為0個字節的數組start[0],
編譯器並不為它分配存儲空間,那么它將指向以.u_boot_list_2_cmd_2開頭的符號段中的第一個符號。
同理ll_entry_end用end[0]來標識.u_boot_list_2_cmd_2_xxx段的結尾,接下來的函數ll_entry_count返回的就是start - end的值,
即符號段.u_boot_list_2_cmd_2_xxx總字節長度。然后調用find_cmd_tbl,根據傳入的.u_boot_list_2_cmd_2_xxx段的首地址和
函數ll_entry_count 返回的長度,根據命令名查找相應的符號段,即相命令對應的cmd_tbl_t結構體變量,然后返回該結構體指針。
find_cmd_tbl的實現如下:
  1. cmd_tbl_t *find_cmd_tbl(const char *cmd, cmd_tbl_t *table, int table_len)  
  2. {  
  3.     cmd_tbl_t *cmdtp;  
  4.     cmd_tbl_t *cmdtp_temp = table;  /* Init value */  
  5.     const char *p;  
  6.     int len;  
  7.     int n_found = 0;  
  8.     if (!cmd)  
  9.         return NULL;  
  10.      len = ((p = strchr(cmd, '.')) == NULL) ? strlen (cmd) : (p - cmd);  
  11.     for (cmdtp = table; cmdtp != table + table_len; cmdtp++) {  
  12.         if (strncmp(cmd, cmdtp->name, len) == 0) {  
  13.             if (len == strlen(cmdtp->name))  
  14.                 return cmdtp;  /* full match */  
  15.             cmdtp_temp = cmdtp; /* abbreviated command ? */  
  16.             n_found++;  
  17.         }  
  18.     }  
  19.     if (n_found == 1) {            /* exactly one match */  
  20.         return cmdtp_temp;  
  21.     }  
  22.     return NULL;   /* not found or ambiguous command */  
  23. }  
cmd_tbl_t *find_cmd_tbl(const char *cmd, cmd_tbl_t *table, int table_len)
{
    cmd_tbl_t *cmdtp;
    cmd_tbl_t *cmdtp_temp = table;  /* Init value */
    const char *p;
    int len;
    int n_found = 0;
    if (!cmd)
        return NULL;
     len = ((p = strchr(cmd, '.')) == NULL) ? strlen (cmd) : (p - cmd);
    for (cmdtp = table; cmdtp != table + table_len; 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 */
}
查找到命令名對應的cmd_tbl_t結構體變量后,cmd_process接下來將調用函數cmd_call執行cmd_tbl_t中的命令。
cmd_process中相應的代碼段如下:
  1. if (!rc) {  
  2.       if (ticks)  
  3.           *ticks = get_timer(0);  
  4.       rc = cmd_call(cmdtp, flag, argc, argv);  
  5.       if (ticks)  
  6.           *ticks = get_timer(*ticks);  
  7.       *repeatable &= cmdtp->repeatable;  
  8.   }  
  9.   if (rc == CMD_RET_USAGE)  
  10.       rc = cmd_usage(cmdtp);  
  if (!rc) {
        if (ticks)
            *ticks = get_timer(0);
        rc = cmd_call(cmdtp, flag, argc, argv);
        if (ticks)
            *ticks = get_timer(*ticks);
        *repeatable &= cmdtp->repeatable;
    }
    if (rc == CMD_RET_USAGE)
        rc = cmd_usage(cmdtp);
變量ticks用來記錄命令的執行時間,repeatable為命令是否自動重復執行標志。這兩個變量都將返回到上層的調用函數。
函數cmd_call利用傳入的參數,直接調用cmdtp->cmd,即:
 (cmdtp->cmd)(cmdtp, flag, argc, argv);
最后,如果命令執行的返回值為CMD_RET_USAGE,代表命令執行出錯,且置標CMD_RET_USAGE ,那么將調用cmd_usage,
輸出簡短的命令使用幫助信息。cmd_usage實現如下:
  1. int cmd_usage(const cmd_tbl_t *cmdtp)  
  2. {  
  3.     printf("%s - %s\n\n", cmdtp->name, cmdtp->usage);  
  4. #ifdef  CONFIG_SYS_LONGHELP  
  5.     printf("Usage:\n%s ", cmdtp->name);  
  6.     if (!cmdtp->help) {  
  7.         puts ("- No additional help available.\n");  
  8.         return 1;  
  9.     }  
  10.     puts(cmdtp->help);  
  11.     putc('\n');  
  12. #endif  /* CONFIG_SYS_LONGHELP */  
  13.     return 1;  
  14. }  
int cmd_usage(const cmd_tbl_t *cmdtp)
{
    printf("%s - %s\n\n", cmdtp->name, cmdtp->usage);
#ifdef  CONFIG_SYS_LONGHELP
    printf("Usage:\n%s ", cmdtp->name);
    if (!cmdtp->help) {
        puts ("- No additional help available.\n");
        return 1;
    }
    puts(cmdtp->help);
    putc('\n');
#endif  /* CONFIG_SYS_LONGHELP */
    return 1;
}
三.u-boot中的子命令
部分u-boot的命令包含子命令,如env命令,它由子命令save,set,edit等組成。類似的還有sf命令。這些主命令執行時必須指定子命令。
u-boot中子命令的實現不再使用上面的gcc關鍵字section來指定段,只是直接定義了一個cmd_tbl_t表,並使用子命令及其運行參數初始化該表。對於上述討論中使用U_BOOT_CMD定義的命令,它們是散放在文件各處的,很難用一個全局的cmd_tbl_t表將這些命令統一定義初始化。而子命令不同,它只定義在一個或少量文件中,該cmd_tbl_t表為static類型,可以在定義時直接填充。當然,主命令還是由宏U_BOOT_CMD來定義引入。

 

 
0
0
 
 
 


免責聲明!

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



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