uboot启动 及命令分析(3)

 

u-boot命令

先贴一个重要结构,位于uboot/include/command.h,这个结构代表每个uboot命令

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)简短用法信息*/

#ifdefCFG_LONGHELP

   char     *help;   /* Help  message   (long) 长的帮助信息*/

#endif

#ifdef CONFIG_AUTO_COMPLETE

                   /* do auto completion on the arguments */

   int  (*complete)(intargc, char *argv[], charlast_char, intmaxv, char*cmdv[]);

#endif

};

 

typedef struct cmd_tbl_s    cmd_tbl_t;

============================================================

 

uboot的第一阶段:硬件相关初始化

0.reset 执行arm920t/start.s  过程如下

1.设置cpu svc管理模式

2.关看门狗中断,mmu等

3.设置时钟,sdram,外部总线

4.代码重定位,搬运代码,从flash到sdram

5.设置栈,bss段清零, bss用于未初始化的全局变量和静态变量

6.ldr pc, _start_armboot

   即进入uboot启动的第二阶段,调用c函数start_armboot()

 

从start_armboot 开始

经过一系列外设初始化

比如

falsh_init

nand_init

...

最后循环调用mian_loop()

main_loop主要流程

{

   1. 生成环境变量mtdparts, 调用mtdparts_init

   2. 在启动过程中

      若无空格键按下则boot_zImage,即run_command(getenv("bootcmd"),0)

      有空格键按下则 run_command("menu",0)

   3. shell过程,读取用户的输入并执行相应的命令

      {

         从控制台获得命令,保存在全局变量comsole_buffer中

         解析命令行字符串,分割命令与参数,最后执行 run_command(...);

      }                    

}

 

也就是说在mian_loop中,是处理环境变量和控制台人机交互,

mian_loop调用readline ()读取命令行到console_buffer,

再把console_buffer复制到lastcommand中去,

还要设置flag,最后调用run_command (lastcommand, flag)函数,

run_command (lastcommand, flag)函数中,首先定义cmd_tbl_t *cmdtp,再解析命令行。

再调用find_cmd(argv[0])函数,其中argv[0]应该是命令本身,参数已经被剥离,

这个函数返回的是一个cmd_tbl_t结构体,

就是说每个命令都有一个cmd_tbl_t结构体相对应,关于run_command函数后面再分析

 

mian_loop中有

#define CONFIG_BOOTDELAY 3  //设置启动延时时间

//如果延时大于等于零,并且没有在延时过程中接收到按键,则引导内核

