记得以前曾经做过WINCE下面利用EBOOT从SD卡读取文件系统更新NAND种的文件,已实现在文件系统被破坏的情况下,用户可以自己还原,那么如果是LINUX系统呢?
思路是一样:UBOOT启动至第2阶段(没有自启动系统)-----------判断是否更新内核和文件系统--------------如果接收到了用户命令则从SD卡拷贝文件写入NAND指定位置;反之,则启动系统
重点是怎么接收到用户指令和从SD卡种拷贝文件;
在UBOOT运行至第2阶段的时候:lib_arm/board.c中调用common/main.c下的main_loop函数
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
char *s;
int bootdelay;
#endif
#ifdef CONFIG_PREBOOT
char *p;
#endif
#ifdef CONFIG_BOOTCOUNT_LIMIT
unsigned long bootcount = 0;
unsigned long bootlimit = 0;
char *bcs;
char bcs_set[16];
#endif /* CONFIG_BOOTCOUNT_LIMIT */
#if defined(CONFIG_VFD) && defined(VFD_TEST_LOGO)
ulong bmp = 0; /* default bitmap */
extern int trab_vfd (ulong bitmap);
#ifdef CONFIG_MODEM_SUPPORT
if (do_mdm_init)
bmp = 1; /* alternate bitmap */
#endif
trab_vfd (bmp);
#endif /* CONFIG_VFD && VFD_TEST_LOGO */
#ifdef CONFIG_BOOTCOUNT_LIMIT
bootcount = bootcount_load();
bootcount++;
bootcount_store (bootcount);
sprintf (bcs_set, "%lu", bootcount);
setenv ("bootcount", bcs_set);
bcs = getenv ("bootlimit");
bootlimit = bcs ? simple_strtoul (bcs, NULL, 10) : 0;
#endif /* CONFIG_BOOTCOUNT_LIMIT */
#ifdef CONFIG_MODEM_SUPPORT
debug ("DEBUG: main_loop: do_mdm_init=%d/n", do_mdm_init);
if (do_mdm_init) {
char *str = strdup(getenv("mdm_cmd"));
setenv ("preboot", str); /* set or delete definition */
if (str != NULL)
free (str);
mdm_init(); /* wait for modem connection */
}
#endif /* CONFIG_MODEM_SUPPORT */
#ifdef CONFIG_VERSION_VARIABLE
{
extern char version_string[];
setenv ("ver", version_string); /* set version variable */
}
#endif /* CONFIG_VERSION_VARIABLE */
#ifdef CFG_HUSH_PARSER
u_boot_hush_start ();
#endif
#ifdef CONFIG_AUTO_COMPLETE
install_auto_complete();
#endif
#ifdef CONFIG_PREBOOT
if ((p = getenv ("preboot")) != NULL) {
# ifdef CONFIG_AUTOBOOT_KEYED
int prev = disable_ctrlc(1); /* disable Control C checking */
# endif
# ifndef CFG_HUSH_PARSER
run_command (p, 0);
# else
parse_string_outer(p, FLAG_PARSE_SEMICOLON |
FLAG_EXIT_FROM_LOOP);
# endif
# ifdef CONFIG_AUTOBOOT_KEYED
disable_ctrlc(prev); /* restore Control C checking */
# endif
}
#endif /* CONFIG_PREBOOT */
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
s = getenv ("bootdelay");
bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
debug ("### main_loop entered: bootdelay=%d/n/n", bootdelay);
# ifdef CONFIG_BOOT_RETRY_TIME
init_cmd_timeout ();
# endif /* CONFIG_BOOT_RETRY_TIME */
#ifdef CONFIG_POST
if (gd->flags & GD_FLG_POSTFAIL) {
s = getenv("failbootcmd");
}
else
#endif /* CONFIG_POST */
#ifdef CONFIG_BOOTCOUNT_LIMIT
if (bootlimit && (bootcount > bootlimit)) {
printf ("Warning: Bootlimit (%u) exceeded. Using altbootcmd./n",
(unsigned)bootlimit);
s = getenv ("altbootcmd");
}
else
#endif /* CONFIG_BOOTCOUNT_LIMIT */
s = getenv ("bootcmd");
debug ("### main_loop: bootcmd=/"%s/"/n", s ? s : "<UNDEFINED>");
if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
# ifdef CONFIG_AUTOBOOT_KEYED
int prev = disable_ctrlc(1); /* disable Control C checking */
# endif
# ifndef CFG_HUSH_PARSER
run_command (s, 0);
# else
parse_string_outer(s, FLAG_PARSE_SEMICOLON |
FLAG_EXIT_FROM_LOOP);
# endif
# ifdef CONFIG_AUTOBOOT_KEYED
disable_ctrlc(prev); /* restore Control C checking */
# endif
}
# ifdef CONFIG_MENUKEY
if (menukey == CONFIG_MENUKEY) {
s = getenv("menucmd");
if (s) {
# ifndef CFG_HUSH_PARSER
run_command (s, 0);
# else
parse_string_outer(s, FLAG_PARSE_SEMICOLON |
FLAG_EXIT_FROM_LOOP);
# endif
}
}
#endif /* CONFIG_MENUKEY */
#endif /* CONFIG_BOOTDELAY */
#ifdef CONFIG_AMIGAONEG3SE
{
extern void video_banner(void);
video_banner();
}
#endif
/*
* Main Loop for Monitor Command Processing
*/
#ifdef CFG_HUSH_PARSER
parse_file_outer();
/* This point is never reached */
for (;;);
#else
for (;;) {
#ifdef CONFIG_BOOT_RETRY_TIME
if (rc >= 0) {
/* Saw enough of a valid command to
* restart the timeout.
*/
reset_cmd_timeout();
}
#endif
len = readline (CFG_PROMPT);
flag = 0; /* assume no special flags for now */
if (len > 0)
strcpy (lastcommand, console_buffer);
else if (len == 0)
flag |= CMD_FLAG_REPEAT;
#ifdef CONFIG_BOOT_RETRY_TIME
else if (len == -2) {
/* -2 means timed out, retry autoboot
*/
puts ("/nTimed out waiting for command/n");
# ifdef CONFIG_RESET_TO_RETRY
/* Reinit board to run initialization code again */
do_reset (NULL, 0, 0, NULL);
# else
return; /* retry autoboot */
# endif
}
#endif
if (len == -1)
puts ("<INTERRUPT>/n");
else
rc = run_command (lastcommand, flag);
if (rc <= 0) {
/* invalid command or not repeatable, forget it */
lastcommand[0] = 0;
}
}
#endif /*CFG_HUSH_PARSER*/
}
这里会做两个判断,调用static __inline__ int abortboot(int bootdelay)
函数,判断是否有用户中断,如果有则进入死循环,接收用户命令,并根据命令,调用相应的函数处理
如果你下载过android系统文件,你肯定知道会有类似nand write c0008000 600000 300000等命令,来写入文件;上面run_command函数 这个函数就是处理类似这样的命令,具体实现可以查看代码各函数功能,
既然是让客户自更新,我们也不能让客户按照我们测试人员一样,打开串口信息,一行行敲命令吧,那就完蛋了。。。。
所以我们可以在这里加入我们的更新系统的提示!-------------(1)用户触发更新系统中断;(2)接收中断,调用run_command函数处理事件(将SD卡种文件写入NAND指定位置)
对于步骤1;我们可以采用读取某个I/O口状态来判断是否更新系统;
对于步骤2:关键是加入我们的处理函数,告诉系统“要从SD卡读取文件写入NAND”
这里就需要了解下run_command函数了
#ifdef DEBUG_PARSER
printf ("[RUN_COMMAND] cmd[%p]=/"", cmd);
puts (cmd ? cmd : "NULL"); /* use puts - string may be loooong */
puts ("/"/n");
#endif
clear_ctrlc(); /* forget any previous Control C */
if (!cmd || !*cmd) {
return -1; /* empty command */
}
if (strlen(cmd) >= CFG_CBSIZE) {
puts ("## Command too long!/n");
return -1;
}
strcpy (cmdbuf, cmd);
/* 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;
}
/*
* Limit the token to data between separators
*/
token = str;
if (*sep) {
str = sep + 1; /* start of command for next pass */
*sep = '/0';
}
else
str = sep; /* no more commands for next pass */
#ifdef DEBUG_PARSER
printf ("token: /"%s/"/n", token);
#endif
/* find macros in this token and replace them */
process_macros (token, finaltoken);
/* Extract arguments */
if ((argc = parse_line (finaltoken, argv)) == 0) {
rc = -1; /* no command at all */
continue;
}
/* Look up command in command table */
if ((cmdtp = find_cmd(argv[0])) == NULL) {
printf ("Unknown command '%s' - try 'help'/n", argv[0]);
rc = -1; /* give up after bad command */
continue;
}
/* found - check max args */
if (argc > cmdtp->maxargs) {
printf ("Usage:/n%s/n", cmdtp->usage);
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) {
rc = -1;
}
repeatable &= cmdtp->repeatable;
/* Did the user stop this? */
if (had_ctrlc ())
return -1; /* if stopped then not repeatable */
}
return rc ? rc : repeatable;
}
流程:处理宏定义,分析命令和参数 , 查找是否有命令 ,执行命令
我们可以通过nand write c0008000 600000 300000这个命令来了解整个过程
common/cmd_nand.c下 U_BOOT_CMD(nand, CONFIG_SYS_MAXARGS, 1, do_nand..............................下有命令的说明
相应的NAND驱动中就有具体的实现;
重要函数:
/* Look up command in command table */
if ((cmdtp = find_cmd(argv[0])) == NULL)
cmd_tbl_t *find_cmd (const char *cmd)
这里会遍历所有结构体集合
find_cmd 函数原型
所以我们可以定义我们自己的U_BOOT_CMD
类似
U_BOOT_CMD(
SD, 2, 1, DO_SD,
"xxxxxxxx/n",
"xxxxxxxxxxx /n"
" -xxxxxxxxxx/n"
);
然后定义DO_SD函数即可