在uboot源码目录下include/command.h中定义了一系列宏来构造一个UBOOT CMD。下面结构是命令表中一条命令的组成
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 * const []);
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 * const argv[], char last_char, int maxv, char *cmdv[]);
#endif
};
typedef struct cmd_tbl_s cmd_tbl_t; //重命名
extern cmd_tbl_t __u_boot_cmd_start; //这是两个很重要的符号 后面会解释
extern cmd_tbl_t __u_boot_cmd_end;
接下来是几个组合的宏定义来构造出一条命令:
#define Struct_Section __attribute__((unused, section(".u_boot_cmd"), aligned(4)))
#ifdef CONFIG_AUTO_COMPLETE
# define _CMD_COMPLETE(x) x,
#else
# define _CMD_COMPLETE(x)
#endif
#ifdef CONFIG_SYS_LONGHELP
# define _CMD_HELP(x) x,
#else
# define _CMD_HELP(x)
#endif
#define U_BOOT_CMD_MKENT_COMPLETE(name,maxargs,rep,cmd,usage,help,comp) \
{#name, maxargs, rep, cmd, usage, _CMD_HELP(help),_CMD_COMPLETE(comp)}
#define U_BOOT_CMD_MKENT(name,maxargs,rep,cmd,usage,help) \
U_BOOT_CMD_MKENT_COMPLETE(name,maxargs,rep,cmd,usage,help,NULL)
#define U_BOOT_CMD_COMPLETE(name,maxargs,rep,cmd,usage,help,comp) \
cmd_tbl_t __u_boot_cmd_##name Struct_Section = \
U_BOOT_CMD_MKENT_COMPLETE(name,maxargs,rep,cmd,usage,help,comp)
#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \
U_BOOT_CMD_COMPLETE(name,maxargs,rep,cmd,usage,help,NULL)
这样当我们在定义一条命令时就可以用最后一个用户接口宏
U_BOOT_CMD来定义自己的命令。以uboot现有的例子来分析:
#include <common.h>
#include <command.h>
int do_echo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
int i;
int putnl = 1;
......
return 0;
}
U_BOOT_CMD(
echo,
CONFIG_SYS_MAXARGS,
1,
do_echo,
"echo args to console",
"[args..]\n",
" - echo args to console; \\c suppresses newline"
);
上面的宏按照顺序依次展开 最终会得到
cmd_tbl_t __u_boot_cmd_echo __attribute__((unused, section(".u_boot_cmd"), aligned(4))) ={
echo,
CONFIG_SYS_MAXARGS,
1,
do_echo,
"echo args to console",
"[args..]\n",
" - echo args to console; \\c suppresses newline"
}
这样就构造出了一条命令。然而我们发现include/command目录下有很多cmd_xxx.c文件。从文件名来看是对命令进行了分类,实际是也就是如此。那这么多文件是如何组织起来的呢?
那就是前面提到的两个重要符号的功劳:
extern cmd_tbl_t __u_boot_cmd_start; //这是两个很重要的符号 后面会解释
extern cmd_tbl_t __u_boot_cmd_end;
这两个符号在连接文件中以下面的方式使用。其含义就是将这些左右这个类型的结构化的命令链接在一个连续的段中,以方便重定向时将uboot的命令表一起搬移到内存中指定区域。
. = ALIGN(4);
. = .;
__u_boot_cmd_start = .;
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;
最后来看一眼command目录下的Makefile ,经便了解这些命令的使能除能配置。
include $(TOPDIR)/config.mk
LIB = $(obj)libcommon.o
# core
COBJS-y += main.o
......
COBJS-$(CONFIG_SYS_HUSH_PARSER) += hush.o
......
# core command
COBJS-y += cmd_boot.o
COBJS-y += cmd_bootm.o
......
COBJS-y += cmd_version.o
# environment
COBJS-y += env_common.o
COBJS-$(CONFIG_ENV_IS_IN_DATAFLASH) += env_dataflash.o
......
COBJS-$(CONFIG_ENV_IS_IN_SPI_FLASH) += env_sf.o
COBJS-$(CONFIG_ENV_IS_NOWHERE) += env_nowhere.o
# command
COBJS-$(CONFIG_CMD_AMBAPP) += cmd_ambapp.o
COBJS-$(CONFIG_SOURCE) += cmd_source.o
......
ifdef CONFIG_4xx
COBJS-$(CONFIG_CMD_SETGETDCR) += cmd_dcr.o
endif
ifdef CONFIG_POST
COBJS-$(CONFIG_CMD_DIAG) += cmd_diag.o
endif
COBJS-$(CONFIG_CMD_DISPLAY) += cmd_display.o
......
COBJS-$(CONFIG_CMD_FLASH) += cmd_flash.o
ifdef CONFIG_FPGA
COBJS-$(CONFIG_CMD_FPGA) += cmd_fpga.o
endif
COBJS-$(CONFIG_CMD_I2C) += cmd_i2c.o
......
COBJS-$(CONFIG_CMD_OTP) += cmd_otp.o
ifdef CONFIG_PCI
COBJS-$(CONFIG_CMD_PCI) += cmd_pci.o
endif
COBJS-y += cmd_pcmcia.o
COBJS-$(CONFIG_CMD_PORTIO) += cmd_portio.o
COBJS-$(CONFIG_CMD_REGINFO) += cmd_reginfo.o
......
COBJS-$(CONFIG_CMD_UNIVERSE) += cmd_universe.o
ifdef CONFIG_CMD_USB
COBJS-y += cmd_usb.o
COBJS-y += usb.o
COBJS-$(CONFIG_USB_STORAGE) += usb_storage.o
endif
COBJS-$(CONFIG_VFD) += cmd_vfd.o
# others
COBJS-$(CONFIG_DDR_SPD) += ddr_spd.o
COBJS-$(CONFIG_HWCONFIG) += hwconfig.o
......
COBJS := $(sort $(COBJS-y))
XCOBJS := $(sort $(XCOBJS-y))
SRCS := $(COBJS:.o=.c) $(XCOBJS:.o=.c)
OBJS := $(addprefix $(obj),$(COBJS))
XOBJS := $(addprefix $(obj),$(XCOBJS))
CPPFLAGS += -I..
all: $(LIB) $(XOBJS)
$(LIB): $(obj).depend $(OBJS)
$(call cmd_link_o_target, $(OBJS))
$(obj)env_embedded.o: $(src)env_embedded.c $(obj)../tools/envcrc
$(CC) $(AFLAGS) -Wa,--no-warn \
-DENV_CRC=$(shell $(obj)../tools/envcrc) \
-c -o $@ $(src)env_embedded.c
$(obj)../tools/envcrc:
$(MAKE) -C ../tools
#########################################################################
# defines $(obj).depend target
include $(SRCTREE)/rules.mk
sinclude $(obj).depend
#########################################################################
可以使用 COBJS-y += cmd_usr.o方式或是条件编译方式COBJS-$(CONFIG_CMD_USR) += cmd_usr.o 来使能命令编译。
尾巴:如果要为uboot添加自定义命令,我们最好在command目录下新建一个cmd_usr.c文件,按照上述规则来构建自己的命令。同时要修改Makefile 来使能自定义命令编译就可以了。