一、run_command函数
前面我们说到,u-boot的核心就是run_command这个函数,那么我们就来分析一下这个函数具体要做那些事情。
1321行,对命令进行解析。举个例子:
比如说,md.w 0这个命令,它就能解析成为:Argv[0]=”md” Argv[1]=”0
那么这个代表什么意思呢?接着往下看:
1327行,这个函数提取1321行解析后的参数,那就先跟踪cmdtp这个变量是如何定义的:cmd_tbl_t *cmdtp;继续跟踪这个结构体:
在for循环里面,从u-boot_command_start到u-boot_command_end之间寻找,也就是比较输入的命令名和原来参数中的命令名是否一致,若是一致,就返回这结构体,若是不一致,就指向下一个。
那么这个时候问题来了,u-boot_command_star和u-boot_command_end到底是什么?请参考前一篇我转载博客《Linux链接脚本分析》,在链接脚本中有定义:
_u-boot_command_start=.;
.u_boot_cmd:{*(..u_boot_cmd)}
_u-boot_command_end=.;
那么我们继续来搜索一下.u_boot_cmd,其位于command.h(include,定义如下:
#define Struct_Section __attribute__ ((unused,section (".u_boot_cmd"))
也就是说,定义好的命令放在u_boot_cmd里面,每次输入命令时都会从这个段里面寻找是否有名字相同的命令,若是找到,就返回这个结构体,也就是命令的具体消息和要处理的内容。若是没有找到就打印相关的信息。二、bootm命令。
通过前面几篇博客的分析,我们知道,u-boot要启动Linux内核是通过bootm这个命令实现的。那么bootm到底是什么?我们可以来搜索一下:
接着再来搜下U_BOOT_CMD这个宏:
对比上述两段代码:
首先98行中的name是命令的名字,也就是bootm ,第二个参数是struct_section 对应的就是我们上面分析的结构体。这就相当于,给这个结构体的成员赋值:
name=bootm; maxarg=CFG_MAXARG; rep=1; cmd=do_bootm,usage和help分别对应下面的字符串。
我们再来看一下上面说到的Struct_Section 的定义:
#define Struct_Section __attribute__ ((unused,section (".u_boot_cmd"))
从这个定义中我们可以看到,u_boot_cmd这个命令会被强制转换成这个结构体,由此,把所有的命令都保存在.u_boot_cmd:{*(..u_boot_cmd)}这个段里面。每次只要比较输入命令的名字和这个段中保存的命令名字即可匹配(上面run_command中的for函数)。
三、添加一个命令
通过上面的分析,我们知道命令的格式以及如何实现,接下来就可以仿照这样的格式自己编写一个命令。
1、首先写这个命令要处理的函数:
do_test (cmdtp, flag, argc, argv)
{
printf("this is a test for adding a u-boot command\n");
}
2、接着对U_BOOT_CMD进行赋值:
U_BOOT_CMD(
test, CFG_MAXARGS, 1,do_test ,
“this is my test command usage.....\n"
"this is the long help msg of my test.....\n"
);
这就完成了一个简单u-boot命令的编写,我们只要把这个c文件加到u-boot工程下的common目录下编译即可。
其他的命令可以仿照这个格式来写。