第1阶段——uboot查找命令run_command函数和命令定义分析(6)

本节主要学习,run_command函数命令查找过程,命令生成过程

1.run_command函数命令查找过程分析:
在u-boot界面中(main_loop();位于u-boot-1.1.6/common/main.c ):
a 输入命令字符串
b 将命令字符串代入函数run_command()
c run_command():判断命令字符串,在argv[0]里保存命令名,并调用find_cmd(argv[0]))函数查找内存中该命令结构体,判断各个参数,执行命令等
d find_cmd(argv[0])):查找.u_boot_cmd命令段中所有命令是否与argv[0]这个命令名字相等,

1.1 首先查看run_command()函数分析,如何判断判断命令:

int run_command (const char *cmd, int flag) //*cmd:入口字符串命令 flag:参数
{
cmd_tbl_t *cmdtp;
char cmdbuf[CFG_CBSIZE];    //cmdbuf:用来备份的
char *str = cmdbuf; //*str指向备份的入口命令
...
if (!cmd || !*cmd) { //先对字符串命令cmd的有效性进行检测,判断该命令是否为空
return -1;    /* empty command */
}
if (strlen(cmd) >= CFG_CBSIZE) { //判断字符串命令的长度是否在CFG_CBSIZE(256)范围之内
puts ("## Command too long!\n");
return -1;
}
strcpy (cmdbuf, cmd); //备份入口命令cmd到cmdbuf

while (*str) { //str指向cmdbuf备份命令,循环判断字符串命令有几个
/*因为uboot允许一次输入多个命令,以下就是分析 是否有多个命令,*/
/* 比如在uboot界面输入"print;md.w 0"回车后,先打印出环境参数后,后打印地址0里存放的数据。*/
for (inquotes = 0, sep = str; *sep; sep++) //sep指向当前命令str的开头,一直for寻找当前命令结尾处
{
if ((*sep==‘\‘‘) && //对"\"解析,分割成多个命令
(*(sep-1) != ‘\\‘))
inquotes=!inquotes;

if (!inquotes &&
(*sep == ‘;‘) &&    //判断当前等于";"
( sep != str) &&    //且当前指向的位置不是命令的开头,
(*(sep-1) != ‘\\‘))
break; //停止本次for循环,sep指向当前这个命令结尾处
}
token= str; //token指向当前命令的开头
if (*sep) { //将当前";"分割符处替换成‘\0‘空字符
str = sep + 1;    //str命令指向下个命令,若下个命令为空,退出while (*str)循环.
*sep = ‘\0‘; //将当前命令结尾";"处替换成‘\0‘空字符
}
else
str = sep;    //如果没有命令了,就指向当前命令底部 

process_macros (token, finaltoken); //token=当前命令开头,将当前命令中的宏替换掉,
//例如命令"nand write .yaffs 30000000 0X00260000 $(kernelsize)":其中$(kernelsize)就是宏,这里将替换成文件大小长度

if ((argc = parse_line (finaltoken, argv)) == 0)
//argc等于参数的个数。
//parse_line函数:解析当前命令用argv数组保存并返回当前命令参数个数,例如"md.w 0"->argv[0]=“md.w”(保存命令), argv[1]=“0”(保存参数)

{
rc = -1;    /* no command at all */
continue;
}

if ((cmdtp = find_cmd(argv[0])) == NULL) {
/* find_cmd(argv[0])) :查找.u_boot_cmd段中是否有这个命令argv[0]名字,若有的话返回这个命令的结构体,否则返回NULL。*/
/* cmdtp: 指向argv[0]命令名字的结构体. */
printf ("Unknown command ‘%s‘ - try ‘help‘\n", argv[0]); //输出提示,未找到命令
rc = -1;    /* give up after bad command */
continue;
}
/*其中find_cmd()返回值和cmdtp都是一个cmd_tbl_s型结构体,其中成员如下所示:
struct cmd_tbl_s {
char    *name;    //命令的名字
int    maxargs;    //命令后带的最大参数个数
int    repeatable;    //定义命令是否可重复,例如:在uboot界面输入"md.w 0"打印后,再次敲回车键继续运行该命令.

int    (*cmd)(struct cmd_tbl_s *, int, int, char *[]); //函数指针,用于命令执行时需要调用什么函数
char    *usage;    // 该命令所对应得较短的使用说明,例如输入“help”,每行命令后面都跟着较短的使用说明
#ifdef    CFG_LONGHELP
char    *help;    // 该命令所对应得较详细的使用说明,例如输入“help md”,会打印出该命令详细的使用说明
#endif
};
*/
if (argc > cmdtp->maxargs) { //检查当前命令的参数个数argc是否在最大参数个数范围内
printf ("Usage:\n%s\n", cmdtp->usage);
rc = -1;
continue;
}

if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) { //cmdtp:当前命令结构体,判断cmdtp->cmd执行命令有没有函数
rc = -1; //执行命令
}

repeatable &= cmdtp->repeatable; //设置命令重复执行标志

if (had_ctrlc ()) //检查是否有ctrl+c按键按下,如果有的话,取消当前命令执行。
return 0;    /* if stopped then not repeatable */
}

