`

uboot笔记:uboot命令分析+实现

阅读更多

                          uboot命令分析+实现

 

先贴一个重要结构,位于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.代码重定位,搬运代码,flashsdram

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内核时将使用变量bootcmdbootargs”,

变量“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内核的启动,主要就是执行环境变量bootcmdbootargs所定义的命令.

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

 

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->nameargv[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_MYCMD 启用我们的自定义命令

也可以在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_MYCMD

int do_myCmd(cmd_tbl_t *cmdtp, intflag, intargc, char *argv[])

{

   printf("Hello,this is myCmd test\n");

   return 0;

}

 

U_BOOT_CMD(

  myTest, 1, 1,  do_myCmd,

  "myTest - 123456myCmd.  \n",

  "myTest - longHelp_abcdefgmyCmd ...\n"

);

#endif

 

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

第一个myTestuboot命令

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

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

 

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

 

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

 

 

 

 

 

 

0
1
分享到:
评论

相关推荐

    Uboot命令使用笔记.docx

    "Uboot命令使用笔记" Uboot是一种开源的Bootloader,广泛应用于嵌入式系统中。本文档记录了Uboot命令的使用笔记,涵盖了Uboot的启动log、命令使用、环境变量设置、内存操作、网络操作、EMMC/SD卡操作、FAT格式文件...

    UBOOT源码阅读笔记

    ### UBOOT源码阅读笔记知识点解析 #### 一、UBOOT简介 UBOOT(Universal Boot Loader)是一款开源的Bootloader程序,广泛应用于嵌入式系统中。它支持多种处理器架构和操作系统,具备高度的可移植性和灵活性。通过...

    uboot 移植笔记

    Uboot 移植笔记 Uboot 移植笔记是一篇关于将 Uboot 移植到 S3C2440 平台上的记录文章。该文章详细介绍了 Uboot 移植的三个阶段,并提供了详细的移植过程和解决常见问题的方法。 Uboot 移植的三个阶段是: 1. 移植...

    uboot代码详细分析.pdf

    u-boot 中的命令实现 .......................................................................................................................... 25 U-BOOT环境变量实现 ......................................

    uboot分析和笔记

    ### U-Boot分析与移植详解 U-Boot作为开源BootLoader的一种,由ppcboot和armboot合并而成,是目前主流的嵌入式系统引导加载程序之一,与RedBoot并驾齐驱。它广泛应用于各种嵌入式平台,包括但不限于ARM、PowerPC、...

    uboot代码详细分析(88页)

    7. U-Boot命令实现:这部分内容应该讲述了如何在U-Boot环境中实现和使用命令,包括命令的注册、解析和执行过程。 8. 环境变量实现:U-Boot通过环境变量提供了灵活的配置方法,文档中可能探讨了环境变量在U-Boot中的...

    朱老师uBoot笔记,学习使用的

    朱老师uBoot笔记,学习使用的

    Uboot源码目录分析笔记.docx

    《UBoot源码目录分析详解》 UBoot,全称微内核启动加载器(Micro Universal Boot Loader),是嵌入式系统中广泛使用的引导加载程序。深入理解UBoot的源码目录结构对于开发者来说至关重要,这有助于我们进行系统移植...

    uboot学习笔记—s5pv210

    Uboot 学习笔记—s5pv210 Uboot 是一个开源的引导加载程序,广泛应用于嵌入式系统中。下面是 Uboot 的学习笔记,涵盖了 Uboot 的基本概念、配置、启动过程、环境变量、Makefile 等方面的知识点。 一、Uboot 的基本...

    jz2440:ARM体系结构学习+ARM uboot+Linux内核+Linux驱动

    jz2440学习笔记本仓库内容jz2440学习笔记思维导图ARM体系架构学习Linux内核驱动学习Something I hope you know before go into the coding~First, please watch or star this repo, I'll be more happy if you ...

    exynos4412-uboot移植笔记

    基于exynos4412的uboot移植笔记

    uboot阅读笔记

    【uboot阅读笔记】 uboot,全称是U-Boot,是一个开源的、跨平台的嵌入式系统启动加载器,广泛应用于各种嵌入式硬件平台。本文将深入探讨uboot的核心概念,主要包括remap和relocate两个关键部分,帮助读者理解uboot...

    uboot启动流程笔记和思维导图.rar

    正点原子的学习笔记是对UBoot启动流程的详细记录和解释,结合代码注释,可以帮助读者深入理解每一步的具体实现。通过阅读笔记和实际操作,可以提升对UBoot及Linux系统启动原理的理解,为后续的开发工作打下坚实基础...

    p2020 uboot 移植笔记

    《P2020 U-Boot 移植详解》 在嵌入式系统开发中,U-Boot 是一个至关重要的组件,它作为系统的引导...对于初学者而言,详细记录移植过程,例如在"P2020 U-Boot移植笔记"中,有助于积累经验,便于后续查阅和问题排查。

    exynos4412-uboot移植笔记 .doc

    Exynos4412 U-Boot 移植笔记 Exynos4412 是 Samsung 推出的一个高性能的移动处理器,基于 ARM Cortex-A9 架构。U-Boot 是一个开源的引导加载器,能够将操作系统加载到内存中,并提供了一些基本的硬件控制功能。本...

    uboot移植过程笔记

    【uboot移植过程笔记】 uboot移植是嵌入式系统开发中的重要环节,它涉及到将uboot引导加载程序适应特定硬件平台的过程。本笔记主要针对从Nor flash和Nand flash启动uboot的移植过程进行详细阐述。 1. **开启Nand ...

    IMX8MP uboot移植笔记

    ### IMX8MP U-Boot 移植笔记 #### 一、源码及工具文件下载与准备工作 在开始U-Boot移植之前,首先需要下载必要的工具和源代码。以下是具体的步骤: 1. **下载imx-mkimage工具**: - 地址:...

Global site tag (gtag.js) - Google Analytics