您的位置:首页 > 其它

uboot启动流程分析之四

2015-04-22 14:34 344 查看
Main_loop()函数在main.c文件中:
void main_loop (void)            //读取命令
{
#ifndef  CONFIG_SYS_HUSH_PARSER
static char lastcommand[CONFIG_SYS_CBSIZE] = { 0, };
int len;
int rc = 1;
int flag;
#endif

#ifdef   CONFIG_VERSION_VARIABLE
{
extern char version_string[];

setenv ("ver", version_string);  /* set version variable */
}
#endif   /* CONFIG_VERSION_VARIABLE */

//是否终止引导
if (bootdelay >= 0 && s && !abortboot(bootdelay)) {
int prev = disable_ctrlc(1);	/* 禁止  ^C */

s = getenv ("bootdelay");      //延迟
bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;

debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);

}

# ifdef CONFIG_MENUKEY
if (menukey == CONFIG_MENUKEY) {
s = getenv("menucmd");      //命令行菜单
if (s) {
# ifndef CONFIG_SYS_HUSH_PARSER
run_command (s, 0);
# else
}
}

/*
* Main Loop for Monitor Command Processing
*/
#ifdef CONFIG_SYS_HUSH_PARSER
parse_file_outer();      //解析输出流
/* This point is never reached */
for (;;);
#else
for (;;) {
len = readline (CONFIG_SYS_PROMPT);
// "fastboot# " /* Monitor Command Prompt */

if (len > 0) {           //读取控制台命令
strncpy (lastcommand, console_buffer, sizeof(lastcommand));
lastcommand[sizeof(lastcommand) - 1] = '\0';
}
else if (len == 0)
flag |= CMD_FLAG_REPEAT;
else if (len == -2) {
/* -2 表示超时, 尝试自动重启
*/
//重新初始化
do_reset (NULL, 0, 0, NULL);
return;		/* retry autoboot */
}

if (len == -1)
puts ("<INTERRUPT>\n");
else
rc =run_command (lastcommand, flag);

/* 清零  避免重复 */
lastcommand[0] = 0;
}
}


static __inline__ int abortboot(int bootdelay)
{
int abort = 0;

#ifdef CONFIG_MENUPROMPT
printf(CONFIG_MENUPROMPT);
#else
printf("Hit any key to stop autoboot: %2d ", bootdelay);
#endif

#if defined CONFIG_ZERO_BOOTDELAY_CHECK
/*
* Check if key already pressed
* Don't check if bootdelay < 0
*/
if (bootdelay >= 0) {
if (tstc()) {	           //是否有键按下
(void) getc();  /* consume input	*/   //接收键值
puts ("\b\b\b 0");
abort = 1;	/* don't auto boot	*/
//修改标记,停止自动引导
}
}
#endif

while ((bootdelay > 0) && (!abort)) {    //如果延时大于0并且停止标记没有赋值则进入延时循环,直到延时完成或接收按键
int i;

--bootdelay;
/* delay 100 * 10ms */  测试按键100次,之后延时10ms
for (i=0; !abort && i<100; ++i) {
if (tstc()) {	/* we got a key press	*/
abort  = 1;	/* don't auto boot	*/          //按键,停止自动引导
bootdelay = 0;           //延时归零
# ifdef CONFIG_MENUKEY
menukey = getc();
# else
(void) getc();  /* consume input	*/
# endif
break;
}
udelay(10000);      //延时10ms
}

printf("\b\b\b%2d ", bootdelay);        //打印当前剩余时间
}

putc('\n');

#ifdef CONFIG_SILENT_CONSOLE
if (abort)
gd->flags &= ~GD_FLG_SILENT;
#endif

return abort;      //返回结果,1是停止引导,0是自动引导
}
# endif	/* CONFIG_AUTOBOOT_KEYED */
#endif	/* CONFIG_BOOTDELAY >= 0  */


