深入剖析u-boot命令结构

来源:互联网 发布:三级分销算法 编辑:程序博客网 时间:2024/05/06 21:23

转自:http://blog.csdn.net/fzu_dianzi/article/details/7165507

一、环境

目标板:mini2440

u-boot版本:u-boot-2009.08

交叉编译器:arm-linux-gcc-4.3.2

操作系统:Linux(Ubuntu-11.10)

 

二、目的

1、剖析u-boot命令结构

2、通过代码修改,添加u-boot命令

三、

1、

u-boot支持命令行交互,几乎全部的命令都在common/里面定义。以cmd_开头的文件都是命令类文件。如下图所示:


2、执行命令入口

u-boot stage1执行完后,就跳入stage2 的入口start_armboot函数中。该函数主要进行一系列的初始化,然后进入等待用户命令的循环,main_loop()。

[cpp] view plaincopy
  1. /* main_loop() can return to retry autoboot, if so just run it again. */  
  2. for (;;)   
  3. {  
  4.     main_loop ();  
  5. }  

在main_loop()里,u-boot获取用户控制台输入,然后调用run_command函数执行命令。

这里不详细的分析run_command[common/Main.c]的处理流程。

执行命令之前肯定有一个校验命令合法性的过程,u-boot是通过find_cmd来查找已注册的合法命令的。

该函数定义在common/command.c

[cpp] view plaincopy
  1. cmd_tbl_t *find_cmd (const char *cmd)  
  2. {  
  3.     int len = &__u_boot_cmd_end - &__u_boot_cmd_start;      //计算命令个数  
  4.     return find_cmd_tbl(cmd, &__u_boot_cmd_start, len);         //查找命令表  
  5. }  

cmd_tbl_t

其定义是在include/command.h

[cpp] view plaincopy
  1. struct cmd_tbl_s {  
  2.     char        *name;      /* Command Name         */  
  3.     int     maxargs;    /* maximum number of arguments  */  
  4.     int     repeatable; /* autorepeat allowed?      */  
  5.                     /* Implementation function  */  
  6.     int     (*cmd)(struct cmd_tbl_s *, intintchar *[]);  
  7.     char        *usage;     /* Usage message    (short) */  
  8. #ifdef  CONFIG_SYS_LONGHELP  
  9.     char        *help;      /* Help  message    (long)  */  
  10. #endif  
  11. #ifdef CONFIG_AUTO_COMPLETE  
  12.     /* do auto completion on the arguments *///自动补全参数  
  13.     int     (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]);  
  14. #endif  
  15. };  
  16.   
  17. typedef struct cmd_tbl_s    cmd_tbl_t;  

cmd_tbl_t定义了u-boot命令的结构信息,包含命令名、参数最多个数及命令的回调函数等

__u_boot_cmd_ start和__u_boot_cmd_end

其定义是在cpu/larm920t/u-boot.lds(不同类型的cpu,位置不同)

[cpp] view plaincopy
  1. //u_boot_cmd的起始地址__u_boot_cmd_start,止于__u_boot_cmd_end  
  2.     //这段区域内存放u-boot所有命令  
  3.     __u_boot_cmd_start = .;  
  4.     .u_boot_cmd : { *(.u_boot_cmd) }  
  5.     __u_boot_cmd_end = .;  

我们可以查看u-boot根目录下system.map,便一目了然。


链接文件里u_boot_cmd段合并在一起生成一个大的.u_boot_cmd段,并且用__u_boot_cmd_start与__u_boot_cmd_end两个符号标识这块内存的首尾边界。这样的机制使得用户添加代码不用去修改其core代码。

3、查看u-boot的命令文件内容

如果我们要自定义出一个命令,那么必须了解其他命令是如何构建的。在每个cmd_XXX.c文件里都可以看到类似下面定义的语句。

[cpp] view plaincopy
  1. U_BOOT_CMD(  
  2.     go, CONFIG_SYS_MAXARGS, 1,  do_go,  
  3.     "start application at address 'addr'",  
  4.     "addr [arg ...]\n    - start application at address 'addr'\n"  
  5.     "      passing 'arg' as arguments"  
  6. );  

U_BOOT_CMD

U-Boot中每个命令都通过U_BOOT_CMD宏来定义,其定义是在common/command.h

[cpp] view plaincopy
  1. /* 
  2. 凡是带有__attribute__ ((unused,section (".u_boot_cmd"))属性声明的变量都将被存放在".u_boot_cmd"段中,并且即使该变量没有在代码中显式的使用编译器也不产生警告信息。 
  3. */  
  4. #define Struct_Section  __attribute__ ((unused,section (".u_boot_cmd")))  
  5.   
  6. #ifdef  CFG_LONGHELP  
  7.   
  8. #define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \  
  9. cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}  
  10. //“##”与“#”都是预编译操作符,“##”有字符串连接的功能,“#”表示后面紧接着的是一个字符串  
  11. #else   /* no long help info */  
  12.   
  13. #define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \  
  14. cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage}  

参数意义如下:

           name:命令名字;

           maxargs:最大的参数个数;

           rep:命令是否可重复,可重复是指运行一个命令后,下次敲回车即可再次运行;

           cmd:对应的函数指针,一般都是do_name;

           usage:简短的使用说明;

           help:较详细的使用说明;

go命令的定义经过宏展开后如下:

[plain] view plaincopy
  1. cmd_tbl_t __u_boot_cmd_go __attribute__ ((unused,section (".u_boot_cmd"))) =   
  2. {  
  3.     go, CONFIG_SYS_MAXARGS, 1,  do_go,  
  4.     "start application at address 'addr'",  
  5.     "addr [arg ...]\n    - start application at address 'addr'\n"  
  6.     "      passing 'arg' as arguments"  
  7. }  

 实质上就是用U_BOOT_CMD宏定义的信息构造了一个cmd_tbl_t类型的结构体。编译器将该结构体放在“u_boot_cmd”段,执行命令时就可以在“u_boot_cmd”段查找到对应的cmd_tbl_t类型结构体。

4、添加自定义命令

1)       在common/创建一个cmd_care.c

[cpp] view plaincopy
  1. #include <common.h>  
  2. #include <command.h>  
  3.   
  4. int do_care (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])  
  5. {  
  6.     printf("Hello world!\n");  
  7. }  
  8.   
  9. U_BOOT_CMD(  
  10.     care,   2,  1,  do_care,  
  11.     "u-boot command test by care",  
  12.     ""  
  13. );  

1)       在common/Makefile添加COBJS-y += cmd_care.o

2)       对u-boot进行编译

3)       结果

编译成功后,查看System.map

证明该命令已经成功添加。

将u-boot.bin烧写到flash,输入我们自定义的命令care