u-boot-2019 u-boot 命令分析

代码分析

u-boot源码我们知道,在u-boot中的每一个命令都是通过U_BOOT_CMDU_BOOT_CMD_COMPLETE来定义的。下面来分析分析他们的具体实现逻辑。

U_BOOT_CMD 是一个宏定义,代码在 include/command.h中。

#define U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help)		\
	U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, NULL)

#ifdef CONFIG_CMDLINE

	#define U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, _comp) \
		ll_entry_declare(cmd_tbl_t, _name, cmd) =			\		//此处需要注意的时这里赋值的是cmd 而非上层参数 _cmd
			U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd,	\
							_usage, _help, _comp);
	
	#define U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd,		\
					_usage, _help, _comp)			\
			{ #_name, _maxargs,					\
			 _rep ? cmd_always_repeatable : cmd_never_repeatable,	\
			 _cmd, _usage, _CMD_HELP(_help) _CMD_COMPLETE(_comp) }

#else

	#define U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help,	\
				    _comp)				\
		_CMD_REMOVE(sub_ ## _name, _cmd)
		
	#define _CMD_REMOVE(_name, _cmd)					\
		int __remove_ ## _name(void)					\
		{								\
			if (0)							\
				_cmd(NULL, 0, 0, NULL);				\
			return 0;						\
		}

#endif /* CONFIG_CMDLINE */

ll_entry_declare 代码在include/linker_lists.h 中。

/**
 * ll_entry_declare() - Declare linker-generated array entry
 * @_type:	Data type of the entry
 * @_name:	Name of the entry
 * @_list:	name of the list. Should contain only characters allowed
 *		in a C variable name!
 *
 * This macro declares a variable that is placed into a linker-generated
 * array. This is a basic building block for more advanced use of linker-
 * generated arrays. The user is expected to build their own macro wrapper
 * around this one.
 *
 * A variable declared using this macro must be compile-time initialized.
 *
 * Special precaution must be made when using this macro:
 *
 * 1) The _type must not contain the "static" keyword, otherwise the
 *    entry is generated and can be iterated but is listed in the map
 *    file and cannot be retrieved by name.
 *
 * 2) In case a section is declared that contains some array elements AND
 *    a subsection of this section is declared and contains some elements,
 *    it is imperative that the elements are of the same type.
 *
 * 3) In case an outer section is declared that contains some array elements
 *    AND an inner subsection of this section is declared and contains some
 *    elements, then when traversing the outer section, even the elements of
 *    the inner sections are present in the array.
 *
 * Example:
 *
 * ::
 *
 *   ll_entry_declare(struct my_sub_cmd, my_sub_cmd, cmd_sub) = {
 *           .x = 3,
 *           .y = 4,
 *   };
 */
#define ll_entry_declare(_type, _name, _list)				\
	_type _u_boot_list_2_##_list##_2_##_name __aligned(4)		\
			__attribute__((unused,				\
			section(".u_boot_list_2_"#_list"_2_"#_name)))

通过上面的代码可知U_BOOT_CMD就是定义了一个类型为cmd_tbl_t的结构体数据并赋值。并且U_BOOT_CMDU_BOOT_CMD_COMPLETE的精减版,实现上U_BOOT_CMD 是调用U_BOOT_CMD_COMPLETE。区别在于U_BOOT_CMDcmd_tbl_t的结构体中的complete成员赋了空值。U_BOOT_CMD_COMPLETE则是对cmd_tbl_t的结构体的所有成员都有赋值。

cmd_tbl_tinclude/command.h中定义

typedef struct cmd_tbl_s	cmd_tbl_t;

struct cmd_tbl_s {
	char		*name;		/* Command Name			*/
	int		maxargs;	/* maximum number of arguments	*/
					/*
					 * Same as ->cmd() except the command
					 * tells us if it can be repeated.
					 * Replaces the old ->repeatable field
					 * which was not able to make
					 * repeatable property different for
					 * the main command and sub-commands.
					 */
	int		(*cmd_rep)(struct cmd_tbl_s *cmd, int flags, int argc,
				   char * const argv[], int *repeatable);
					/* 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
};

U_BOOT_CMD 中的各个参数,其实对应的就是cmd_tbl_s 结构体里面成员变量。

U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help) 
_name		:命令名称
_maxargs	:接受最大的参数个数
_rep		:重复
_cmd		:命令实现函数
_usage		:使用说明(短说明)
_help		:使用说明

具体命令分析

envprintenv 为例, 这两个命令为别通过U_BOOT_CMDU_BOOT_CMD_COMPLETE来定义。其代码在cmd/nvedit.c中,

U_BOOT_CMD(
	env, CONFIG_SYS_MAXARGS, 1, do_env,
	"environment handling commands", env_help_text
);

通过宏展开后可知U_BOOT_CMD就是定义了一个名为 _u_boot_list_cmd_2_env类型为cmd_tbl_t的结构体数据并赋值。

 cmd_tbl_t _u_boot_list_cmd_env __aligned(4)        \
            __attribute__((unused,section(".u_boot_list_2_cmd_2_env))) = \
			{ env, 16,                    \
             1 ? cmd_always_repeatable : cmd_never_repeatable,    \
             do_env, "environment handling commands", env_help_text  }
U_BOOT_CMD_COMPLETE(
	printenv, CONFIG_SYS_MAXARGS, 1,	do_env_print,
	"print environment variables",
	"[-a]\n    - print [all] values of all environment variables\n"
#if defined(CONFIG_CMD_NVEDIT_EFI)
	"printenv -e [name ...]\n"
	"    - print UEFI variable 'name' or all the variables\n"
#endif
	"printenv name ...\n"
	"    - print value of environment variable 'name'",
	var_complete
);

通过宏展开后可知U_BOOT_CMD_COMPLETE就是定义了一个名为 _u_boot_list_2_cmd_2_printenv类型为cmd_tbl_t的结构体数据并赋值。

 cmd_tbl_t _u_boot_list_2_cmd_2_printenv __aligned(4)        \
            __attribute__((unused, section(".u_boot_list_2_cmd_2_printenv))) = \
			{ printenv, 16,                    \
             1 ? cmd_always_repeatable : cmd_never_repeatable,    \
             do_env_print, 
			"print environment variables", 
			"[-a]\n    - print [all] values of all environment variables\n"
			#if defined(CONFIG_CMD_NVEDIT_EFI)
				"printenv -e [name ...]\n"
				"    - print UEFI variable 'name' or all the variables\n"
			#endif
				"printenv name ...\n"
				"    - print value of environment variable 'name'",
				var_complete}

通过nmreadelf 查看相应的符号表

$ nm u-boot | grep _u_boot_list_2_cmd_2_env
9fca6818 D _u_boot_list_2_cmd_2_env

$ readelf -s u-boot | grep _u_boot_list_2_cmd_2_env
  4671: 9fca6818    28 OBJECT  GLOBAL DEFAULT    8 _u_boot_list_2_cmd_2_env

命令调用流程

run_command common/cli.c
	 cli_simple_run_command	common/cli_simple.c
		cli_simple_parse_line 				分析参数
		cmd_process		common/command.c	
			find_cmd 						根据name查找命令,在section .u_boot_list_2_cmd_1和.u_boot_list_2_cmd_3 之间查找
			cmd_call						执行命令

在u-boot中添加命令

  1. common 建立cmd_xx.c 文件,参考其他文件如 cmd_bootm.c 来添加头文件
  2. U_BOOT_CMDU_BOOT_CMD_COMPLETE 来定义命令
  3. 实现命令的操作do_xx 函数
  4. common/cmd_xx.c 加入common/Makefile中 COBJS += cmd_xx.o
  5. 重新配置编译u-boot
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值