int run_command (const char *cmd, int flag)
{
cmd_tbl_t *cmdtp;
char cmdbuf[CONFIG_SYS_CBSIZE];	/* 复制命令行字符串*/
char *token;			/* start of token in cmdbuf	*/
char *sep;			/* end of token (separator) in cmdbuf */
char finaltoken[CONFIG_SYS_CBSIZE];
char *str = cmdbuf;
char *argv[CONFIG_SYS_MAXARGS + 1];	/* NULL terminated	*/
int argc, inquotes;
int repeatable = 1;
int rc = 0;

clear_ctrlc();		                                /* 清除 Control C */

if (!cmd || !*cmd) {
return -1;	/* 空命令行 */
}

if (strlen(cmd) >= CONFIG_SYS_CBSIZE) {   //命令行太长
puts ("## Command too long!\n");
return -1;
}

strncpy (cmdbuf, cmd, sizeof(cmdbuf));      //复制
cmdbuf[sizeof(cmdbuf) - 1] = '\0';

/* Process separators and check for invalid
* repeatable commands
*/

#ifdef DEBUG_PARSER
printf ("[PROCESS_SEPARATORS] %s\n", cmd);
#endif
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循环结束有两种情况:
//遍历到结尾或是存在多条指令,完整读取一条命令后

token = str;
if (*sep) {                   //当前为分隔符;
str = sep + 1;   	/* 指向下一个命令 */
*sep = '\0';          //将分隔符替换为空字符
}
else                      //循环结束  为空
str = sep;	/* 指向最后 */
#ifdef DEBUG_PARSER
printf ("token: \"%s\"\n", token);
#endif

/* 宏命令 */
process_macros (token, finaltoken);    //将token指向的命令中的宏替换掉

/* 分离参数 */
///将每一个参数用‘/0’隔开,argv中的每一个指针指向一个参数的起始地址。返回值为参数的个数
if ((argc = parse_line (finaltoken, argv)) == 0) {       //返回参数的个数
rc = -1;	/* no command at all */
continue;<pre name="code" class="html">/* 在命令列表中寻找对应的命令 */
if ((cmdtp = <strong>find_cmd</strong>(argv[0])) == NULL) {
printf ("Unknown command '%s' - try 'help'\n", argv[0]);
rc = -1;	/* give up after bad command */
continue;
}
if (argc > cmdtp->maxargs) {     //检查参数是否过多
cmd_usage(cmdtp);
rc = -1;
continue;
}

#if defined(CONFIG_CMD_BOOTD)
/* avoid "bootd" recursion */
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

/* OK - call function to do the command */
if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {     //调用命令执行函数        参照 cmd_tbl_t结构内容
rc = -1;
}

//设置命令自动重复执行的标志,即只按下enter键
repeatable &= cmdtp->repeatable;

/* Did the user stop this? */
if (had_ctrlc ())              //检查是否有ctrl+c按下,如有结束当前命令
return -1;	/* if stopped then not repeatable */
}

return rc ? rc : repeatable;
}


}

  
int parse_line (char *line, char *argv[])
{
int nargs = 0;

#ifdef DEBUG_PARSER
printf ("parse_line: \"%s\"\n", line);
#endif
while (nargs < CONFIG_SYS_MAXARGS) {

/* skip any white space */
while ((*line == ' ') || (*line == '\t')) {
++line;
//找到开始位置
}

if (*line == '\0') {	/* end of line, no more args	*/           结束位置
argv[nargs] = NULL;
#ifdef DEBUG_PARSER
printf ("parse_line: nargs=%d\n", nargs);
#endif
return (nargs);
}

argv[nargs++] = line;	/* begin of argument string	*/

/* find end of string */
while (*line && (*line != ' ') && (*line != '\t')) {
++line;
//下一个参数
}

if (*line == '\0') {	/* end of line, no more args	*/
argv[nargs] = NULL;
#ifdef DEBUG_PARSER
printf ("parse_line: nargs=%d\n", nargs);
#endif
return (nargs);
}

*line++ = '\0';		   //每个参数都是一个单独的字符串
}

printf ("** Too many args (max. %d) **\n", CONFIG_SYS_MAXARGS);

#ifdef DEBUG_PARSER
printf ("parse_line: nargs=%d\n", nargs);
#endif
return (nargs);
}


如何查找命令???

