目录
一、命令体系基础知识
- 每一个uboot的命令对应一个函数do_命令名字,例如do_bootm
- 命令是可以传参的,参数以argc&argv传给函数
例如:int do_bootm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); - uboot的命令体系在工作时,一个命令对应一个cmd_tbl结构体的一个实例,然后uboot支持多少个命令,就需要多少个结构体实例。uboot的命令体系把这些结构体实例管理起来,当用户输入了一个命令时,uboot会去这些结构体实例中查找(查找方法和存储管理的方法有关)。如果找到则执行命令,如果未找到则提示命令未知。
1.1、命令结构体
- 命令结构体cmd_tbl
struct cmd_tbl { 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 *cmd, int flags, int argc, char *const argv[], int *repeatable); /* Implementation function */ int (*cmd)(struct cmd_tbl *cmd, int flags, int argc, char *const argv[]); 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 };
- name:命令名称,字符串格式
- maxargs:命令最多可以接收多少个参数
- cmd_rep:指示这个命令是否可重复执行
- cmd:函数指针,命令对应的函数的函数指针
- usage:命令的短帮助信息
- help:命令的长帮助信息
- complete:函数指针,指向这个命令的自动补全的函数
1.2、命令的管理方式
管理方式:数组,链表等
uboot管理方式是:通过自定义段,实现
- 给命令结构体实例附加特定段属性(用户自定义段),链接时将带有该段属性的内容链接在一起排列(挨着的,不会夹杂其他东西,也不会丢掉一个带有这种段属性的,但是顺序是乱序的)。
- uboot重定位时将该段整体加载到DDR中。加载到DDR中的uboot镜像中带有特定段属性的这一段其实就是命令结构体的集合,有点像一个命令结构体数组。
- 段起始地址和结束地址(链接地址、定义在u-boot.lds中)决定了这些命令集的开始和结束地址。
. = ALIGN(8); . = .; . = ALIGN(8); .u_boot_list : { KEEP(*(SORT(.u_boot_list*))); }
- U_BOOT_CMD宏:位置common/command.h
U_BOOT_CMD( bootm, CONFIG_SYS_MAXARGS, 1, do_bootm, "boot application image from memory", bootm_help_text ); //U_BOOT_CMD 是 U_BOOT_CMD_COMPLETE 的特例 ,多了一个NULL参数 #define U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help) \ U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, NULL) //用到了ll_entry_declare和U_BOOT_CMD_MKENT_COMPLETE // U_BOOT_CMD替换后 //struct cmd_tbl _u_boot_list_2_cmd_2_name __aligned(4) __attribute__((unused)) __section(".u_boot_list_2_"cmd"_2_"name) = { #name, maxargs, rep, cmd, usage, help NULL } #define U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, _comp) \ ll_entry_declare(struct cmd_tbl, _name, cmd) = \ U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd, \ _usage, _help, _comp); //ll_entry_declare,位置在include/linker_lists.h 中,定义如下 //定义了一个 cmd_tbl 变量, //“##_name”就是用_name 的值来替换,“ # ” 表示将 _name 传递过来的值字符串化 #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) #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) }
- 替换后:
struct cmd_tbl _u_boot_list_2_cmd_2_name __aligned(4) __attribute__((unused)) __section(".u_boot_list_2_"cmd"_2_"name) = { #name, maxargs, rep, cmd, usage, help NULL }
二、uboot命令体系执行
- cli_loop函数,就是一个获取命令、解析命令、执行命令的过程参考博文
位置:common/cli.c - cmd_process函数,就是查找执行处理命令的函数
位置:common/command.cenum command_ret_t cmd_process(int flag, int argc, char *const argv[], int *repeatable, ulong *ticks) { enum command_ret_t rc = CMD_RET_SUCCESS; struct cmd_tbl *cmdtp; #if defined(CONFIG_SYS_XTRACE) char *xtrace; xtrace = env_get("xtrace"); if (xtrace) { puts("+"); for (int i = 0; i < argc; i++) { puts(" "); puts(argv[i]); } puts("\n"); } #endif /* Look up command in command table */ cmdtp = find_cmd(argv[0]); if (cmdtp == NULL) { printf("Unknown command '%s' - try 'help'\n", argv[0]); return 1; } /* found - check max args */ if (argc > cmdtp->maxargs) rc = CMD_RET_USAGE; #if defined(CONFIG_CMD_BOOTD) /* avoid "bootd" recursion */ else if (cmdtp->cmd == do_bootd) { if (flag & CMD_FLAG_BOOTD) { puts("'bootd' recursion detected\n"); rc = CMD_RET_FAILURE; } else { flag |= CMD_FLAG_BOOTD; } } #endif /* If OK so far, then do the command */ if (!rc) { int newrep; if (ticks) *ticks = get_timer(0); rc = cmd_call(cmdtp, flag, argc, argv, &newrep); if (ticks) *ticks = get_timer(*ticks); *repeatable &= newrep; } if (rc == CMD_RET_USAGE) rc = cmd_usage(cmdtp); return rc; }
- find_cmd查找命令,位置common/command.c
struct cmd_tbl *find_cmd(const char *cmd) { struct cmd_tbl *start = ll_entry_start(struct cmd_tbl, cmd); //命令集的头 const int len = ll_entry_count(struct cmd_tbl, cmd); //命令集长度 return find_cmd_tbl(cmd, start, len); //查找命令 }
- cmd_call:执行命令
static int cmd_call(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[], int *repeatable) { int result; result = cmdtp->cmd_rep(cmdtp, flag, argc, argv, repeatable); if (result) debug("Command failed, result=%d\n", result); return result; }
三、添加命令
- 在u-boot-2022.01/cmd下,新建文件xw.c
可以cp里面的echo.c文件 - 在common/cmd/Makefile中添加上xw.o,目的是让Make在编译时编译链接进去
- xw.c
#include <common.h> 8 #include <command.h> 9 10 static int do_xw(struct cmd_tbl *cmdtp, int flag, int argc, 11 char *const argv[]) 12 { 13 if (argc > 1) { 14 printf("argc>1\n"); 15 }else{ 16 printf("xw do_xw zhixing\n"); 17 } 18 19 return 0; 20 } 21 22 U_BOOT_CMD( 23 xw, 1, 1, do_xw, 24 "Custom Commands xw", 25 "Custom Commands xw!!!" 26 );