从零开始的UBOOT的学习8--命令体系

参考朱有鹏UBOOT全集的一部分

1、从UBOOT的启动阶段的第二流程到命令体系

(1)在UBOOT中使用一个死循环,实现了命令体系:

在这个main_loop()函数里面实现了命令的注册,存储,解析,处理的过程
而且这个是一个死循环,也就是说会不断的执行这个函数。

    for (;;) {main_loop ();}

2、从零开始分析这个函数main_loop()

void main_loop (void)
{static char lastcommand[CFG_CBSIZE] = { 0, };
//定义的最近的使用的命令,是用来使用回车键执行的命令int len;int rc = 1;int flag;char *s;   //定义一个字符数组int bootdelay;  //定义一个开机倒计时的功能//如果定义了UBOOT的版本说明
#ifdef CONFIG_VERSION_VARIABLE{extern char version_string[];setenv ("ver", version_string);  /* set version variable */}
#endif /* CONFIG_VERSION_VARIABLE */#ifdef CFG_HUSH_PARSERu_boot_hush_start ();
#endif//使用fastboot来烧写程序
#ifdef CONFIG_FASTBOOTif (fastboot_preboot())run_command("fastboot", 0);
#endif#ifdef CONFIG_PREBOOTif ((p = getenv ("preboot")) != NULL) {#ifdef CONFIG_AUTOBOOT_KEYEDint prev = disable_ctrlc(1);    /* disable Control C checking */#endif#ifndef CFG_HUSH_PARSERrun_command (p, 0);#elseparse_string_outer(p, FLAG_PARSE_SEMICOLON |FLAG_EXIT_FROM_LOOP);#endif#ifdef CONFIG_AUTOBOOT_KEYEDdisable_ctrlc(prev);    /* restore Control C checking */#endif}
#endif /* CONFIG_PREBOOT *///这里通过得到环境变量的值来判断程序
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)s = getenv ("bootdelay");bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);# ifdef CONFIG_BOOT_RETRY_TIMEinit_cmd_timeout ();
# endif    /* CONFIG_BOOT_RETRY_TIME */#ifdef CONFIG_POSTif (gd->flags & GD_FLG_POSTFAIL) {s = getenv("failbootcmd");}else
#endif /* CONFIG_POST */#ifdef CONFIG_BOOTCOUNT_LIMITif (bootlimit && (bootcount > bootlimit)) {printf ("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n",(unsigned)bootlimit);s = getenv ("altbootcmd");}else
#endif /* CONFIG_BOOTCOUNT_LIMIT */s = getenv ("bootcmd");debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
#ifdef CONFIG_AUTOBOOT_KEYEDint prev = disable_ctrlc(1);    /* disable Control C checking */
#endif#ifndef CFG_HUSH_PARSERrun_command (s, 0);
#elseparse_string_outer(s, FLAG_PARSE_SEMICOLON |FLAG_EXIT_FROM_LOOP);
#endif#ifdef CONFIG_AUTOBOOT_KEYEDdisable_ctrlc(prev);    /* restore Control C checking */
#endif}#ifdef CONFIG_MENUKEYif (menukey == CONFIG_MENUKEY) {s = getenv("menucmd");if (s) {
#ifndef CFG_HUSH_PARSERrun_command (s, 0);
#elseparse_string_outer(s, FLAG_PARSE_SEMICOLON |FLAG_EXIT_FROM_LOOP);
#endif}}
#endif /* CONFIG_MENUKEY */
#endif    /* CONFIG_BOOTDELAY *//** Main Loop for Monitor Command Processing*/
#ifdef CFG_HUSH_PARSERparse_file_outer();/* This point is never reached */for (;;);
#elsefor (;;) {#ifdef CONFIG_BOOT_RETRY_TIMEif (rc >= 0) {/* Saw enough of a valid command to* restart the timeout.*/reset_cmd_timeout();}#endiflen = readline (CFG_PROMPT);flag = 0;    /* assume no special flags for now */if (len > 0)strcpy (lastcommand, console_buffer);else if (len == 0)flag |= CMD_FLAG_REPEAT;
#ifdef CONFIG_BOOT_RETRY_TIMEelse if (len == -2) {/* -2 means timed out, retry autoboot*/puts ("\nTimed out waiting for command\n");#ifdef CONFIG_RESET_TO_RETRY/* Reinit board to run initialization code again */do_reset (NULL, 0, 0, NULL);#elsereturn;        /* retry autoboot */#endif}
#endifif (len == -1)puts ("<INTERRUPT>\n");elserc = run_command (lastcommand, flag);if (rc <= 0) {/* invalid command or not repeatable, forget it */lastcommand[0] = 0;}}
#endif /*CFG_HUSH_PARSER*/
}

这是执行运行命令的函数

