本文目标:
理解u-boot命令的实现原理。
上一篇文章分析了u-boot是如何启动kernel的,其中就涉及到bootm命令,考虑到文章主题需要,当时并没有对bootm命令做过多的解释。然而,u-boot命令行又是u-boot及其重要的一部分。这篇文章,我们就通过实战来理解u-boot命令的实现原理。
我们要做的很简单,就是添加一条uboot command,希望在开发板上,uboot命令行中输入itxiebo时,能够从串口打印出一句log。
#include <common.h>
#include <command.h>
static int do_itxiebo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
printf("do_itxiebo command is ready now!");
return 0;
}
U_BOOT_CMD(
itxiebo, 2, 0, do_itxiebo,
"itxiebo - this is a itxiebo command, do nothing",
"- this is a itxiebo command, do nothing"
);
2.在./common/Makefile中添加:
obj-y += cmd_itxiebo.o
3.在linux环境下,重新编译u-boot,得到u-boot.bin,并升级到自己的开发板中(如果你没有开发板,没有关系,你只需要明白我们要在开发板中验证自己添加的命令itxiebo)
4.升级完后,在开发板启动内核之前,按space键进入u-boot命令行模式。
5.在串口终端中输入help命令,回车,可以发现itxiebo命令行已经添加成功。
6.在串口终端中输入itxiebo命令,回车执行该命令,发现我们添加的打印log,可以正确打印出来:
实战见效果了,我们继续分析。不难发现,只要能搞清上面代码中的“U_BOOT_CMD”,就能弄明白uboot命令实现原理。
U_BOOT_CMD格式如下:
U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help)
其中,各个参数解释如下:
参数名 | 说明 |
---|---|
_name | 命令名,非字符串,但在U_BOOT_CMD中用“#”符号转化为字符串 |
_maxargs | 命令的最大参数个数 |
_rep | 是否自动重复(按Enter键是否会重复执行) |
_cmd | 该命令对应的响应函数 |
_usage | 简短的使用说明(字符串) |
_help | 较详细的使用说明(字符串) |
说明:
在内存中保存命令的help字段会占用一定的内存,通过配置U-Boot可以选择是否保存help字段。若在include/configs/s5p4418_urbetter.h 中定义了CONFIG_SYS_LONGHELP宏,则在U-Boot中使用help命令查看某个命令的帮助信息时将显示_usage和_help字段的内容,否则就只显示usage字段的内容,而不显示_help字段的内容。
另外,在include/command.h中,对U_BOOT_CMD的define 如下:
#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_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(_name, _maxargs, _rep, _cmd, _usage, _help) \
U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, NULL)
最后,同样在include/command.h中定义了一个结构体cmd_tbl_t:
如此,我们便可以将U_BOOT_COM解析,如下
U_BOOT_CMD( itxiebo, 2, 0, do_itxiebo, "itxiebo - this is a itxiebo command, do nothing", "- this is a itxiebo command, do nothing" );
解析为:
cmd_tbl_t _u_boot_list_2_do_itxiebo_2_itxiebo __aligned(4) __attribute__((unused,section(".u_boot_list_2_"do_itxiebo"_2_"itxiebo)))
其中,“u_boot_list”,《u-boot分析 三》分析u-boot.lds时解释过。也就是说咱们新增的itxiebo command会被储存在u_boot_list段内。
.u_boot_list : {
KEEP(*(SORT(.u_boot_list*)));
/*.data段结束后,紧接着存放u-boot自有的一些function,例如u-boot command等*/
}
在U-Boot中输入(串口终端)“itxiebo”命令执行时,U-Boot接收输入的字符串“itxiebo”,传递给run_command()函数。run_command()函数调用common/command.c中实现的find_cmd()函数在u_boot_list段内查找命令,并返回itxiebo命令的cmd_tbl_t结构。然后run_command()函数使用返回的cmd_tbl_t结构中的函数指针调用itxiebo命令的响应函数do_itxiebo,从而完成了命令的执行。
参考:
http://www.cnblogs.com/sdphome/archive/2011/08/19/2146327.html
完事儿。