第1阶段——uboot分析之查找命令run_command函数和命令定义过程(6)
本節(jié)主要學(xué)習(xí),run_command函數(shù)命令查找過(guò)程,命令生成過(guò)程
1.run_command函數(shù)命令查找過(guò)程分析:
在u-boot界面中(main_loop();位于u-boot-1.1.6/common/main.c ):
a 輸入命令字符串
b 將命令字符串代入函數(shù)run_command()
c run_command():判斷命令字符串,在argv[0]里保存命令名,并調(diào)用find_cmd(argv[0]))函數(shù)查找內(nèi)存中該命令結(jié)構(gòu)體,判斷各個(gè)參數(shù),執(zhí)行命令等
d find_cmd(argv[0])):查找.u_boot_cmd命令段中所有命令是否與argv[0]這個(gè)命令名字相等,
1.1 首先查看run_command()函數(shù)分析,如何判斷判斷命令:
?
int run_command (const char *cmd, int flag) //*cmd:入口字符串命令 flag:參數(shù) { cmd_tbl_t *cmdtp; char cmdbuf[CFG_CBSIZE]; //cmdbuf:用來(lái)備份的 char *str = cmdbuf; //*str指向備份的入口命令 ... if (!cmd || !*cmd) { //先對(duì)字符串命令cmd的有效性進(jìn)行檢測(cè),判斷該命令是否為空 return -1; /* empty command */ } if (strlen(cmd) >= CFG_CBSIZE) { //判斷字符串命令的長(zhǎng)度是否在CFG_CBSIZE(256)范圍之內(nèi) puts ("## Command too long!\n"); return -1; } strcpy (cmdbuf, cmd); //備份入口命令cmd到cmdbufwhile (*str) { //str指向cmdbuf備份命令,循環(huán)判斷字符串命令有幾個(gè) /*因?yàn)閡boot允許一次輸入多個(gè)命令,以下就是分析 是否有多個(gè)命令,*/ /* 比如在uboot界面輸入"print;md.w 0"回車后,先打印出環(huán)境參數(shù)后,后打印地址0里存放的數(shù)據(jù)。*/ for (inquotes = 0, sep = str; *sep; sep++) //sep指向當(dāng)前命令str的開(kāi)頭,一直for尋找當(dāng)前命令結(jié)尾處 { if ((*sep=='\'') && //對(duì)"\"解析,分割成多個(gè)命令 (*(sep-1) != '\\')) inquotes=!inquotes;if (!inquotes && (*sep == ';') && //判斷當(dāng)前等于";" ( sep != str) && //且當(dāng)前指向的位置不是命令的開(kāi)頭, (*(sep-1) != '\\')) break; //停止本次for循環(huán),sep指向當(dāng)前這個(gè)命令結(jié)尾處 } token= str; //token指向當(dāng)前命令的開(kāi)頭 if (*sep) { //將當(dāng)前";"分割符處替換成'\0'空字符 str = sep + 1; //str命令指向下個(gè)命令,若下個(gè)命令為空,退出while (*str)循環(huán). *sep = '\0'; //將當(dāng)前命令結(jié)尾";"處替換成'\0'空字符 } else str = sep; //如果沒(méi)有命令了,就指向當(dāng)前命令底部 process_macros (token, finaltoken); //token=當(dāng)前命令開(kāi)頭,將當(dāng)前命令中的宏替換掉, //例如命令"nand write .yaffs 30000000 0X00260000 $(kernelsize)":其中$(kernelsize)就是宏,這里將替換成文件大小長(zhǎng)度if ((argc = parse_line (finaltoken, argv)) == 0) //argc等于參數(shù)的個(gè)數(shù)。 //parse_line函數(shù):解析當(dāng)前命令用argv數(shù)組保存并返回當(dāng)前命令參數(shù)個(gè)數(shù),例如"md.w 0"->argv[0]=“md.w”(保存命令), argv[1]=“0”(保存參數(shù)) { rc = -1; /* no command at all */ continue; }if ((cmdtp = find_cmd(argv[0])) == NULL) { /* find_cmd(argv[0])) :查找.u_boot_cmd段中是否有這個(gè)命令argv[0]名字,若有的話返回這個(gè)命令的結(jié)構(gòu)體,否則返回NULL。*/ /* cmdtp: 指向argv[0]命令名字的結(jié)構(gòu)體. */ printf ("Unknown command '%s' - try 'help'\n", argv[0]); //輸出提示,未找到命令 rc = -1; /* give up after bad command */ continue; } /*其中find_cmd()返回值和cmdtp都是一個(gè)cmd_tbl_s型結(jié)構(gòu)體,其中成員如下所示: struct cmd_tbl_s { char *name; //命令的名字 int maxargs; //命令后帶的最大參數(shù)個(gè)數(shù) int repeatable; //定義命令是否可重復(fù),例如:在uboot界面輸入"md.w 0"打印后,再次敲回車鍵繼續(xù)運(yùn)行該命令.int (*cmd)(struct cmd_tbl_s *, int, int, char *[]); //函數(shù)指針,用于命令執(zhí)行時(shí)需要調(diào)用什么函數(shù) char *usage; // 該命令所對(duì)應(yīng)得較短的使用說(shuō)明,例如輸入“help”,每行命令后面都跟著較短的使用說(shuō)明 #ifdef CFG_LONGHELP char *help; // 該命令所對(duì)應(yīng)得較詳細(xì)的使用說(shuō)明,例如輸入“help md”,會(huì)打印出該命令詳細(xì)的使用說(shuō)明 #endif }; */ if (argc > cmdtp->maxargs) { //檢查當(dāng)前命令的參數(shù)個(gè)數(shù)argc是否在最大參數(shù)個(gè)數(shù)范圍內(nèi) printf ("Usage:\n%s\n", cmdtp->usage); rc = -1; continue; }if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) { //cmdtp:當(dāng)前命令結(jié)構(gòu)體,判斷cmdtp->cmd執(zhí)行命令有沒(méi)有函數(shù) rc = -1; //執(zhí)行命令 }repeatable &= cmdtp->repeatable; //設(shè)置命令重復(fù)執(zhí)行標(biāo)志if (had_ctrlc ()) //檢查是否有ctrl+c按鍵按下,如果有的話,取消當(dāng)前命令執(zhí)行。 return 0; /* if stopped then not repeatable */ }return rc ? rc : repeatable; }?
1.2 進(jìn)入find_cmd()函數(shù)分析,如何查找命令:
cmd_tbl_t *find_cmd (const char *cmd) //*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; len = ((p = strchr(cmd, '.')) == NULL) ? strlen (cmd) : (p - cmd); //查找'.'這個(gè)字符,用來(lái)獲得當(dāng)前字符串命令長(zhǎng)度lenfor (cmdtp = &__u_boot_cmd_start; cmdtp != &__u_boot_cmd_end; cmdtp++) //上面的__u_boot_cmd_start和__u_boot_cmd_end在board/100ask24x0/u-boot.lds連接腳本里已定義. //所以for循環(huán)是將*cmd入口參數(shù)從所有命令起始段找到命令結(jié)束段,直到找到為止。 { if (strncmp (cmd, cmdtp->name, len) == 0) { //比較len長(zhǎng)度的*cmd和cmdtp->name,若相等表示找到一樣的實(shí)際命令。 if (len == strlen (cmdtp->name)) //再次獲取實(shí)際命令的長(zhǎng)度,判斷是否和當(dāng)前命令的長(zhǎng)度一樣。 return cmdtp; //已找到,返回實(shí)際命令的結(jié)構(gòu)體 cmdtp_temp = cmdtp; /* abbreviated command ? */ n_found++; } }if (n_found == 1) { /* exactly one match */ return cmdtp_temp; }return NULL; /* not found or ambiguous command */ }2命令定義分析,分析命令是怎么定義出來(lái)的:
例如:"boodcmd=nand read.jffs2 0x30007FC0 kernel;bootm 0x30007FC0 "中bootm命令(定義過(guò)程,如何定義的)分析:
2.1“bootm 0x30007FC0” 是使用bootm命令,參數(shù)為0x30007FC0, 該命令位于Cmd_bootm.C
先搜索bootm命令,位于./common/Cmd_bootm.C (命令文件都存在common文件里,Cmd_bootm.C就是定義bootm命令的文件)
進(jìn)入./common/Cmd_bootm.C:
其中執(zhí)行bootm這個(gè)命令時(shí)所對(duì)應(yīng)的函數(shù)就是:
這個(gè)do_bootm函數(shù)等于bootm命令里的宏U_BOOT_CMD->cmd
do_bootm()成員:
它在U_BOOT_CMD宏里,是因?yàn)槊總€(gè)命令都是通過(guò)U_BOOT_CMD宏定義調(diào)用的,如下:
U_BOOT_CMD( //U_BOOT_CMD宏里有bootm成員,CFG_MAXARGS成員等 bootm, CFG_MAXARGS, 1, do_bootm, // do_bootm是一個(gè)函數(shù)名 "bootm - boot application image from memory\n", "[addr [arg ...]]\n - boot application image stored in memory\n" //usage成員,較短的幫助說(shuō)明 "\tpassing arguments 'arg ...'; when booting a Linux kernel,\n" "\t'arg' can be the address of an initrd image\n" #ifdef CONFIG_OF_FLAT_TREE "\tWhen booting a Linux kernel which requires a flat device-tree\n" "\ta third argument is required which is the address of the of the\n" "\tdevice-tree blob. To boot that kernel without an initrd image,\n" "\tuse a '-' for the second argument. If you do not pass a third\n" "\ta bd_info struct will be passed instead\n" //help成員,詳細(xì)的幫助說(shuō)明 #endif );?
2.2 再來(lái)看看U_BOOT_CMD宏是怎么定義的,宏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}這里定義了全局變量:U_BOOT_CMD(name,maxargs,rep,cmd,usage,help)等于"cmd_tbl_t __u_boot_cmd_##name Struct_Section={#name, maxargs, rep, cmd, usage, help}"
2.3 其中U_BOOT_CMD宏各個(gè)參數(shù)意義如下:
?
cmd_tbl_t: 定義__u_boot_cmd_bootm的類型為cmd_tbl_t結(jié)構(gòu)體
##name: ? ?指向name,其中name指向第2.1節(jié)里面U_BOOT_CMD宏里的第一個(gè)成員 ? ? ? ? ? ? ? ? ? ? ? bootm.
Struct_Section : ? ? 保存命令的段位置參數(shù),在./include/Command.h中定義, “#define Struct_Section __attribute__ ((unused,section (".u_boot_cmd")))”,section表示強(qiáng)制將 段屬性設(shè)為.u_boot_cmd命令段
#name: ? ? U_BOOT_CMD宏里第一個(gè)成員,命令名字,等于"bootm"
maxargs: ?最大參數(shù)個(gè)數(shù),等于CFG_MAXARGS
rep: ? ? ? ?[repeat]是否支持重復(fù),等于1,表示支持
cmd: ? ? ? ? ?執(zhí)行命令后對(duì)應(yīng)的函數(shù)指針,執(zhí)行命令時(shí)就會(huì)使用該指針 , 在2.1節(jié)里,
usage:保存字符串,用于較短的幫助說(shuō)明,等于上面代碼里"bootm - boot application ? ? ? ? ? ? ? ? ? ? image from ?memory\n"
help:用于詳細(xì)的幫助說(shuō)明,等于U_BOOT_CMD宏里usage成員后剩下的幾行字符串 ?(它們之間沒(méi)有加逗號(hào),所以那幾行字符串都是連接在一起的).
?
2.4所以對(duì)于bootm命令,最終擴(kuò)展開(kāi)為: cmd_tbl_t __u_boot_cmd_bootm __attribute__ ((unused,section (".u_boot_cmd"))) /
={bootm, CFG_MAXARGS, 1, do_bootm, "字符串1",""字符串2"}
所有uboot中命令定義都是通過(guò) U_BOOT_CMD宏 保存在.u_boot_cmd段中,通過(guò)run_command()函數(shù)調(diào)用.
接下來(lái)學(xué)習(xí)怎么仿照bootm命令來(lái)制作hello命令。
總結(jié)
以上是生活随笔為你收集整理的第1阶段——uboot分析之查找命令run_command函数和命令定义过程(6)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 《ASP.NET MVC企业实战》(二)
- 下一篇: 思科推出EnergyWise合作伙伴计划