uboot分析之uboot命令实现
// md.w 0 命令打印0地址的内容
OpenJTAG> md.w 0
00000000: 00ff ea00 f014 e59f f014 e59f f014 e59f ................
00000010: f014 e59f f014 e59f f014 e59f f014 e59f ................
00000020: 0160 33f8 01c0 33f8 0220 33f8 0280 33f8 `..3...3 ..3...3
00000030: 02e0 33f8 0400 33f8 0420 33f8 beef dead ...3...3 ..3....
00000040: 0000 33f8 0000 33f8 06ac 33fb 7904 33fb ...3...3...3.y.3
00000050: c0de 0bad c0de 0bad 0000 0000 c0de 0bad ................
00000060: c0de 0bad 0000 e10f 001f e3c0 00d3 e380 ................
00000070: f000 e129 0453 e3a0 1000 e3a0 1000 e580 ..).S...........
u-boot的命令:
1. 串口输入命令
2. 处理命令, 输出结果
处理的时候肯定是根据命令名字找到对应的处理函数, 然后调用处理函数
看看run_command实现:
int run_command (const char *cmd, int flag)
{
char cmdbuf[CFG_CBSIZE];
...
strcpy (cmdbuf, cmd);
while (*str) {
process_macros (token, finaltoken);
if ((argc = parse_line (finaltoken, argv)) == 0) {
rc = -1;
continue;
}
if ((cmdtp = find_cmd(argv[0])) == NULL) {
printf ("Unknown command '%s' - try 'help'\n", argv[0]);
rc = -1;
continue;
}
if (argc > cmdtp->maxargs) {
printf ("Usage:\n%s\n", cmdtp->usage);
rc = -1;
continue;
}
#if (CONFIG_COMMANDS & CFG_CMD_BOOTD)
if (cmdtp->cmd == do_bootd) {
#ifdef DEBUG_PARSER
printf ("[%s]\n", finaltoken);
#endif
if (flag & CMD_FLAG_BOOTD) {
puts ("'bootd' recursion detected\n");
rc = -1;
continue;
} else {
flag |= CMD_FLAG_BOOTD;
}
}
#endif
if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {
rc = -1;
}
repeatable &= cmdtp->repeatable;
if (had_ctrlc ())
return 0;
}
}
命令结构:
struct cmd_tbl_s {
char *name;
int maxargs;
int repeatable;
int (*cmd)(struct cmd_tbl_s *, int, int, char *[]);
char *usage;
#ifdef CFG_LONGHELP
char *help;
#endif
#ifdef CONFIG_AUTO_COMPLETE
int (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]);
#endif
};
根据命令名字找到对应的命令结构体:
cmd_tbl_t *find_cmd (const char *cmd)
{
cmd_tbl_t *cmdtp;
cmd_tbl_t *cmdtp_temp = &__u_boot_cmd_start;
const char *p;
int len;
int n_found = 0;
len = ((p = strchr(cmd, '.')) == NULL) ? strlen (cmd) : (p - cmd);
for (cmdtp = &__u_boot_cmd_start; // __u_boot_cmd_start从uboot.lds文件中传进来
cmdtp != &__u_boot_cmd_end; // __u_boot_cmd_end从uboot.lds文件中传进来
cmdtp++) {
if (strncmp (cmd, cmdtp->name, len) == 0) { //从__u_boot_cmd_start到__u_boot_cmd_end逐个比对命令名
if (len == strlen (cmdtp->name))
return cmdtp;
cmdtp_temp = cmdtp;
n_found++;
}
}
if (n_found == 1) {
return cmdtp_temp;
}
return NULL;
}
bootm命令分析:
我们输入bootm 0x30007FC0命令之后就确定内核, 看看bootm命令是调用哪个函数执行
在cmd_bootm.c定义了一个宏:
U_BOOT_CMD(
bootm, CFG_MAXARGS, 1, do_bootm,
"bootm - boot application image from memory\n",
"[addr [arg ...]]\n - boot application image stored in memory\n"
"\tpassing arguments 'arg ...'; when booting a Linux kernel,\n"
"\t'arg' can be the address of an initrd image\n"
#ifdef CONFIG_OF_FLAT_TREE
"\tWhen booting a Linux kernel which requires a flat device-tree\n"
"\ta third argument is required which is the address of the of the\n"
"\tdevice-tree blob. To boot that kernel without an initrd image,\n"
"\tuse a '-' for the second argument. If you do not pass a third\n"
"\ta bd_info struct will be passed instead\n"
#endif
);
在command.h中定义了一个U_BOOT_CMD宏:
#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \
cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}
name = bootm
maxargs = CFG_MAXARGS
rep = 1
cmd = do_bootm
usage = "bootm - boot application image from memory\n"
help = "[addr [arg ...]]\n - boot application image stored in memory\n"
"\tpassing arguments 'arg ...'; when booting a Linux kernel,\n"
"\t'arg' can be the address of an initrd image\n"
command.h中定义宏
#define Struct_Section __attribute__ ((unused,section (".u_boot_cmd")))
将以上值代入宏
cmd_tbl_t __u_boot_cmd_bootm __attribute__ ((unused,section (".u_boot_cmd"))) = {
bootm,
CFG_MAXARGS,
1,
do_bootm,
"boo...memory\n",
"[add..image\n"
}
可以看出以上定义了名为__u_boot_cmd_bootm的cmd_tbl_t类型的结构体, 结构体的属性section(段属性)强制设置为.u_boot_cmd
__attribute__ ((unused,section (".u_boot_cmd")))是强制把section段属性设置为.u_boot_cmd
可以看出所有用U_BOOT_CMD定义的东西都会相当定义了一个cmd_tbl_t类型的结构,
这个结构体的特别之处就是它的段属性被强制设置为.u_boot_cmd, 所以所有的命令都被集中在__u_boot_cmd_start到__u_boot_cmd_end之间
实现简单的hello命令
创建cmd_hello.c
#include <common.h>
#include <watchdog.h>
#include <command.h>
#include <image.h>
#include <malloc.h>
#include <zlib.h>
#include <bzlib.h>
#include <environment.h>
#include <asm/byteorder.h>
int do_hello (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
int i = 0;
for (i = 0; i < argc; i++)
printf("%s\r\n", argv[i]);
printf("hello world\r\n");
return 0;
}
U_BOOT_CMD(
hello, CFG_MAXARGS, 1, do_hello,
"hello - hello\n",
"hello - long hello.........\n"
);
存放在common目录, 修改common目录下的Makefile文件, 加入cmd_hello.o
编译, 烧写就可以执行hello命令了