以下内容源于朱有鹏嵌入式课程的学习,如有侵权,请告知删除。
参考资料:http://www.cnblogs.com/biaohc/p/6394710.html
一、uboot命令体系基础
1、使用uboot命令
- uboot启动后进入命令行环境,在此输入命令按回车结束,uboot会接收此命令,然后解析、执行。
2、uboot命令体系实现代码在哪里?
- 实现代码在uboot/common/cmd_xxx.c中。
- command.c、main.c也和命令有关。
3、每个uboot命令对应一个函数
- 这是uboot实现命令体系的一种思路和方法。
4、argc&argv传给对应的函数,作为命令参数
(1)有些uboot的命令支持传递参数
- 命令对应的函数接收的参数列表中一般有argc和argv;
- 命令体系会把执行命令时的命令+参数(比如 md 30000000 10),以argc(这里为3)和argv(这里argv[0]=md,argv[1]=30000000,argv[2]=10)的方式传递给执行命令的函数。
- help命令背后对应的函数名叫:do_help,在uboot/common/command.c的236行。
- int do_help (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
二、uboot命令解析和执行过程分析
1、uboot启动的第二阶段即start_armboot()函数,最后进入一个死循环,循环体就是main_loop。
2、main_loop函数执行一遍,就是一个获取命令、解析命令、执行命令的过程。
(1)readline函数作用
- 输出x210 #;
- 内部调用cread_line函数,此函数从securecrt中命令行中读取命令,并进行初步的处理;
- ichar = getcmd_getch();这个函数是从串口中读取信息;如果读取到'\n'或者'\r'的话表示输入完成;
- 之后的代码是处理键盘的特殊字符,详细解释见博客:http://blog.chinaunix.net/uid-30031530-id-5152127.html
(2)rc = run_command (lastcommand, flag)函数
- 此函数进一步处理lastcommand中的字符串;
- 调用process_macros函数,处理字符串中的转义字符;
- 调用parse_line函数,统计argc、赋值argv;
- 调用find_cmd命令查找相应命令返回命令的结构体指针;
- (cmdtp->cmd) (cmdtp, flag, argc, argv)以函数指针的方式来执行命令函数;
命令的结构体
run_command函数
命令解释函数
- 如parse_line函数把"md 30000000 10"解析成argv[0]=md,argv[1]=30000000,argv[2]=10;
命令查找函数
- 本来可以把所有命令的结构体放在一个数组里或者一个链表里;
- 但是uboot中用了一个新的方法,就是定义了一个专门的段来存放所有的命令结构体,这个段的起始地址和结束地址都放在连接脚本里。见下图:
- 详细分析见博文http://blog.csdn.net/oqqhutu12345678/article/details/73251739
总结:uboot实现命令管理的思路
(1)填充1个结构体实例构成一个命令;
(2)给命令结构体实例附加特定段属性(用户自定义段),链接时将带有该段属性的内容链接在一起排列
- 命令结构体彼此紧挨着,不会夹杂其他东西,也不会遗漏带有这种段属性的实例,但它们是乱序的;
- 其实就是命令结构体的集合,有点像一个命令结构体数组。
(4)段起始地址和结束地址(定义在u-boot.lds中)决定了这些命令集的开始和结束地址。
附:
一、uboot中增加自定义命令
1、在已有的c文件中直接添加命令
(1)比如在uboot/common/command.c中添加一个命令,叫:mycmd。
(2)在已有的.c文件中添加命令比较简单,直接使用U_BOOT_CMD宏即可添加命令,给命令提供一个do_xxx的对应的函数。
(3)添加完成后要重新编译工程(make distclean; make x210_sd_config; make),然后烧录新的uboot去运行即可体验新命令。
(4)还可以在函数中使用argc和argv来验证传参。
2、自建一个c文件并添加命令
(1)在uboot/common目录下新建一个命令文件,叫cmd_xjh.c(对应的命令名就叫xjh,对应的函数就叫do_xjh函数),然后在c文件中使用U_BOOT_CMD宏,定义命令对应的函数。注意头文件包含不要漏掉。
(2)在uboot/common/Makefile中添加上xjh.o,目的是让Make在编译时把cmd_xjh.c编译链接进去。
(3)重新编译烧录。重新编译步骤是:make distclean; make x210_sd_config; make
二、creat_line函数
static int cread_line(const char *const prompt, char *buf, unsigned int *len)
{unsigned long num = 0;unsigned long eol_num = 0;unsigned long rlen;unsigned long wlen;char ichar;int insert = 1;int esc_len = 0;int rc = 0;char esc_save[8];while (1) {rlen = 1;
#ifdef CONFIG_BOOT_RETRY_TIMEwhile (!tstc()) { /* while no incoming data */if (retry_time >= 0 && get_ticks() > endtime)return (-2); /* timed out */}
#endifichar = getcmd_getch();if ((ichar == '\n') || (ichar == '\r')) {putc('\n');break;}/** handle standard linux xterm esc sequences for arrow key, etc.*/if (esc_len != 0) {if (esc_len == 1) {if (ichar == '[') {esc_save[esc_len] = ichar;esc_len = 2;} else {cread_add_str(esc_save, esc_len, insert,&num, &eol_num, buf, *len);esc_len = 0;}continue;}switch (ichar) {case 'D': /* <- key */ichar = CTL_CH('b');esc_len = 0;break;case 'C': /* -> key */ichar = CTL_CH('f');esc_len = 0;break; /* pass off to ^F handler */case 'H': /* Home key */ichar = CTL_CH('a');esc_len = 0;break; /* pass off to ^A handler */case 'A': /* up arrow */ichar = CTL_CH('p');esc_len = 0;break; /* pass off to ^P handler */case 'B': /* down arrow */ichar = CTL_CH('n');esc_len = 0;break; /* pass off to ^N handler */default:esc_save[esc_len++] = ichar;cread_add_str(esc_save, esc_len, insert,&num, &eol_num, buf, *len);esc_len = 0;continue;}}switch (ichar) {case 0x1b:if (esc_len == 0) {esc_save[esc_len] = ichar;esc_len = 1;} else {puts("impossible condition #876\n");esc_len = 0;}break;case CTL_CH('a'):BEGINNING_OF_LINE();break;case CTL_CH('c'): /* ^C - break */*buf = '\0'; /* discard input */return (-1);case CTL_CH('f'):if (num < eol_num) {getcmd_putch(buf[num]);num++;}break;case CTL_CH('b'):if (num) {getcmd_putch(CTL_BACKSPACE);num--;}break;case CTL_CH('d'):if (num < eol_num) {wlen = eol_num - num - 1;if (wlen) {memmove(&buf[num], &buf[num+1], wlen);putnstr(buf + num, wlen);}getcmd_putch(' ');do {getcmd_putch(CTL_BACKSPACE);} while (wlen--);eol_num--;}break;case CTL_CH('k'):ERASE_TO_EOL();break;case CTL_CH('e'):REFRESH_TO_EOL();break;case CTL_CH('o'):insert = !insert;break;case CTL_CH('x'):case CTL_CH('u'):BEGINNING_OF_LINE();ERASE_TO_EOL();break;case DEL:case DEL7:case 8:if (num) {wlen = eol_num - num;num--;memmove(&buf[num], &buf[num+1], wlen);getcmd_putch(CTL_BACKSPACE);putnstr(buf + num, wlen);getcmd_putch(' ');do {getcmd_putch(CTL_BACKSPACE);} while (wlen--);eol_num--;}break;case CTL_CH('p'):case CTL_CH('n'):{char * hline;esc_len = 0;if (ichar == CTL_CH('p'))hline = hist_prev();elsehline = hist_next();if (!hline) {getcmd_cbeep();continue;}/* nuke the current line *//* first, go home */BEGINNING_OF_LINE();/* erase to end of line */ERASE_TO_EOL();/* copy new line into place and display */strcpy(buf, hline);eol_num = strlen(buf);REFRESH_TO_EOL();continue;}
#ifdef CONFIG_AUTO_COMPLETEcase '\t': {int num2, col;/* do not autocomplete when in the middle */if (num < eol_num) {getcmd_cbeep();break;}buf[num] = '\0';col = strlen(prompt) + eol_num;num2 = num;if (cmd_auto_complete(prompt, buf, &num2, &col)) {col = num2 - num;num += col;eol_num += col;}break;}
#endifdefault:cread_add_char(ichar, insert, &num, &eol_num, buf, *len);break;}}*len = eol_num;buf[eol_num] = '\0'; /* lose the newline */if (buf[0] && buf[0] != CREAD_HIST_CHAR)cread_add_to_hist(buf);hist_cur = hist_add_idx;return (rc);
}