u-boot中各种命令的组织架构

           在u-boot中,我们可以输入命令来进行操作,如print命令打印内核信息,bootm命令来启动内核等等,那这些命令是如何被u-boot组织起来的呢?为了说明这个问题,我们以bootm命令为例来找到问题的答案。

           u-boot源码中搜索”bootm“,可以在common\cmd_bootm.c中找到bootm命令对应的do_bootm()函数,那这个函数是如何被调用起来的?注意在这个源文件中存在一个U_BOOT_CMD宏,如下代码所示,虽然现在看不懂这个宏的含义,但是从这个宏的参数可以看出将bootm命令和do_bootm()函数对应起来。

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"
);
那么现在我们就需要知道这个宏的定义,继续在源码中搜索”U_BOOT_CMD“,当然会搜索出一大堆眼花缭乱的东西,宏的定义必然涉及“define”字段,在结果中搜索“define”可以找到定义了,在include\command.h中定义,同时这个宏中的Struct_Section也是一个宏。

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

那么现在根据宏的定义将上面定义bootm的宏进行展开,看这个宏到底进行了什么工作,展开结果是

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",
 "[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"
}
从展开的结果来看,定义了一个cmd_tbl_t的结构体,并设置这个结构体的段属性为“.u_boot_cmd”,先来看看cmd_tb_t这个结构体的内容
struct cmd_tbl_s {
        char     *name;           //命令的名称,“bootm”
	int      maxargs;        //命令运行携带的最大参数个数,CFG_MAXARGS=16个
	int      repeatable;     //是否允许通过敲入回车键来重复上一次输入的命令 1为允许,0为不允许			
        int      (*cmd)(struct cmd_tbl_s *, int, int, char *[]);  //对于命令的实现函数 do_bootm,此处就将bootm命令和命令的实现关联起立了</span>
        char     *usage;         //短的帮助信息,"bootm   - boot application image from memory\n" 
        char     *help;          //长的帮助信息
};
从这个结构来看,显然是构造了一个命令的名称,命令的实现函数,及其帮助信息。那么段属性为“.u_boot_cmd”在哪定义,对于这种属性的定义,一般都在链接脚本中定义的,链接脚本内容如下

SECTIONS
{
	. = 0x00000000;

	. = ALIGN(4);
	.text      :
	{
	  cpu/arm920t/start.o	(.text)
          board/100ask24x0/boot_init.o (.text)
	  *(.text)
	}

	. = ALIGN(4);
	.rodata : { *(.rodata) }

	. = ALIGN(4);
	.data : { *(.data) }

	. = ALIGN(4);
	.got : { *(.got) }

	. = .;
	__u_boot_cmd_start = .;   //此处定了(.u_boot_cmd)段的起始地址__u_boot_cmd_start
	.u_boot_cmd : { *(.u_boot_cmd) } //此处存放了所有文件的(.u_boot_cmd)
	__u_boot_cmd_end = .;      //定义了(.u_boot_cmd)段的结束地址__u_boot_cmd_end<pre name="code" class="plain">
. = ALIGN(4);__bss_start = .;.bss : { *(.bss) }_end = .;

 从链接脚本来看,它将所有命令的cmd_tbl_t结构体都集中到(.u_boot_cmd)段进行存放。那么现在关键在于命令的调用了。我们可以假象一下,在u-boot的菜单中,当我们输入一个bootm命令的时候,我们一般的处理思路是将这个”bootm“字符串跟所有的命令结构体中name字段进行匹配,如果匹配成功那么就取出这个命令的cmd_tbl_t结构体,那么自然就可以调用这个命令的实现函数了。因此,既然涉及到所有命令结构的遍历,那么自然是从__u_boot_cmd_start遍历到__u_boot_cmd_end,那么我们可以继续在源码中搜索“__u_boot_cmd_start”,可以在common\command.c中找到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 */   //先找到(.u_boot_cmd段的起始地址)
	const char *p;
	int len;
	int n_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);  //如果命令中有".",则只取"."之前的命令的长度
        //下面就是在(.u_boot_cmd段中进行遍历与匹配)
	for (cmdtp = &__u_boot_cmd_start;
	     cmdtp != &__u_boot_cmd_end;
	     cmdtp++) {
		if (strncmp (cmd, cmdtp->name, len) == 0) {     //如果输入的命令字符串和cmdtp中name字段完全匹配则返回cmdtp结构体
			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中命令的组织架构了,那么我们也可以仿照bootm命令来自己实现一个u-boot的命令,比如输入一个hello命令,然后打印出hello world,步骤如下:

1、类似于bootm,在common下创建一个名为cmd_hello.c的源文件,内容如下

#include <common.h>
#include <watchdog.h>
#include <command.h>
#include <image.h>
#include <malloc.h>
#include <zlib.h>
#include <bzlib.h>
#include <environment.h>
#include <asm/byteorder.h>
int do_bhello (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
	printf("hello world\n");
	return 1;
}
U_BOOT_CMD(
     hello, CFG_MAXARGS, 1,do_hello,
    "hello -new command\n",
    ""
);
2、在common目录下的Makefile文件中COBJ后加上 cmd_hello.o,这样就将这个命令编译进u-boot了。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值