return rc ? rc : repeatable;
}

1.2 进入find_cmd()函数分析,如何查找命令:

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); //查找‘.‘这个字符,用来获得当前字符串命令长度len

for (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循环是将*cmd入口参数从所有命令起始段找到命令结束段,直到找到为止。
{
if (strncmp (cmd, cmdtp->name, len) == 0) { //比较len长度的*cmd和cmdtp->name,若相等表示找到一样的实际命令。
if (len == strlen (cmdtp->name)) //再次获取实际命令的长度,判断是否和当前命令的长度一样。
return cmdtp;    //已找到,返回实际命令的结构体
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命令定义分析,分析命令是怎么定义出来的:
例如:"boodcmd=nand read.jffs2 0x30007FC0 kernel;bootm 0x30007FC0 "中bootm命令(定义过程,如何定义的)分析:

2.1“bootm 0x30007FC0” 是使用bootm命令,参数为0x30007FC0, 该命令位于Cmd_bootm.C
先搜索bootm命令,位于./common/Cmd_bootm.C (命令文件都存在common文件里,Cmd_bootm.C就是定义bootm命令的文件)
进入./common/Cmd_bootm.C:

其中执行bootm这个命令时所对应的函数就是:

int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);

这个do_bootm函数等于bootm命令里的宏U_BOOT_CMD->cmd
do_bootm()成员:

cmd_tbl_t *cmdtp :  指向命令段里的bootm命令结构体
flag   :      参数
argc   :      参数个数,例如"bootm 0x30007FC0",那么argc=2。
argv   :      存参数的数组,共argc个.例如"bootm 0x30007FC0",那么argv[0]="bootm",argv[1]="0x30007FC0".

它在U_BOOT_CMD宏里,是因为每个命令都是通过U_BOOT_CMD宏定义调用的,如下:

U_BOOT_CMD(                            //U_BOOT_CMD宏里有bootm成员,CFG_MAXARGS成员等
bootm,    CFG_MAXARGS,    1,    do_bootm,                 // do_bootm是一个函数名
"bootm - boot application image from memory\n",
"[addr [arg ...]]\n - boot application image stored in memory\n" //usage成员,较短的帮助说明
"\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成员,详细的帮助说明
#endif
);

2.2 再来看看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宏各个参数意义如下:

cmd_tbl_t: 定义__u_boot_cmd_bootm的类型为cmd_tbl_t结构体
##name:    指向name,其中name指向第2.1节里面U_BOOT_CMD宏里的第一个成员bootm.
Struct_Section :     保存命令的段位置参数,在./include/Command.h中定义, “#define Struct_Section __attribute__ ((unused,section (".u_boot_cmd")))”,section表示强制将 段属性设为.u_boot_cmd命令段
#name:     U_BOOT_CMD宏里第一个成员,命令名字,等于"bootm"
maxargs:  最大参数个数,等于CFG_MAXARGS
rep:        [repeat]是否支持重复,等于1,表示支持
cmd:          执行命令后对应的函数指针,执行命令时就会使用该指针 , 在2.1节里,
usage:保存字符串,用于较短的帮助说明,等于"bootm - boot application image from memory\n"
help:用于详细的帮助说明,等于U_BOOT_CMD宏里usage成员后剩下的几行字符串(它们之间没有加逗号,所以那几行字符串都是连接在一起的).

2.4所以对于bootm命令,最终扩展开为: cmd_tbl_t __u_boot_cmd_bootm __attribute__ ((unused,section (".u_boot_cmd"))) /
={bootm, CFG_MAXARGS, 1, do_bootm, "字符串1",""字符串2"}

所有uboot中命令定义都是通过 U_BOOT_CMD宏 保存在.u_boot_cmd段中,通过run_command()函数调用.
接下来学习怎么仿照bootm命令来制作hello命令。

时间: 2024-10-25 05:19:29

第1阶段——uboot查找命令run_command函数和命令定义分析(6)的相关文章

uboot移植之start_armboot()函数分析

/******************************** uboot的第二阶段就是初始化剩下的还没在第一阶段初始化的硬件.主要是SoC外部硬件(譬如 iNand 网卡芯片....... )uboot本身的一些东西(uboot的命令 环境变量等.....).然后最终初始化完必要的东西后进入到uboot的命令行准备接受命令. ***********************************/ void start_armboot (void)       //这个函数构成了uboot

uboot启动第二阶段--start_armboot函数

uboot第二阶段应该做什么? uboot的第二阶段就是要初始化剩下的还没被初始化的硬件,主要是SOC外部硬件(譬如inand.网卡芯片).uboot本身的一些东西(uboot的命令.环境变量等),然后最终初始化完必要的东西后进入uboot的命令行准备接受命令. uboot第二阶段完结于何处? uboot启动后自动运行打印出很多信息,这些信息就是uboot第一和第二阶段不断进行初始化时,打印出来的信息,然后uboot进入了bootdelay然后执行bootcmd对应的启动命令,如果这时候用户不干

Oracle SQL*plus常用的命令和函数

Oracle中常用的命令和函数,做个整理,以备以后用到,方便查阅. 常用命令: 连接sqlplus命令行下运行cmd进入,如以sys模式登陆,命令如下:(1).sqlplus "sys/zhb126 as sysdba" (2).sqlplus/nolog  connect sys/zhb126 as sysdba (3).sqlplus scott/tiger 启动数据库实例 startup --启动数据库的同时启动控制文件.数据文件 startup mount --启动数据库的同时

linux中查找(find、locate、which、whereis、grep)命令汇总、帮助命令(man、whatis、apropos、info、help)汇总

(一)find命令详解 find:功能:文件搜索: 语法:find[搜索范围][匹配条件]:  只要匹配条件完全符合才可以被显示,使用通配符*匹配条件*则可以显示匹配条件的所有目录,问号?匹配单个字符 所在路径:/bin/find:按照名字查找文件: eg:# find /tmp -name *test*:区分大小写,显示所有包含test的文件: # find /tmp -iname *test* :不区分大小写,显示所有包含test的文件 按照所有者查找文件: find / -user zxh

执行shell命令的函数——system()、popen()

1.FILE* popen(const char* cmd,const char* type); int pclose(FILE* stream); popen()函数fork()一个子进程,创建管道用于父子进程间通信,父进程要么从管道读,要么往管道写,执行一个shell以运行命令来开启一个进程 相比于system()的又是在于使用简单,popen()只返回两个值,成功返回子进程的status,失败返回-1 2.int system(const char* cmd); 处理了fork().exe

linux--shift命令-shell函数-shell脚本实战

•     将windows中的脚本导入到Linux系统后执行报错•     Shift参数左移指令•     shell中函数使用方法•     shell脚本实战:mysql自动备份和自动解压ZIP 文件脚本 将windows中的脚本导入到Linux系统后执行报错linux与windows换行符问题使用dos2unix 工具    dos2unix Filename================================================================

find——文件查找命令 linux一些常用命令

find 命令eg: 一般文件查找方法: 1.  find /home -name file  ,  在/home目录下查找文件名为file的文件2.  find /home -name '*file*'  ,  在/home目录下查找文件名包含file的文件3.  find /home -name 'file*'  ,  在/home目录下查找以file开头的文件名的文件4.  find /home -size 512c  ,    在/home目录下查找512kb大小的文件5.  find

查找与引用函数

一.查找与引用函数的清单 二.VLOOKUP函数模型 三.VLOOKUP实例 四.个人所得税 五.offset应用基础 六.offset,合并单元格快速填充指定内容 七.MATCH函数 八.INDEX函数 九.积累数据 十.相同个数 十一.提取姓名 十二.index+match函数的组合应用 十三.INDIRECT理解 十四.二级组合框 十五.HLOOKUP函数 十六.动态计算学生总成绩 原文地址:https://www.cnblogs.com/LUOyaXIONG/p/10420776.htm

Linux一步步学习(一)命令行下执行命令

因为之前申请了阿里云服务器(免费体验半年),所以刚好用阿里云的服务器安装了个Ubuntu12.04 64位PHP的运行环境 本次主要对基础命令行的总结: (1)显示日期与实践的命令:date (2)显示日历的命令:cal (3)简单好用的计算器:bc (4)重要热键[tab],[ctrl]-c,[ctrl]-d (5)man page与info page (6)超简单文本编辑器:nano (7)惯用关机命令:shutdown 开始学习: (1)显示日期与实践的命令:date 直接输入date,则