其中U_BOOT_CMD命令格式以下:函數
U_BOOT_CMD(name,maxargs,repeatable,command,"usage","help")
oop
各個參數的意義以下:spa
name:命令名,非字符串,但在U_BOOT_CMD中用「#」符號轉化爲字符串
.net
maxargs:命令的最大參數個數
命令行
repeatable:是否自動重複(按Enter鍵是否會重複執行)
指針
command:該命令對應的響應函數指針
code
usage:簡短的使用說明(字符串)
blog
help:較詳細的使用說明(字符串)
token
U_BOOT_CMD宏在include/command.h中定義:圖片
#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}
「##」
與「#」
都是預編譯操做符,「##」
有字符串鏈接的功能,「#」
表示後面緊接着的是一個字符串。
其中Struct_Section在include/command.h中定義以下:
#define Struct_Section __attribute__ ((unused,section (".u_boot_cmd")))
凡是帶有attribute ((unused,section (「.u_boot_cmd」))屬性聲明的變量都將被存放在」.u_boot_cmd」段中,而且即便該變量沒有在代碼中顯式的使用編譯器也不產生警告信息。
在u-Boot鏈接腳本 u-boot.lds中定義了」.u_boot_cmd」段:
. = .;
__u_boot_cmd_start = .; /*將 __u_boot_cmd_start指定爲當前地址 */
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .; /* 將__u_boot_cmd_end指定爲當前地址 */
這代表帶有「.u_boot_cmd」聲明的函數或變量將存儲在「u_boot_cmd」段。
這樣只要將u-boot全部命令對應的cmd_tbl_t變量加上「.u_boot_cmd」聲明,編譯器就會自動將其放在「u_boot_cmd」段,查找cmd_tbl_t變量時只要在 __u_boot_cmd_start 與 __u_boot_cmd_end 之間查找就能夠了。
cmd_tbl_t在include/command.h中定義以下:
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
};
typedef struct cmd_tbl_s cmd_tbl_t;
一個cmd_tbl_t結構體變量包含了調用一條命令的所須要的信息。
cmd_tbl_t __u_boot_cmd_boot __attribute__ ((unused,section (".u_boot_cmd"))) = {boot, 1, 1, do_bootd, "boot - boot default, i.e., run 'bootcmd'\n", " NULL"}
int do_bootd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
int rcode = 0;
if (run_command(getenv("bootcmd"), flag) < 0)
rcode = 1;
return rcode;
}
s = getenv ("bootcmd");
if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
......
run_command (s, 0);
......
}
從main_loop中咱們知道,若是bootdelay時間內未按下按鍵則啓動Linux內核,按下按鍵則進入uboot命令行等待用戶輸入命令。
用戶輸入命令則調取run_command函數,在該函數中有下面幾個比較重要的點:
/*
* Find separator, or string end
* Allow simple escape of ';' by writing "\;"
*/
for (inquotes = 0, sep = str; *sep; sep++) {
if ((*sep=='\'') &&
(*(sep-1) != '\\'))
inquotes=!inquotes;
if (!inquotes &&
(*sep == ';') && /* separator */
( sep != str) && /* past string start */
(*(sep-1) != '\\')) /* and NOT escaped */
break;
}
2. 分離參數
/* Extract arguments */
if ((argc = parse_line (finaltoken, argv)) == 0) {
rc = -1; /* no command at all */
continue;
}
/* Look up command in command table */
if ((cmdtp = find_cmd(argv[0])) == NULL) {
printf ("Unknown command '%s' - try 'help'\n", argv[0]);
rc = -1; /* give up after bad command */
continue;
}
在common/command.c 中查看find_cmd函數
/*__u_boot_cmd_start與__u_boot_cmd_end間查找命令,並返回cmdtp->name命令的cmd_tbl_t結構。*/
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++;
}
}
① 在u-boot控制檯中輸入「boot」命令執行時,u-boot控制檯接收輸入的字符串「boot」,傳遞給run_command函數。
② run_command函數調用common/command.c中實現的find_cmd函數在__u_boot_cmd_start與__u_boot_cmd_end間查找命令,並返回boot命令的cmd_tbl_t結構。
③ 而後run_command函數使用返回的cmd_tbl_t結構中的函數指針調用boot命令的響應函數do_bootd,從而完成了命令的執行。
https://blog.csdn.net/yexiangCSDN/article/details/81773093