//command.c
cmd_tbl_t *find_cmd (const char *cmd)
{                              //返回类型cmd_tbl_t
int len = &__u_boot_cmd_end - &__u_boot_cmd_start;
return find_cmd_tbl(cmd, &__u_boot_cmd_start, len);
}
//u_boot.lds文件中定义了u_boot_cmd段

结构体:     command.h
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	CONFIG_SYS_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
};

typedef struct cmd_tbl_s	cmd_tbl_t;

extern cmd_tbl_t  __u_boot_cmd_start;
extern cmd_tbl_t  __u_boot_cmd_end;

//查找命令的函数
cmd_tbl_t *   find_cmd_tbl (const char *cmd, cmd_tbl_t *table, int table_len)
{	/*
* Some commands allow length modifiers (like "cp.b");
* 仅比较点之前的.
*/命令长度
len = ((p = strchr(cmd, '.')) == NULL) ? strlen (cmd) : (p - cmd);

for (cmdtp = table;         //查找
cmdtp != table + table_len;   //命令表table
cmdtp++) {
if (strncmp (cmd, cmdtp->name, len) == 0) {   //比较前len个字符
if (len == strlen (cmdtp->name))
return cmdtp;	/* 完全匹配*/

cmdtp_temp = cmdtp;	/* 相似命令 */
n_found++;
}
}
if (n_found == 1) {			/* exactly one match */
return cmdtp_temp;
}

return NULL;	/* not found or ambiguous command */
}


u_boot.lds:

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
/*指定输出可执行文件是elf格式,32位ARM指令,小端*/
OUTPUT_ARCH(arm)
/*输出平台arm*/
ENTRY(_start) /*可执行文件的起始段的段名是_start*/
SECTIONS
{
/*指定可执行image文件的全局入口点,通常这个地址都是ROM(flash)0x00*/
. = 0x00000000; //.代表0x00

. = ALIGN(4); /*4字节对对齐*/
.text : /*代码段*/
{
arch/arm/cpu/s40/start.o (.text) //start.S
arch/arm/cpu/s40/lowlevel_init.o (.text)
arch/arm/cpu/s40/ddrphy_training.o (.text)
arch/arm/cpu/s40/ddrphy_training_func.o (.text)
arch/arm/cpu/s40/ddr_dataeye_training.o (.text)
arch/arm/cpu/s40/emmc_boot.o (.text)
arch/arm/cpu/s40/chip.o (.text)
arch/arm/cpu/s40/uart.o (.text)
__bootram_code_end = .;
*(.text)
}
__text_end = .; //代表当前位置
. = . + 0x84;
. = ALIGN(4);
.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
//只读数据段
. = ALIGN(4);
.data : { *(.data) } //可读写数据段

. = ALIGN(4);
.got : { *(.got) } //uboot自定义的段

__u_boot_cmd_start = .;
.u_boot_cmd : { *(.u_boot_cmd) } //uboot相关命令
/fastboot/include/command.h
__u_boot_cmd_end = .;

. = ALIGN(4);
.image : { *(.image) } //加载各种image文件

. = ALIGN(4);
__bss_start = .;
.bss : { *(.bss) } //指定BSS段
_end = .;
}

接下来我们看一下如何来定义u_boot_cmd的:
common.h:
。。。
#define Struct_Section __attribute__ ((unused,section (".u_boot_cmd")))
//定义一个结构体Struction_Section 展开之后就是__attribute__ ((unused,section(".u_boot_cmd")))
//将变量编译到u_boot_cmd段中,并设置属性为unused

//__attribute__ 是GCC的关键字,描述变量的属性。
//对结构体(struct )进行属性设置,大致有六个参数值可以被设定
//即:aligned, packed, transparent_union, unused,
deprecated 和 may_alias 。
//aligned:对齐格式
//packed:设定其类型的每一个变量的内存约束

#ifdef CONFIG_SYS_LONGHELP

#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
//例:boot 0,0,fun,"boot xxx","boot --help"
//cmd_tbl_t __u_boot_cmd_boot __attribute__ ((unused,section(".u_boot_cmd"))) = {"boot",0,0,fun,"boot xxx","boot --help"}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: