在u-boot之start_armboot函数分析已经分析过了整个程序框架,但只是说了下什么时候运行内核,并没有具体说明是怎么执行内核的。内核启动分以下几个步骤说明:
1、启动参数bootcmd=nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0说明
2、run_command函数是怎么执行命令的
3、u-boot给内核传递的参数说明
4、内核启动流程
1、启动参数bootcmd=nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0说明
这个参数分了两条uboot命令首先从kernel区拷贝相应大小的内核到内存0x30007FC0 处;然后执行 bootm 0x30007FC0命令,这条命令后面会详细解释流程。执行了这条命令后就可以从0x30007FC0处启动内核了。这里需要再说明一下其实真正的内核位于0x30008000处,因为前面64字节是内核的一些信息,具体定义如下:
typedef struct image_header {
uint32_t ih_magic; /* Image Header Magic Number *///内核的编号
uint32_t ih_hcrc; /* Image Header CRC Checksum */ //内核头部数据的CRC校验
uint32_t ih_time; /* Image Creation Timestamp */ //内核建立的时间戳
uint32_t ih_size; /* Image Data Size */ //内核的大小
uint32_t ih_load; /* Data Load Address */ //内核的装载地址
uint32_t ih_ep; /* Entry Point Address */ //内核切入点地址
uint32_t ih_dcrc; /* Image Data CRC Checksum */ //内核数据的CRC校验
uint8_t ih_os; /* Operating System *///内核是什么操作系统
uint8_t ih_arch; /* CPU architecture */ //内核的CPU架构
uint8_t ih_type; /* Image Type */ //内核映像文件类型
uint8_t ih_comp; /* Compression Type *///压缩类型
uint8_t ih_name[IH_NMLEN]; /* Image Name *///内核映像文件名称
} image_header_t;
2、run_command函数是怎么执行命令的
run_command函数在Main.c (common)中,这个函数是整个U-BOOT命令的核心函数。uboot的链接文件中存在着.u_boot_cmd段,这个段的内容就是存放的所有的UBOOT命令
这个段的定义在command.h(include)中,如下:其中
#define Struct_Section __attribute__ ((unused,section ('.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}
//分解为=>U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) cmd_tbl_t __u_boot_cmd_name __attribute__ ((unused,section ('.u_boot_cmd'))) = {name, maxargs, rep, cmd, usage, help}
//name为命令的名字
//maxargs为命令的最大数量
//rep为命令是否可以重复,表示按下回车是否可以运行上一次的命令
//cmd表示具体命令的执行函数指针,这个函数不在.u_boot_cmd这个段内,只是函数的指针存放在.u_boot_cmd这个段内
//usage表示简短的用法说明
//help表示长的说明
struct cmd_tbl_s {
char *name; /* Command Name */
int maxargs; /* maximum number of arguments */
int repeatable; /* autorepeat allowed? */
/* Implementation function */
int (*cmd)(struct cmd_tbl_s *, int, int, char *[]);
char *usage; /* Usage message (short) */
#ifdef CFG_LONGHELP
char *help; /* Help message (long) */
#endif
#ifdef CONFIG_AUTO_COMPLETE
/* do auto completion on the arguments */
int (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]);
#endif
};
举个例子以bootm这个命令为例子,在u-boot控制台输入bootm命令后,u-boot代码会执行run_command(bootm, 0);这个函数。然后调用do_bootm函数。
U_BOOT_CMD(
bootm, CFG_MAXARGS, 1, do_bootm,
'bootm - boot application image from memoryn',
'[addr [arg ...]]n - boot application image stored in memoryn'
'tpassing arguments 'arg ...'; when booting a Linux kernel,n'
't'arg' can be the address of an initrd imagen'
#ifdef CONFIG_OF_FLAT_TREE
'tWhen booting a Linux kernel which requires a flat device-treen'
'ta third argument is required which is the address of the of then'
'tdevice-tree blob. To boot that kernel without an initrd image,n'
'tuse a '-' for the second argument. If you do not pass a thirdn'
'ta bd_info struct will be passed insteadn'
#endif
);
照着执行bootm命令继续下去,run_command(bootm, 0)函数首先做一些参数的检查
clear_ctrlc(); /* forget any previous Control C *///清除前一条命令
if (!cmd || !*cmd) {//检查cmd命令是否存在
return -1; /* empty command */
}
if (strlen(cmd) >= CFG_CBSIZE) {//检查参数个数是否超过最大限制
puts ('## Command too long!n');
return -1;
}
strcpy (cmdbuf, cmd);//将cmd全部拷贝到cmdbuf中
run_command(bootm, 0)继续运行,一直循环寻找str中的命令。str在初始化的时候就已经被赋为cmdbuf了。大致说明一下程序的流程:
a、首先就查询命令有几条
b、展开调用环境变量的命令
c、取得参数的个数
d、查找命令,从.u_boot_cmd段中找出符合的命令
e、执行命令的运行函数
while (*str) {//从输入的字符中取出有效命令 by andy
/*
* 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;
}
/*
* Limit the token to data between separators
*/
token = str;
if (*sep) {//如果不止一条命令 by andy
str = sep + 1; /* start of command for next pass *///指向下一条命令的开头,当前seq指向的是;
*sep = '
