当前位置: 首页 > 工具软件 > cmd-enter > 使用案例 >

嵌入式实践教程--使用U_BOOT_CMD()自定义uboot命令

许俊风
2023-12-01

总目录

NXP i.MX8M secure boot流程
Uboot链接脚本分析述
Uboot启动分析–start.S启动分析(1)
Uboot启动分析–start.S启动分析(2)
Uboot启动分析–start.S启动分析(3)
Uboot启动分析–__main分析(1)
Uboot启动分析–__main分析(2)
Uboot启动分析–启动kernel
Uboot分析–SPL跳转过程分析
Uboot中lpddr4的初始化(i.MX8M)
使用U_BOOT_CMD()自定义uboot命令

首先引入command相关的头文件:

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

如果要添加自己的uboot命令必须要使用U_BOOT_CMD()这个宏。以hdmi检测功能为例:

U_BOOT_CMD(hdmidet, 1, 1, do_hdmidet,
	"detect HDMI monitor",
	""
);

U_BOOT_CMD()宏定义

typedef struct cmd_tbl_s	cmd_tbl_t;

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

#define U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, _comp) \
	ll_entry_declare(cmd_tbl_t, _name, 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) 
		}

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

_name:uboot中命令的名字

_maxargs:最多几个args

_rep:是否自动重复(按Enter键是否会重复执行)

_cmd:我们自己写的函数

_usage:函数的用途说明,比如“检测hdmi功能”

_help:较详细的使用说明(字符串)

/**
 * 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)

以fastboot为例

U_BOOT_CMD( 
	fastboot, 
	CONFIG_SYS_MAXARGS, 
	1, 
	do_fastboot, 
	"run as a fastboot usb or udp device", 
	fastboot_help_text 
);
U_BOOT_CMD(fastboot, CONFIG_SYS_MAXARGS, 1, do_fastboot,"run as a fastboot usb or udp device", fastboot_help_text);
====展开得到====> 

U_BOOT_CMD_COMPLETE(fastboot, CONFIG_SYS_MAXARGS, 1, do_fastboot,"run as a fastboot usb or udp device", fastboot_help_text, NULL)
====展开得到====> 

ll_entry_declare(cmd_tbl_t, fastboot, cmd) = 
		{ 
			#fastboot, 
			64,	 				// #define CONFIG_SYS_MAXARGS      64  /* max command args */
			cmd_always_repeatable,	 
			do_fastboot, 
			"run as a fastboot usb or udp device", 
			fastboot_help_text,
			NULL
		}
====展开得到====> 

_type _u_boot_list_2_cmd_2_fastboot __aligned(4) __attribute__((unused,	section(".u_boot_list_2_cmd_2_fastboot")))= 
{ 
	#fastboot, 
	64,	 				// #define CONFIG_SYS_MAXARGS      64  /* max command args */
	cmd_always_repeatable,	 
	do_fastboot, 
	"run as a fastboot usb or udp device", 
	fastboot_help_text,
	NULL
}

可以看出,通过U_BOOT_CMD宏控就生成了一个_u_boot_list_2_cmd_2_fastboot 类型的结构体。

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

\arch\arm\cpu\u-boot.lds
	. = .;

	. = ALIGN(4);
	.u_boot_list : {
		KEEP(*(SORT(.u_boot_list*)));
	}

	. = ALIGN(4)

这表明,凡是以u_boot_list开头的都会被放在 .u_boot_list段中。至此,我们就将 fastboot 命令相关信息在编译阶段就存储在了 .u_boot_list 段中。

在编译中, .u_boot_list 字段就会和 .text . data 一样被打包进uboot bin中。

# limit ourselves to the sections we want in the .bin.
ifdef CONFIG_ARM64
OBJCOPYFLAGS += -j .text -j .image -j .secure_text -j .secure_data -j .rodata -j .data \
		-j .u_boot_list -j .rela.dyn -j .got -j .got.plt \
		-j .binman_sym_table -j .text_rest
else
OBJCOPYFLAGS += -j .text -j .secure_text -j .image -j .secure_data -j .rodata -j .hash \
		-j .data -j .got -j .got.plt -j .u_boot_list -j .rel.dyn \
		-j .binman_sym_table -j .text_rest
endif

命令调用过程

un_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						执行命令
 类似资料: