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"}
相关文章推荐
- 从0移植uboot (二) _uboot启动流程分析
- uboot启动流程分析之五
- uboot流程分析--修改android启动模式按键
- Uboot启动流程分析
- Uboot启动流程分析
- 天嵌科技TQ2440的uboot启动流程分析学习笔记
- Uboot启动流程分析
- 从0移植uboot (二) _uboot启动流程分析
- uboot流程分析--修改android启动模式按键
- Uboot启动流程分析:启动阶段1 Start.S
- uboot启动流程分析之二
- uboot流程分析--修改android启动模式按键
- uboot 启动流程分析
- uboot 启动流程分析
- Uboot 启动流程分析:启动阶段2 board.c
- uboot启动流程分析之六
- uboot流程分析--修改android启动模式按键
- Uboot启动流程分析
- HISI3520DV300 折腾记录(一)之 《Uboot-Start.S分析 以及 相关启动流程分析》
- Uboot启动流程分析