第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 -; /* empty command */
}
if (strlen(cmd) >= CFG_CBSIZE) { //判断字符串命令的长度是否在CFG_CBSIZE(256)范围之内
puts ("## Command too long!\n");
return -;
}
strcpy (cmdbuf, cmd); //备份入口命令cmd到cmdbuf while (*str) { //str指向cmdbuf备份命令,循环判断字符串命令有几个
/*因为uboot允许一次输入多个命令,以下就是分析 是否有多个命令,*/
/* 比如在uboot界面输入"print;md.w 0"回车后,先打印出环境参数后,后打印地址0里存放的数据。*/
for (inquotes = , sep = str; *sep; sep++) //sep指向当前命令str的开头,一直for寻找当前命令结尾处
{
if ((*sep=='\'') && //对"\"解析,分割成多个命令
(*(sep-) != '\\'))
inquotes=!inquotes; if (!inquotes &&
(*sep == ';') && //判断当前等于";"
( sep != str) && //且当前指向的位置不是命令的开头,
(*(sep-) != '\\'))
break; //停止本次for循环,sep指向当前这个命令结尾处
}
token= str; //token指向当前命令的开头
if (*sep) { //将当前";"分割符处替换成'\0'空字符
str = sep + ; //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)) == )
//argc等于参数的个数。
//parse_line函数:解析当前命令用argv数组保存并返回当前命令参数个数,例如"md.w 0"->argv[0]=“md.w”(保存命令), argv[1]=“0”(保存参数) {
rc = -; /* no command at all */
continue;
} if ((cmdtp = find_cmd(argv[])) == NULL) {
/* find_cmd(argv[0])) :查找.u_boot_cmd段中是否有这个命令argv[0]名字,若有的话返回这个命令的结构体,否则返回NULL。*/
/* cmdtp: 指向argv[0]命令名字的结构体. */
printf ("Unknown command '%s' - try 'help'\n", argv[]); //输出提示,未找到命令
rc = -; /* 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 = -;
continue;
} if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != ) { //cmdtp:当前命令结构体,判断cmdtp->cmd执行命令有没有函数
rc = -; //执行命令
} repeatable &= cmdtp->repeatable; //设置命令重复执行标志 if (had_ctrlc ()) //检查是否有ctrl+c按键按下,如果有的话,取消当前命令执行。
return ; /* 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 = ;
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) == ) { //比较len长度的*cmd和cmdtp->name,若相等表示找到一样的实际命令。
if (len == strlen (cmdtp->name)) //再次获取实际命令的长度,判断是否和当前命令的长度一样。
return cmdtp; //已找到,返回实际命令的结构体
cmdtp_temp = cmdtp; /* abbreviated command ? */
n_found++;
}
} if (n_found == ) { /* 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=。
argv : 存参数的数组,共argc个.例如"bootm 0x30007FC0",那么argv[]="bootm",argv[]="0x30007FC0".
它在U_BOOT_CMD宏里,是因为每个命令都是通过U_BOOT_CMD宏定义调用的,如下:
U_BOOT_CMD( //U_BOOT_CMD宏里有bootm成员,CFG_MAXARGS成员等
bootm, CFG_MAXARGS, , 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命令。
第1阶段——uboot分析之查找命令run_command函数和命令定义过程(6)的更多相关文章
- 第1阶段——uboot分析之硬件初始化start_armboot函数(5)
start_armboot()分析:在start.S初始化后跳转到start_armboot实现第2阶段硬件相关的初始化(烧写擦除flash,网卡驱动,usb驱动,串口驱动,从FLASH读内核,启动内 ...
- 第1阶段——uboot分析之仿照bootm制作hello命令(7)
仿照bootm命令生成来制作一个hello命令,功能:打印出hello,world!和参数值 1.点击New File ,创建cmd_hello.c将./common/cmd_bootm.c的头文件复 ...
- 第1阶段——uboot分析之通过nand命令读内核(8)
本节主要学习: 详细分析UBOOT中"bootcmd=nand read.jffs2 0x30007FC0 kernel;bootm 0x30007FC0" 怎么实现nand命令读 ...
- 第1阶段——uboot分析之启动函数bootm命令 (9)
本节主要学习: 详细分析UBOOT中"bootcmd=nand read.jffs2 0x30007FC0 kernel;bootm 0x30007FC0"中怎么实现bootm命令 ...
- 第1阶段——u-boot分析之make指令(2)
通过make 100ask24x0_config 指令配置好芯片选型后,使用make指令来生成uboot.bin文件 本文学习目标: 对Makefile文件进行基本了解,掌握make指令是怎么实现生成 ...
- 第1阶段——uboot分析之硬件初始化start.S(4)
分析uboot第一个执行函数_start(cpu/arm920t/start.S) 打开cpu/arm920t/start.S .globl _start // .globl定义一个全局符号" ...
- 第1阶段——u-boot分析之make 100ask24x0_config指令(1)
本文学习目标: 掌握"make 100ask24x0_config"指令在Makefile和mkconfig文件中是怎么实现配置芯片选型 1.执行make 100a ...
- 菜刀(代码执行)函数和命令执行函数详解及Getshell方法
i春秋作家:大家奥斯的哦 原文来自:https://bbs.ichunqiu.com/thread-41471-1-1.html 代码执行函数 VS 命令执行函数 一直想整理这两块的内容,但是一直没时 ...
- 【随笔】菜刀(代码执行)函数和命令执行函数详解及Getshell方法
代码执行函数 VS 命令执行函数 一直想整理这两块的内容,但是一直没时间弄,直到前两天碰上一个写入了菜刀马但是死活连不上菜刀的站,顿时不知道怎么继续了,所以就趁这个机会整理了一下代码执行函数怎么get ...
随机推荐
- JAVA基础2----数据类型和运算符
Java数据类型 1.基本数据类型 整数:byte/short/int/long byte:-128~127 (1个字节) short:-2^15~2^15-1 (2个字节) int(默认类型):-2 ...
- UE4 C++BeginPlay And BlueprintBeginPlay
今天遇到了一个诡异的问题,经过几个小时的煎熬终于找到了原因.mmmp 如果有一个类AActorChild,这个AActorChild继承自AActor,再有一个蓝图类BPAActorChild. 蓝图 ...
- wamp+python+CGI+wingIDE
一.环境配置情况 windows7 32位 wamp2.5 python3.5.2 wingIDE5.1.12 上述软件下载安装按照自己的意愿行事. 二.配置 wamp支持cgi和python: ...
- ARP与RARP协议及arp脚本
1.什么是ARP与RARP协议 地址解析协议,即ARP(Address Resolution Protocol),是根据IP地址获取物理地址的一个TCP/IP协议. 在⽹络通讯时,源主机的应⽤程序知道 ...
- NYOJ--21--bfs--三个水杯
/* 输入 第一行一个整数N(0<N<50)表示N组测试数据 接下来每组测试数据有两行,第一行给出三个整数V1 V2 V3 (V1>V2>V3 V1<100 V3> ...
- mybatis 详解(十)------ 逆向工程
通过前面的学习,在实际开发中,我们基本上能对mybatis应用自如了,但是我们发现了一个问题,所有操作都是围绕着po类,xxxMapper.xml文件,xxxMapper接口等文件来进行的.如果实际开 ...
- 扩展Python模块系列(三)----参数解析与结果封装
在上一节中,通过一个简单的例子介绍了C语言扩展Python内建模块的整体流程,从本节开始讲开始深入讨论一些细节问题,在细节讨论中从始至终都会涉及[引用计数]的问题.首先讨论C语言封装的Python函数 ...
- HDU 3625 Examining the Rooms:第一类stirling数
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3625 题意: 有n个房间,每个房间里放着一把钥匙,对应能开1到n号房间的门. 除了1号门,你可以踹开任 ...
- 王佩丰第2讲-excel单元格格式设置 笔记
点小箭头都可以进入单元格格式设置 跨越合并 添加斜线 回车 ALT+ENTER 格式刷 数字格式 特定红色 货币VS会计专用 日期 2是1月2号,3是1月3号-- 自定义[例子中是在数值后面加&quo ...
- python---scrapy之MySQL同步存储
假设我们已经能获取到item里定义的字段的数据,接下来就需要保存item的数据到mysql数据库. pipeline用来存储item中的数据,将爬取到的数据进行二次处理 首先,要做的准备的工作,安装M ...