深入剖析u-boot命令结构

该博客主要记录和总结我在工作中遇到的问题和积累的经验。如有错误之处,谢请指正。

共享资源,欢迎转载:http://blog.csdn.net/fzu_dianzi

一、环境

目标板: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()。

/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;) 
{
	main_loop ();
}

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

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

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

该函数定义在common/command.c

cmd_tbl_t *find_cmd (const char *cmd)
{
	int len = &__u_boot_cmd_end - &__u_boot_cmd_start;		//计算命令个数
	return find_cmd_tbl(cmd, &__u_boot_cmd_start, len);			//查找命令表
}

cmd_tbl_t

其定义是在include/command.h

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	CONFIG_SYS_LONGHELP
	char		*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;

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

__u_boot_cmd_ start和__u_boot_cmd_end

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

//u_boot_cmd的起始地址__u_boot_cmd_start,止于__u_boot_cmd_end
	//这段区域内存放u-boot所有命令
	__u_boot_cmd_start = .;
	.u_boot_cmd : { *(.u_boot_cmd) }
	__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文件里都可以看到类似下面定义的语句。

U_BOOT_CMD(
	go, CONFIG_SYS_MAXARGS, 1,	do_go,
	"start application at address 'addr'",
	"addr [arg ...]\n    - start application at address 'addr'\n"
	"      passing 'arg' as arguments"
);

U_BOOT_CMD

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

/*
凡是带有__attribute__ ((unused,section (".u_boot_cmd"))属性声明的变量都将被存放在".u_boot_cmd"段中,并且即使该变量没有在代码中显式的使用编译器也不产生警告信息。
*/
#define Struct_Section  __attribute__ ((unused,section (".u_boot_cmd")))

#ifdef  CFG_LONGHELP

#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}
//“##”与“#”都是预编译操作符,“##”有字符串连接的功能,“#”表示后面紧接着的是一个字符串
#else	/* no long help info */

#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \
cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage}

参数意义如下:

           name:命令名字;

           maxargs:最大的参数个数;

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

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

           usage:简短的使用说明;

           help:较详细的使用说明;

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

cmd_tbl_t __u_boot_cmd_go __attribute__ ((unused,section (".u_boot_cmd"))) = 
{
	go, CONFIG_SYS_MAXARGS, 1,	do_go,
	"start application at address 'addr'",
	"addr [arg ...]\n    - start application at address 'addr'\n"
	"      passing 'arg' as arguments"
}

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

4、添加自定义命令

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

#include <common.h>
#include <command.h>

int do_care (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
	printf("Hello world!\n");
}

U_BOOT_CMD(
	care,	2,	1,	do_care,
	"u-boot command test by care",
	""
);

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

2)       对u-boot进行编译

3)       结果

编译成功后,查看System.map

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

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






猜你喜欢

转载自blog.csdn.net/fzu_dianzi/article/details/7165507
今日推荐