最近有点空了,就看了点开发板的UBOOT源码(主要是去分析如何解析命令)。
uboot最开始执行的代码是汇编,在标签 _start处开始,后面有了个中断向量表(主要是为个让这点代码被放有地址0x0处),用汇编程序是它可以保证这点代码就在0X0处。
.globl _start
_start: b reset //上电后执行的第一行,跳到reset处。
ldr pc, _undefined_instruction //未定义中断
ldr pc, _software_interrupt //软中断
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
进入到后,
之后设置,CPU工作在SVC32 模式,
对设备要完成很多的设置,这里不详讲。
在汇编的最后
ldr pc, _start_armboot //PC指针指向start_armboot函数,在/lib_arm/board.c中
在这个函数里做了很多数据的初始化工作,
start_armboot在最后用了一个for(;;)死循环,之后调用了main_loop();在/common/main.c中。在这里用死循环的主要原因是防止main_loop的调用没有成功执行。
1 在main_loop的前面部分记录并限制开机的次数。
2 初始化modem
3 set version
4 启动延迟功能,需要等待用户从串口/网络接口输入等。
完成设置后main_loop函数又用了一个for(;;)循环,之后就在这个死循环里面不断的读命令并执行命令,命令的解析开始~~~
parse_file_outer();也是一种命令 解析,可是没有用,我本也想去看一下是如何用行命令解析的,可是看了半天,由于水平太差了。没有看明白,它的命令解析主要是用的Hush.c中实现。
今天讲的是后面的这一种。
readline (CFG_PROMPT);用来获得用户输入的命令,CFG_PROMPT就如同 # 的东西。
在readline(CFG_PROMPT)中用getc()获得用户的输入,并存放在console_buffer数组当中。后面用了一个switch语句对输入的值进行检测,若是一些特别的ASCII码值(如:^H)则进行不同的处理(在这里实现了输入的一个比较复杂的操作就是删除操作)。
在readline中的前面定义了一些变量,之后打印了一些东西就不多讲了。后面会有一些打印之类的函数调用也同样不多讲了。
clear_ctrlc();//这个函数太简单了,我就不说了,
if (strlen(cmd) >= CFG_CBSIZE) { //这里的strlen是测试的cmd这个指针指向的命令的字符长度,长度不能超过CFG_CBSIZE。
puts ("## Command too long!\n");
return -1;
}
strcpy (cmdbuf, cmd);//把cmd里面的内容拷到cmdbuf中去。
while (*str) { //这里的这个while函数 的注释说是分离“;“ 但我真没看出来哪里有分离,(本人水平真的很有限)
........
}
token = str;
if (*sep) { //把*sep清空,
str = sep + 1;
*sep = '\0';
}
后面用了一个函数process_macros的作用我也不是很清楚,但看起来也不是太重要了。
parse_line(finaltoken, argv)是对参数进行获得,
find_cmd(argv[0])再用这个函数在一个对命令与命令库中的命令进行比较,在这个函数里面用来比较是用的strncmp(cmd, cmdtp->name, len) == 0)。而放这些命令 的就是一个结构体cmd_tbl_s,
struct cmd_tbl_s {
char *name; //命令的名字,进行命令的解析就是用的名字。
int maxargs; //最大行参数
int repeatable; //允许自动覆盖。
int (*cmd)(struct cmd_tbl_s *, int, int, char *[]); //命令实现用的指针
char *usage; /* Usage message (short) */
#ifdef CFG_LONGHELP
char *help; //命令的帮助
#endif
#ifdef CONFIG_AUTO_COMPLETE
int (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[])
#endif
};
在strncmp中比较用的是对指针中的值进行相减,如果每一位相减都为0,则这命令找到了,返回该命令的指针。此时就已经得到了命令,后面要做的事当然就是实现用户的命令了。
if (cmdtp->cmd == do_bootd) 下面这一句,是防止bootd的递归。
if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) //这里就是调用的cmd_tbl_s结构体当中的一个函数指针,
{ //cmd指针指向命令的实现函数。
rc = -1;
}
run_command函数结束,由于这是在一个for(;;)死循环当中,程序又回到了readline (CFG_PROMPT);获取用户输入的命令,