if (bootdelay >= 0 && s && !abortboot (bootdelay)) { //

# ifdef CONFIG_AUTOBOOT_KEYED

      intprev = disable_ctrlc(1);/* disable Control C checking */

# endif   //状态设置

 

# ifndef CFG_HUSH_PARSER

        {

             printf("Booting Linux ...\n");       //启动 linux   

         run_command (s, 0);  //运行引导内核的命令,s=getenv("bootcmd")          

        }

 

加载linux内核时将使用变量“bootcmd”和 “bootargs”,

变量“bootcmd”和 “bootargs”的值可以在在加载linux内核前,

uboot的命令控制台中进行修改

 

bootcmd=nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0

第一条命令  从flash上读出内核   kernel是一个分区标志

第二条命令  启动命令指示了启动地址

 

而bootargs是其它参数信息

而 run_command (getenv ("bootcmd"), flag)

 

bootcmd中的bootm,即boot application image from memory

参数形式:"bootm addr"

当addr省略的时候bootm加载默认的配置宏

#define CONFIG_SYS_LOAD_ADDR  0x30008000  /* default load address */

 

uboot中,"bootm"命令的执行函数为do_bootm(),这个是由U_BOOT_CMD绑定的函数指针,

在do_bootm()中执行了do_bootm_linux(),

do_bootm_linux()函数中获取了"bootargs"环境变量的值,最终将此值传递给linux内核,

并调用theKernel函数,完成对linux内核的加载启动

 

linux内核的启动,主要就是执行环境变量bootcmd和bootargs所定义的命令.

============================================================

 

uboot的核心功能是用run_command()来执行的

run_command是怎么实现的?

 

int run_command (const char *cmd, intflag)

{

   cmd_tbl_t *cmdtp;

   charcmdbuf[CFG_CBSIZE];    /* working copy of cmd      */

   char *token;          /* start of token in cmdbuf*/

   char *sep;               /* end of token (separator) in cmdbuf */

   charfinaltoken[CFG_CBSIZE];

   char *str = cmdbuf;

   char *argv[CFG_MAXARGS + 1];   /* NULL terminated*/

   intargc, inquotes;

   intrepeatable = 1;

   intrc = 0;

   ...

   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 ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {

      rc = -1;

   }

   ...

}

 

run_command(...)    //流程解析

{

   1. 对\;解析,分割出一个个命令

   2. 然后对每一个完整的命令执行

     {

      parse_line

      {

         line是整条的命令行bootcmd的值

         例如line = nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0

         先去掉开头的空格,

         然后对命令进行解析,找到空格之后将空格替换为\0,这样解析出命令和参数

      }

 

      find_cmd(argv[0])

      {

         从 __u_boot_cmd_start 到 __u_boot_cmd_end 的array进行遍历,

         从找到的cmd_tbl_t中,字符串寻找cmdtp->name与argv[0]相同的命令

      }

      找到匹配的命令后,调用cmd_tbl_t->cmd执行

     }

}

 

run_command函数中的parse_line函数主要代码如下

int parse_line (char *line, char *argv[])

{

   ...

   while ((*line == ' ') || (*line == '\t'))

   {

      ++line;

   }

   ...

}

============================================================

run_command函数中的find_cmd()

cmd_tbl_t *find_cmd (const char *cmd)

{

   cmd_tbl_t *cmdtp;

   cmd_tbl_t *cmdtp_temp = &__u_boot_cmd_start;   /*Init value */

   const char *p;

   intlen;

   intn_found = 0;

 

   /*

    * Some commands allow length modifiers (like "cp.b");

    * compare command name only until first dot.

    */

   len = ((p = strchr(cmd, '.')) == NULL) ? strlen (cmd) : (p - cmd);

 

   for (cmdtp  = &__u_boot_cmd_start;

        cmdtp != &__u_boot_cmd_start;

        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 */

}

 

其中__u_boot_cmd_start和__u_boot_cmd_start是怎么来的?

查找发现只有在command.h中有声明

extern cmd_tbl_t  __u_boot_cmd_start;

extern cmd_tbl_t  __u_boot_cmd_end;

 

而__u_boot_cmd_start是在链接脚本uboot.lds里面定义的

 

   . = .;

   __u_boot_cmd_start = .;

   .u_boot_cmd : { *(.u_boot_cmd) }  //所有u_boot_cmd宏命令都保存在这个段

   __u_boot_cmd_end = .;

 

在command.h中有

#define Struct_Section  __attribute__ ((unused,section (".u_boot_cmd")))

 

#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}

 

 

搜索到在cmd_bootm.c中有 U_BOOT_CMD的实参

U_BOOT_CMD(

   bootm,CFG_MAXARGS,1,do_bootm,

   "bootm   - boot application image from memory\n",

   "[addr [arg ...]]\n    - boot application image stored in memory\n"

   "\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"

#endif

);

 

将这个宏展开并替换

#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \

cmd_tbl_t __u_boot_cmd_bootm __attribute__ ((unused,section (".u_boot_cmd"))) =

{"bootm", CFG_MAXARGS, 1, do_bootm, "bootm   - boot application image from memory\n", "阴影部分"}

参数说明---------------

名称:bootm

将段属性设置为: .u_boot_cmd

最大参数个数:CFG_MAXARGS

是否可重复:1 , 可重复,即下一次按回车时可重复执行

cmd对应do_bootm,这是在cmd_tblt_t中定义的函数指针,命令就是在这个函数中实现

usage:使用概要 "bootm   - boot application image from memory\n"

help:详细帮助:那一大段阴影部分

 

 

 

总结:

每个U_BOOT_CMD宏组成的命令实质上是一个个cmd_tbl_t结构,

它们在链接时全部被定位保存到__u_boot_cmd_start起始地址开始的段中,也就是.u_boot_cmd段中.

 

当上电后,若启动的是默认的linux内核,执行run_command (getenv ("bootcmd"), flag),

由bootcmd字串中得知bootm,bootm的执行函数是do_bootm(),

在do_bootm()中执行了do_bootm_linux(...),

do_bootm_linux()函数中获取了"bootargs"环境变量的值,

最终将此值传递给linux内核,并调用theKernel函数,完成对linux内核的加载启动

 

当上电后,若用户按空格并输入命令,先同样执行run_command函数,调用find_cmd遍历每一个cmd_tbl_t结构,

比较cmdtp->name,当名称匹配时,就通过cmd_tbl_t结构的(*cmd)(...)函数指针来执行命令功能,

即执行cmd_tbl_t->cmd

 

============================================================

 

                                      添加uboot命令

在uboot/include/configs/xxx.h文件中,添加#define CONFIG_CMD_HELLO启用我们的自定义命令

也可以在uboot/include/config_cmd_default.h文件中添加,不过这个define在这里不是必须的

 

在common目录,命令都是在cmd_xxx.c文件中实现的,这个是命名规范,必须是cmd_xxx.c形式,

所以我们在common目录新建一个文件cmd_myCmd.c

 

#include <common.h>

 #include <command.h>

#ifdef CONFIG_CMD_HELLO

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

{

   int i;

   printf("hello the word!,%d\n",argc);

 

   for(is = 0;i < argc;i++)  

   {    

    printf("argv[%d]:%s\n",i,argv[i]);  

   }    

return 0;

}

 

U_BOOT_CMD(   hello, CFG_MAXARGS, 1, do_hello,

     "hello   - just for test\n",   

    "hello,long help .................\n"

);   

#endif

 

 

 

U_BOOT_CMD这里3个hello写法最好一致,为什么?

第一个hello是uboot命令

第二个hello是在命令行输入help时输出的概要信息

第三个hello是当输入help myTest的时候显示的详细信息

 

最后,修改common下的Makefile文件,将cmd_myCmd.o加入编译

输入hello a b c d e f

输出

hello the word!,7            
argv[0]:hello
argv[1]:a
argv[2]:b
argv[3]:c
argv[4]:d
argv[5]:e
argv[6]:f

 

========================================================

 

 

转载于:https://www.cnblogs.com/CZM-/p/5069920.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/543807.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mozilla开源了VR框架A-Frame

Mozilla创建并开源了A-Frame&#xff0c;这是一个用于在桌面浏览器、智能手机和Oculus Rift上创建VR场景的框架。\\A-Frame是一个在浏览器中创建VR体验的开源框架。该框架由Mozilla的MozVR团队创建和开发。A-Frame使用了一个在游戏开发中经常使用的“实体-组件&#xff08;Enti…

css网格_CSS网格容器

css网格CSS | 网格容器 (CSS | Grid Containers) There are numerous ways to display our list items or elements. For instance, we can display them in the navigation bar, in a menu bar and whatnot. Well, it would be right to say that there are many more such me…

c ++向量库_在C ++中对2D向量进行排序

c 向量库As per as a 2D vector is concerned its a vector of a 1D vector. But what we do in sorting a 1D vector like, 就2D向量而言&#xff0c;它是1D向量的向量 。 但是我们在对一维向量进行排序时所做的工作 sort(vector.begin(),vector.end());We cant do the same …

监听文本框数据修改,特别是微信等客户端直接选择粘贴修改

2019独角兽企业重金招聘Python工程师标准>>> // 手机号码信息加载验证 $(input).bind(input propertychange, function() { initPage.checkName(); }); 转载于:https://my.oschina.net/u/1579617/blog/550488

SSIA的完整形式是什么?

SSIA&#xff1a;主题说明一切 (SSIA: Subject Says It All) SSIA is an abbreviation of "Subject Says It All". SSIA是“主题说明一切”的缩写。 It is an expression, which is commonly used in the Gmail platform. It is written in the subject of the mail…

服务器控件转换成HTML

服务器控件转换成HTML<asp:Label ID"Label1" runat"server" Text"I am label"><asp:Literal ID"Literal1" runat"server" Text"I am a literal"><asp:Panel ID"Panel1" runat"serv…

Eratosthenes筛

什么是Eratosthenes筛&#xff1f; (What is Sieve of Eratosthenes?) Sieve of Eratosthenes is an ancient algorithm of finding prime numbers for any given range. Its actually about maintaining a Boolean table to check for corresponding prime no. Eratosthenes的…

微信iOS多设备多字体适配方案总结

一、背景 2014下半年&#xff0c;微信iOS版先后适配iPad, iPhone6/6plus。随着这些大屏设备的登场&#xff0c;部分用户觉得微信的字体太小&#xff0c;但也有很多用户不喜欢太大的字体。为了满足不同用户的需求&#xff0c;我们做了全局字体设置功能&#xff0c;在【设置-通用…

python矩阵中插入矩阵_Python | 矩阵的痕迹

python矩阵中插入矩阵The sum of diagonal elements of a matrix is commonly known as the trace of the matrix. It is mainly used in eigenvalues and other matrix applications. In this article, we are going to find the trace of a matrix using inbuilt function nu…

TOP命令监视系统任务及掩码umask的作用

top 命令使用方法及參数。 top 选择參数 參数&#xff1a; -b 以批量模式执行。但不能接受命令行输入&#xff1b;-c 显示命令行&#xff0c;而不不过命令名。-d N 显示两次刷新时间的间隔&#xff0c;比方 -d 5&#xff0c;表示两次刷新间隔为5秒&#xff1b;-i 禁止显示空暇…

python点线图_Python | 点线图

python点线图A mixture of dot and line plot is called a Dot-Line plot. Each dot is connected through a line and it is the next version of the line plot. It maintains the discrete property of the points and also represents the correlation between consecutive…

Android Studio导入工程的正确姿势

为什么80%的码农都做不了架构师&#xff1f;>>> 如果你有很好的网络环境 好的网络环境&#xff0c;这里不是指&#xff1a;我家网速带宽100M&#xff0c;电信的光纤接入。 而是&#xff1a;能翻墙。因为如果本机的gradle和将要导入的工程版本不匹配&#xff0c;Stu…

BBIAF的完整形式是什么?

BBIAF&#xff1a;回来几场 (BBIAF: Be Back In A Few) BBIAF is an abbreviation of "Be Back In A Few". BBIAF是“几回去”的缩写 。 It is an expression, which is commonly used in messaging or chatting on social media networking sites like Facebook, …

为什么年轻人挣得很多还是穷?北上广深挑战指数报告~

又是年底&#xff0c;又到了做选择的时候。从“激情燃烧的岁月”到“何处安放的青春”&#xff0c;逃离北上广深的口号从未停止过&#xff0c;回到北上广深的呼喊更是一浪接着一浪。应届生们奔波忙碌&#xff0c;想有一份承载自己梦想的工作&#xff0c;想在异乡有一处安身之所…

apple组织名称是什么_什么是Apple Macintosh?

apple组织名称是什么苹果Macintosh (Apple Macintosh) Steve Jobs and Steve Wozniak has founded the line of computers in the year 1984, on the date 24th January, named it Apple Macintosh. Macintosh is shortly abbreviated as Mac. In this, various versions of co…

什么是Apple Desktop Bus? 亚行代表什么?

亚行&#xff1a;Apple桌面总线 (ADB: Apple Desktop Bus) ADB is an abbreviation of "Apple Desktop Bus". ADB是“ Apple Desktop Bus”的缩写 。 It is a low-speed proprietary bit-serial peripheral bus connecting devices to computers. In 1986, it was l…

CentOS 创建SVN 服务器,并且自动同步到WEB 目录

CentOS 创建SVN 服务器&#xff0c;并且自动同步到WEB 目录 标签&#xff1a; centossvnsubversion服务器2013-12-06 10:09 5492人阅读 评论(0) 收藏 举报分类&#xff1a;linux&#xff08;5&#xff09; 一、安装Subversion #yum install subversion二&#xff0c;基本的SVN服…

TTYL的完整形式是什么?

TTYL&#xff1a;稍后再与您交谈 (TTYL: Talk To You Later) TTYL is an abbreviation of Talk To You Later. It is an internet slang that is most generally used in text messaging, instant messaging, and chatting on Facebook, Twitter, WhatsApp, etc. The acronym i…

zhilizhili-ui 2016始动 开始做个样例站吧 (一)

对 我又挖坑了 不过其实也不算挖坑 因为ui构建中就会有填坑的文章 之前一直在写《编写大型web页面 结合现有前端形势思考未来前端》这是一篇巨难写的文章 估计要到年中才能写好了 写作的过程中 发生了国内前端大撕逼 2015的尾声大战 是否可以宣告前端是否开始新的时代 2016年 国…

python 网格_Python | 网格到情节

python 网格Most of the time, we need good accuracy in data visualization and a normal plot can be ambiguous. So, it is better to use a grid that allows us to locate the approximate value near the points in the plot. It helps in reducing the ambiguity and t…