文章目录

  • 1. uboot命令体系基础
    • 1.1使用uboot命令
    • 1.2每个命令对应一个函数
    • 1.3命令参数以argc&argv传给函数
  • 2. uboot命令解析和执行过程分析
    • 2.1从main_loop说起
  • 3. run_command函数详解
    • 3.1关键点分析
  • 4. uboot如何处理命令集1
    • 4.1可能的管理方式
    • 4.2命令结构体cmd_tbl_t
    • 4.3 uboot实现命令管理的思路
  • 5. uboot如何处理命令集2
    • 5.1 uboot命令定义具体实现分析
    • 5.2 find_cmd函数详解
    • 5.4 U_BOOT_CMD宏详解
  • 6. uboot中增加自定义命令
    • 6.1在已有的c文件中直接添加命令
    • 6.2自建一个c文件并添加命令
    • 6.3体会:uboot命令体系的优点

1. uboot命令体系基础

1.1使用uboot命令

(1)uboot启动后进入命令行环境下,在此输入命令按回车结束,uboot会收取这个命令然后解析,然后执行。
2.8.1.2、uboot命令体系实现代码在哪里
(1)uboot命令体系的实现代码在uboot/common/cmd_xxx.c中。有若干个.c文件和命令体系有关。(还有command.c main.c也是和命令有关的)

1.2每个命令对应一个函数

(1)每一个uboot的命令背后都对应一个函数。这就是uboot实现命令体系的一种思路和方法。这个东西和我们在裸机第十六部分shell中实现shell命令的方法是一样的。
(2)我们要找到每一个命令背后所对应的那个函数,而且要分析这个函数和这个命令是怎样对应起来的。

1.3命令参数以argc&argv传给函数

(1)有些uboot的命令还支持传递参数。也就是说命令背后对应的函数接收的参数列表中有argc和argv,然后命令体系会把我们执行命令时的命令+参数(md 30000000 10)以argc(3)和argv(argv[0]=md, argv[1]=30000000 argv[2]=10)的方式传递给执行命令的函数。

举例分析,以help命令为例:
help命令背后对应的函数名叫:do_help。在uboot/common/command.c的236行。int do_help (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])

2. uboot命令解析和执行过程分析

2.1从main_loop说起

(1)uboot启动的第二阶段,在初始化了所有该初始化的东西后,进入了一个死循环,死循环的循环体就是main_loop。
(2)main_loop函数执行一遍,就是一个获取命令、解析命令、执行命令的过程。
(3)run_command函数就是用来执行命令的函数。

3. run_command函数详解

3.1关键点分析

int run_command (const char *cmd, int flag)
{cmd_tbl_t *cmdtp;char cmdbuf[CFG_CBSIZE];  /* working copy of cmd      */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;#ifdef DEBUG_PARSERprintf ("[RUN_COMMAND] cmd[%p]=\"", cmd);puts (cmd ? cmd : "NULL");   /* use puts - string may be loooong */puts ("\"\n");
#endifclear_ctrlc();        /* forget any previous Control C */if (!cmd || !*cmd) {return -1;   /* empty command */}if (strlen(cmd) >= CFG_CBSIZE) {puts ("## Command too long!\n");return -1;}strcpy (cmdbuf, cmd);/* Process separators and check for invalid* repeatable commands*/#ifdef DEBUG_PARSERprintf ("[PROCESS_SEPARATORS] %s\n", cmd);
#endifwhile (*str) {/** Find separator, or string end* Allow simple escape of ';' by writing "\;"*/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/* find macros in this token and replace them */process_macros (token, finaltoken);/* Extract arguments */if ((argc = parse_line (finaltoken, argv)) == 0) {rc = -1;  /* no command at all */continue;}/* Look up command in command table */if ((cmdtp = find_cmd(argv[0])) == NULL) {printf ("Unknown command '%s' - try 'help'\n", argv[0]);rc = -1; /* give up after bad command */continue;}/* found - check max args */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/* OK - call function to do the command */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 */}

(1)控制台命令获取
(2)命令解析。parse_line函数把"md 30000000 10"解析成argv[0]=md, argv[1]=30000000 argv[2]=10;
(3)命令集中查找命令。find_cmd(argv[0])函数去uboot的命令集合当中搜索有没有argv[0]这个命令,
(4)执行命令。最后用函数指针的方式调用执行了对应函数。

思考:关键点就在于find_cmd函数如何查找到这个命令是不是uboot的合法支持的命令?这取决于uboot的命令体系机制(uboot是如何完成命令的这一套设计的,命令如何去注册、存储、管理、索引。)。

4. uboot如何处理命令集1

4.1可能的管理方式

(1)数组。结构体数组,数组中每一个结构体成员就是一个命令的所有信息。
(2)链表。链表的每个节点data段就是一个命令结构体,所有的命令都放在一条链表上。这样就解决了数组方式的不灵活。坏处是需要额外的内存开销,然后各种算法(遍历、插入、删除等)需要一定复杂度的代码执行。
(3)有第三种吗?uboot没有使用数组或者链表,而是使用了一种新的方式来实现这个功能。

4.2命令结构体cmd_tbl_t

struct cmd_tbl_s {char       *name;      /* Command Name         */int       maxargs;    /* maximum number of arguments  */int       repeatable; /* autorepeat allowed?      *//* Implementation function    */int       (*cmd)(struct cmd_tbl_s *, int, int, char *[]);char     *usage;     /* Usage message    (short) */
#ifdef  CFG_LONGHELPchar        *help;      /* Help  message    (long)  */
#endif
#ifdef CONFIG_AUTO_COMPLETE/* do auto completion on the arguments */int     (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]);
#endif
};
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的命令体系把这些结构体实例管理起来,当用户输入了一个命令时,uboot会去这些结构体实例中查找(查找方法和存储管理的方法有关)。如果找到则执行命令,如果未找到则提示命令未知。

4.3 uboot实现命令管理的思路

(1)填充1个结构体实例构成一个命令。
(2)给命令结构体实例附加特定段属性(用户自定义段),链接时将带有该段属性的内容链接在一起排列(挨着的,不会夹杂其他东西,也不会丢掉一个带有这种段属性的,但是顺序是乱序的)。
(3)uboot重定位时将该段整体加载到DDR中。加载到DDR中的uboot镜像中带有特定段属性的这一段其实就是命令结构体的集合,有点像一个命令结构体数组。
(4)段起始地址和结束地址(链接地址、定义在u-boot.lds中)决定了这些命令集的开始和结束地址。

5. uboot如何处理命令集2

5.1 uboot命令定义具体实现分析

(1)U_BOOT_CMD宏基本分析
这个宏定义在uboot/common/command.h中。

U_BOOT_CMD(version,  1,      1,  do_version,"version - print monitor version\n",NULL
);
这个宏替换后变成:
cmd_tbl_t __u_boot_cmd_version __attribute__ ((unused,section (".u_boot_cmd"))) = {#name, maxargs, rep, cmd, usage, help}

总结:这个U_BOOT_CMD宏的理解,关键在于结构体变量的名字和段属性。名字使用##作为连字符,附加了用户自定义段属性,以保证链接时将这些数据结构链接在一起排布。

5.2 find_cmd函数详解

(1)find_cmd函数的任务是从当前uboot的命令集中查找是否有某个命令。如果找到则返回这个命令结构体的指针,如果未找到返回NULL。
(2)函数的实现思路很简单,如果不考虑命令带点的情况(md.b md.w这种)就更简单了。查找命令的思路其实就是for循环遍历数组的思路,不同的是数组的起始地址和结束地址是用地址值来给定的,数组中的元素个数是结构体变量类型。

5.4 U_BOOT_CMD宏详解

(1)这个宏其实就是定义了一个命令对应的结构体变量,这个变量名和宏的第一个参数有关,因此只要宏调用时传参的第一个参数不同则定义的结构体变量不会重名。

6. uboot中增加自定义命令

6.1在已有的c文件中直接添加命令

(1)在uboot/common/command.c中添加一个命令,叫:mycmd
(2)在已有的.c文件中添加命令比较简单,直接使用U_BOOT_CMD宏即可添加命令,给命令提供一个do_xxx的对应的函数这个命令就齐活了。
(3)添加完成后要重新编译工程(make distclean; make x210_sd_config; make),然后烧录新的uboot去运行即可体验新命令。
(4)还可以在函数中使用argc和argv来验证传参。

6.2自建一个c文件并添加命令

(1)在uboot/common目录下新建一个命令文件,叫cmd_aston.c(对应的命令名就叫aston,对应的函数就叫do_aston函数),然后在c文件中添加命令对应的U_BOOT_CMD宏和函数。注意头文件包含不要漏掉。
(2)在uboot/common/Makefile中添加上aston.o,目的是让Make在编译时能否把cmd_aston.c编译链接进去。
(3)重新编译烧录。重新编译步骤是:make distclean; make x210_sd_config; make

6.3体会:uboot命令体系的优点

(1)uboot的命令体系本身稍微复杂,但是他写好之后就不用动了。我们后面在移植uboot时也不会去动uboot的命令体系。我们最多就是向uboot中去添加命令,就像本节课所做的这样。
(2)向uboot中添加命令非常简单。

uboot移植——命令体系相关推荐

  1. uboot源码——命令体系

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

  2. 嵌入式uboot移植之三星官方uboot开始移植

    注:以下内容来自朱老师物联网课件 1. 移植前的准备工作 1.1 获取三星移植过的uboot源代码 我们使用的是老师提供的android_uboot_smdkv210.tar.bz2,文件存储在课件2 ...

  3. u-boot移植随笔:自定义u-boot命令点灯

    u-boot移植随笔:自定义u-boot命令点灯 前几天一不小心在CSDN论坛上发帖散分,同时许诺完成点灯就结账,经过努力,终于可以在u-boot的shell中输入自定义的命令来点灯了.下面简单讲一下 ...

  4. u-boot移植随笔:让u-boot shell支持tab、命令历史

    u-boot移植随笔:让u-boot shell支持tab.命令历史 前两天一直在想一个问题,u-boot的shell怎么不支持命令自动补齐,命令历史呢?由于受linux的shell影响,只要其它的& ...

  5. rouboot命令linux,UBOOT移植详细 很全面

    移植u-boot-1.3.4到S3C2440 一.预备知识: 1.首先,U-Boot1.3.4还没有支持s3c2440,移植仍是用2410的文件稍作修改而成的. 2.       2440和2410的 ...

  6. Exynos4412 Uboot 移植(三)—— Uboot添加自定义命令

    Uboot添加自定义命令:uboot中的命令使用U_BOOT_CMD这个宏声明来注册进系统,链接脚本会把所有的cmd_tbl_t结构体放在相邻的地方. UBoot版本:u-boot-2013.01 一 ...

  7. uboot和系统移植2(uboot常用命令)

    1.5.uboot的常用命令1 1.5.1.类似linux终端的行缓冲命令行 (1)行缓冲的意思就是:当我们向终端命令行输入命令的时候,这些命令没有立即被系统识别,而是被缓冲到一个缓存区(也就是系统认 ...

  8. 【u-boot】uboot代码简要分析 (u-boot 移植)

    uboot代码简要分析 (u-boot 移植) 2012-12-19 22:46:04 [转] 先来看看源码目录结构,再按照代码的执行顺序简单地分析源码 1.U-boot源码整体框架 源码解压以后,我 ...

  9. 嵌入式uboot移植之从uboot官方移植

    注:以下内容来自朱老师物联网大讲堂课件 1. 选择合适的官方原版uboot 1.1 官方原版uboot的版本 (1)版本号.刚开始是1.3.4,后来变成2009.08 (2)新版和旧版的差别.uboo ...

  10. uboot移植——启动第二阶段

    文章目录 1.start_armboot函数简介 2.uboot第二阶段简介 2.1 uboot第二阶段应该做什么 2.2 uboot第二阶段完结于何处? 3.变量定义分析 3.1 init_fnc_ ...

最新文章

  1. java Apache Commons jar包简介
  2. 狎昵关系和依恋情结辨诠
  3. android 获取短信验证码倒计时
  4. MJExtension 模型嵌套模型数组
  5. Cesium 中两种添加 model 方法的区别
  6. 数字图像处理实验(3):PROJECT 02-03, Zooming and Shrinking Images by Pixel Replication
  7. Spring MVC 常用Jar包官方下载地址(官方Maven仓库)
  8. 生产场景不同角色linux服务器分区案例分享
  9. Sentinel(六)之集群流控
  10. HTTP 错误500.19 -Internal Server Error
  11. 【Scala】Scala中常见集合的使用---代码详解
  12. 中国数字X射线设备行业市场供需与战略研究报告
  13. μc/os-II原理简介(笔记)
  14. 创建最基本的GD32F4xx的工程
  15. android 过滤蓝光软件下载,安卓蓝光过滤器
  16. 常吃大蒜对人有什么好处与坏处?
  17. 红米k50 刷入类原生教程
  18. python 数据分析 |3. Pandas 学习
  19. 基于OpenCV做图像数据增强(平移、镜像、缩放、旋转、仿射)
  20. Python 可视化--Matplotlib 安装和pyplot

热门文章

  1. 安卓webview嵌套网页不更新更换域名
  2. Ext.grid.EditorGridPanel使用方法
  3. Ext3.4.0中EditorGridPanel可以复制文本
  4. ctfmon.exe开机无法自己主动启动
  5. 数据库索引失效与判断是否命中索引
  6. 遥感专业学c语言吗,2019遥感科学与技术专业怎么样、学什么、前景好吗
  7. win32API中文参考手册
  8. 【深入理解JS核心技术】1.在 JavaScript 中创建对象的可能方式有哪些?
  9. QT tablewidget设置表头
  10. FFmpeg入门详解之67:Qt FFmpeg开发播放器