int run_command (const char *cmd, int flag)
{cmd_tbl_t *cmdtp;char cmdbuf[CFG_CBSIZE]; //定义了一个字符数组,用来存储命令char *token;            /* start of token in cmdbuf    */char *sep;            /* end of token (separator) in cmdbuf */char finaltoken[CFG_CBSIZE];char *str = cmdbuf;char *argv[CFG_MAXARGS + 1];    /* NULL terminated    */int argc, inquotes;int repeatable = 1;int rc = 0;clear_ctrlc(); //Ctrl C来打断程序的运行if (!cmd || !*cmd) {return -1;    /* empty command */}//如果命令的长度,比512个字节来大的话,打印执行的命令太长if (strlen(cmd) >= CFG_CBSIZE) {puts ("## Command too long!\n");return -1;}strcpy (cmdbuf, cmd);//把cmd的命令存储到cmdbuf中去//此指针是字符数组while (*str) {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;}/** Limit the token to data between separators*/token = str;if (*sep) {str = sep + 1;    /* start of command for next pass */*sep = '\0';}elsestr = sep;    /* no more commands for next pass */
#ifdef DEBUG_PARSERprintf ("token: \"%s\"\n", token);
#endif/* Extract arguments */if ((argc = parse_line (finaltoken, argv)) == 0) {rc = -1;    /* no command at all */continue;}//通过查找命令不断的从命令池中轮询命令,没有的话,打印不确定的命令if ((cmdtp = find_cmd(argv[0])) == NULL) {printf ("Unknown command '%s' - try 'help'\n", argv[0]);rc = -1;    /* give up after bad command */continue;}//判断传递过来的参数是否超过这个命令超过的参数if (argc > cmdtp->maxargs) {printf ("Usage:\n%s\n", cmdtp->usage);rc = -1;continue;}#if defined(CONFIG_CMD_BOOTD)/* avoid "bootd" recursion */if (cmdtp->cmd == do_bootd) {
#ifdef DEBUG_PARSERprintf ("[%s]\n", finaltoken);
#endifif (flag & CMD_FLAG_BOOTD) {puts ("'bootd' recursion detected\n");rc = -1;continue;} else {flag |= CMD_FLAG_BOOTD;}}
#endif//直接使用函数指针的方式,来调用函数if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {rc = -1;}repeatable &= cmdtp->repeatable;/* Did the user stop this? */if (had_ctrlc ())return -1;    /* if stopped then not repeatable */}return rc ? rc : repeatable;
}

这个是找命令的函数,传递给这个函数的参数是命令的第一个参数

cmd_tbl_t *find_cmd (const char *cmd)
{cmd_tbl_t *cmdtp;cmd_tbl_t *cmdtp_temp = &__u_boot_cmd_start;//定义命令的起始地址const char *p;int len;int n_found = 0;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++;}}if (n_found == 1) {            /* exactly one match */return cmdtp_temp;}return NULL;    /* not found or ambiguous command */
}

3、命令结构体cmd_tbl_t

typedef struct cmd_tbl_s cmd_tbl_t;
(1)name:命令名称,字符串格式。
(2)maxargs:命令最多可以接收多少个参数
(3)repeatable:指示这个命令是否可重复执行。重复执行是uboot命令行的一种工作机制,就是直接按回车则执行上一条执行的命令。
(4)cmd:函数指针,命令对应的函数的函数指针,将来执行这个命令的函数时使用这个函数指针来调用。
(5)usage:命令的短帮助信息。对命令的简单描述。
(6)help:命令的长帮助信息。细节的帮助信息。
(7)complete:函数指针,指向这个命令的自动补全的函数。

总结:UBOOT的命令体系在工作的时候,一个命令对应一个cmd_tbl_t结构体的一个实例,然后UBOOT支持多少个命令。

UBOOT实现命令管理的思路:
(1)填充一个结构体实例构成一个命令
(2)给命令结构体实例附加特定段属性(用户自定义段),链接时将带有该段属性的内容链接在一起排列。
(3)UBOOT重定位时将该段整体加载到DDR中,加载到DDR中的UBOOT镜像中带有特定段属性的这一段其实就是命令结构体的集合,有点像一个命令结构体数组。
(4)段起始地址和段结束地址(链接地址、定义在uboot.lds)决定了这些命令集的开始和结束地址。

struct cmd_tbl_s
{char *name;    //命令的名字int  maxargs;  //命令允许的最多的参数int  repeatable;  //是否允许ENTER键重复int  (*cmd)(struct cmd_tbl_s *, int, char *[]); //函数指针,相当于方法char *usage;   //短帮助信息char *help;    //长帮助信息
};

4、简单的实例分析:

VERSION命令集的实现

(1)U_BOOT_CMD:其实可以认为它定义了一个命令结构体的实例。
也就是Linux内核经常说的很牛逼的注册

(2)使用一个宏定义来进行注册命令,这个宏定义其实就是定义一个结构体实例,并且初始化它。

(3)do_version函数其实就是C++常说的面向对象的思考方法
我们需要对一些重复的东西进行抽象,这样就是面向对象的思想。

#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}int
do_version (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{extern char version_string[];printf ("\n%s\n", version_string);return 0;
}U_BOOT_CMD(version,    1,        1,    do_version,"version - print monitor version\n",NULL
);

从零开始的UBOOT的学习8--命令体系相关推荐

  1. uboot源码——命令体系

    以下内容源于朱有鹏嵌入式课程的学习,如有侵权,请告知删除. 参考资料:http://www.cnblogs.com/biaohc/p/6394710.html 一.uboot命令体系基础 1.使用ub ...

  2. termite:从零开始的go语言学习生活

    时隔一年.终于下定决心认真的学习一下golang,为此昨天纠结了好久要不要买一个正版的goland,最后还是没舍得买-为什么要学习go呢?如今在当前这家公司已经工作两年,悠哉的生活使我日日堕落-体重长 ...

  3. 从零开始的MSP430单片机学习(一)

    从零开始的MSP430单片机学习(一) 图片有些缺失,原链接:从零开始的MSP430单片机学习(一) 写在前面 单片机学习本身是一个了解学习一个技术的过程,学习的过程中不应该拘泥于某一款,而是要了解学 ...

  4. uboot环境下mmc操作_android uboot中的mmc命令

    一:mmc的命令如下: 1:对mmc读操作 mmc read addr blk# cnt 2:对mmc写操作 mmc write addr blk# cnt 3:对mmc擦除操作 mmc erase ...

  5. Golang学习-基础命令

    链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载. . Golang学习-基础命令 一.go run 用于运行命令源码文件,只能接收一个命令源码文件以及若干个库源码文件作为 ...

  6. 学习Linux命令神器-看不懂直接给你解释

    大家都知道,Linux 系统有非常多的命令,而且每个命令又有非常多的用法,想要全部记住所有命令的所有用法,恐怕是一件不可能完成的任务. 一般情况下,我们学习一个命令时,要么直接百度去搜索它的用法,要么 ...

  7. Windbg学习 (0x0012) 命令-批处理命令程序

    Windbg学习 (0x0012) 命令-批处理命令 转载于:https://www.cnblogs.com/ywnwa417/p/5678344.html

  8. 【 Vivado 】在工程模式下通过jou文件来学习 Tcl 命令

    Xilinx 的数据手册UG895提供了一些系统级设计的方法,写得很详细,详细到得不到重要的消息(我菜). Tcl命令在工程模式下以及非工程模式下有一些差异,具体什么差异,这里暂时不说,后面我想应该会 ...

  9. Linux学习之命令【1】

    Linux学习之命令[1] 一·命令总览        1.基本简单命令          1.0 pwd 1.1 echo          1.2 date          1.3 cal 1. ...

最新文章

  1. python布尔测试对象_面试题十九期-测试开发面试题之python系列-这个中~
  2. OpenCV注视估计Gaze Estimation的实例(附完整代码)
  3. 【渝粤教育】电大中专就业指导 (3)作业 题库
  4. python矩阵输入_Python基础之矩阵输入
  5. 计算矩阵边缘元素之和(信息学奥赛一本通-T1121)
  6. 用Python快速实现视频的人脸融合
  7. wordmaker html转为word,PHP HTML生成word
  8. 《Effective C#》读书笔记(4)
  9. 【预测模型】基于狼群算法优化BP神经网络实现预测matlab源码
  10. 软考常考知识点整理-项目风险管理计划
  11. 启用IIS7配置ASP运行环境的详细方法
  12. 中序线索化二叉树的遍历
  13. 【Java】29.常用API之lang.Throwable(异常情况大总结)
  14. fastdds交叉编译
  15. 【全开源+免费更新】doodoo.js快速入门教程
  16. matlab图像剪裁命令imcrop()
  17. 玩转百度即用API(5)——空气质量指数查询
  18. 黑盒测试和白盒测试优点和缺点
  19. caffe安装使用、样本制作、网络修改、错误重新训练!
  20. java招投标管理系统的区别_建设项目招投标信息管理系统的设计与开发

热门文章

  1. ARKit 2推出共享体验
  2. 【DB笔试面试622】在Oracle中,说说COUNT(*)计算行数有哪些优化手段?
  3. sql文件反向生成物理概念模型
  4. keepalive (1)
  5. 上面两点下面一个三角形_章勤琼:三角形内角和180该如何说明 ——小学数学中的合情推理和演绎推理...
  6. python字符串两个冒号_Python 数组字符串 冒号 用法
  7. java程序的执行流程
  8. win10桌面版outlook邮箱配置流程
  9. 如何开发一个 WPS 加载项
  10. Verilog 时钟分频