您的位置:首页 > 其它

uboot命令解释与运行分析

2015-06-29 15:18 375 查看
这一回来分析一下uboot中命令行的解释, 所以我们直接从main_loop开始分析.

1. 从汇编阶段进入c阶段的第一个函数是start_xxx, 如/lib_unicore/board.c中的start_unicoreboot. 前半部分调用了若干初始化函数来进行部分硬件的初始化, 并设置一下环境. 这里不是我们本回要讨论的所以一一跳过. 在start_xxx的最后调用了main_loop(), 而且还是被一个死循环死死圈住了;

for (;;) {

main_loop ();

}

2. 现在我们已经进入了这个圈套那么只能往里钻了. common/main.c文件中的main_loop().

//从环境变量里找bootdelay

s = getenv ("bootdelay");

//如果环境变量中有定义, 将delay数值赋值给变量bootdelay, 否则赋值CONFIG_BOOTDELAY.

bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;

//获取bootcmd

s = getenv ("bootcmd");

debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "");

//如果bootdelay和bootcmd都存在, 那么在abortboot()中延时bootdelay, 调用run_command执行在bootcmd中定义的默认命令

if (bootdelay >= 0 && s && !abortboot (bootdelay)) {

run_command (s, 0);

}

上面代码主要是对自启动部分的描述, 其中命令执行部分是在run_command中进行的, 这个等在后文分析. 如果我们没有bootcmd或者在延时中被打断, 那么代码会继续向下执行

//下面for循环是uboot处理终端命令的主循环, 这时等待我们从键盘中输入一行命令, 真正的人机交互从这里开始

for (;;) {

// CFG_PROMPT中定义的就是我们在命令行显示的题头部分,如"sep611=>",

// 在readline中首先先显示CFG_PROMPT定义的字符串, 然后等待键盘输入

// 每次从终端读入一个字符, 先判断是否是正常字符(ctrl+c, 回车等属于非正常字符)

// 对与正常字符那么将其存入console_uffer中, 并在终端回显

len = readline (CFG_PROMPT);

// 这时我们已经收到屏幕上的一行输入, 而且命令已经存console_uffer

flag = 0; /* assume no special flags for now */

if (len > 0)

strcpy (lastcommand, console_buffer);

else if (len == 0)

flag |= CMD_FLAG_REPEAT;

// 命令从console_buffer搬运到lastcommand中, 乾坤大挪移

rc = run_command (lastcommand, flag);

3.read_line()读取到命令行后会调用common/main.c文件中的run_command(). 现在是分析run_command()的时候了, 不管是从环境变量还是终端获得命令, 都是由run_command()来处理的.

//下面if语句判断命令是否太长, 还是避免有些变态的家伙输入了超过CFG_CBSIZE个字符的命令

if (strlen(cmd) >= CFG_CBSIZE) {

puts ("## Command too long!\n");

return -1;

}

//这个世界到处体现了自私, 对命令又进行了一次拷贝, 安全吗?

strcpy (cmdbuf, cmd);

中场休息, 下面要进入处理cmdbuf的循环中了, 长征马上开始

//str就是指向cmdbuf的指针, 其实这些东西都是针对的刚才那行命令

while (*str) {

//注释很清楚, 找到;作为命令结束符, 因为多个命令可以一次输入, 并以;分割. 忽略'\;'

/* Find separator, or string end Allow simple escape of ';' by writing "\;" */

for (inquotes = 0, sep = str; *sep; sep++) {

if ((*sep=='\'') &&

(*(sep-1) != '\\'))

inquotes=!inquotes;

if (!inquotes &&

(*sep == ';') && /*
separator */

( sep != str) && /*
past string start */

(*(sep-1) != '\\')) /*
and NOT escaped */

break;

}

//如果上面for循环找到一条以';'结束的命令, 那么sep指向命令末尾


/*

* Limit the token to data between separators

*/

token = str;

if (*sep) {

str = sep + 1; /*
str为下一条命令开始start of command for next pass */

*sep = '\0'; /*
作为token的结束 */

}

else

str = sep; /* 只有一条命令 */

/* 找到命令中的宏兵替换宏, 这中类型的命令我没有用过, 所以暂不去管它, 现在命令已经转移到finaltoken find macros in this token and replace them */

process_macros (token, finaltoken);

/* 将命令行中的关键词取出放入argv中, 注意, 命令行被分解到argv数组中, Extract arguments */

if ((argc = parse_line (finaltoken, argv)) == 0) {

rc = -1; /*
no command at all */

continue;

}

/* 查找命令, 我们认为命令行中的第一个关键词就是命令, Look up command in command table */

if ((cmdtp = find_cmd(argv[0])) == NULL) {

printf ("Unknown command '%s' - try 'help'\n", argv[0]);

rc = -1; /*
give up after bad command */

continue;

}

4.就此打断一下, 我们要分析一下find_cmd了, 不能再跳过了. find_cmd()在.u_boot_cmd段中寻找该命令的cmd_tbl_t结构, 找到后返回该结构. 该命令的结构是通过定义在include/command.h中的宏定义U_BOOT_CMD登记进.u_boot_cmd段中的.

//先研究一下这个神奇的U_BOOT_CMD, 定义如下, 其中cmd_tbl_t是命令的结构体类型, 这里不罗列了,成员包括命令名字, 参数的最大个数,
使用说明等等. Struct_Section定义为


#define Struct_Section
__attribute__ ((unused,section (".u_boot_cmd")))

//所以, U_BOOT_CMD将会创建一个类型为cmd_tbl_t的结构体对象, 名字为__u_boot_cmd_name, 存储在__.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}

//这个for循环是find_cmd()的核心, __u_boot_cmd_start在lds连接脚本中, 指定的是在__.u_boot_cmd的开始地址, __u_boot_cmd_end就是相对应的结束地址. 注意:for中的cmdtp++每次加的不是1二是sizeof(cmd_tbl_t).
所以在这个循环中将会遍历在__.u_boot_cmd段中的所有命令, 并查找与本次命令向对应的那个命令的结构体.

for (cmdtp = &__u_boot_cmd_start;

cmdtp != &__u_boot_cmd_end;

cmdtp++) {

if (strncmp (cmd, cmdtp->name, len) == 0) {

if (len == strlen (cmdtp->name))

return cmdtp; /* 命令完全匹配, 返回命令结构体 full match */

cmdtp_temp = cmdtp; /* 部分匹配, 后面会返回cmdtp_temp, abbreviated command ? */

n_found++;

}

}

5. 刚才我们在长征的半路翻越了一座雪山, 现在继续回到while循环中

/* 雪山之后就是平坦的草原, 是不是觉得下面这个判断很简单, found - check max args */

if (argc > cmdtp->maxargs) {

printf ("Usage:\n%s\n", cmdtp->usage);

rc = -1;

continue;

}

//这是啥, 我不管它了, 掠过这条小溪

#if defined(CONFIG_CMD_BOOTD)

/* avoid "bootd" recursion */

if (cmdtp->cmd == do_bootd) {

if (flag & CMD_FLAG_BOOTD) {

puts ("'bootd' recursion detected\n");

rc = -1;

continue;

} else {

flag |= CMD_FLAG_BOOTD;

}

}

#endif

//长征马上结束, 胜利就在眼前! 调用结构体中注册的cmd函数, 何时注册的呢? 上面不远处介绍的U_BOOT_CMD!

/* OK - call function to do the command */

if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {

rc = -1;

}

repeatable &= cmdtp->repeatable;

/* ctrl+c 会终止, Did the user stop this? */

if (had_ctrlc ())

return -1; /*
if stopped then not repeatable */

}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: