uboot启动流程源码分析(二)

简介: uboot启动流程源码分析(二)

上一篇找到了我的关键点–main_loop函数,这一篇来好好看一下。

uboot中的main_loop函数是怎么工作的。

1、main_loop函数是做什么的?

start_armboot最后进入死循环调用了main_loop 函数;

uboot的目的是启动内核,那么main_loop一定会有设置启动参数启动内核的实现;

main_loop()函数做的都是与具体平台无关的工作,主要包括初始化启动次数限制机制、设置软件版本号、打印启动信息、解析命令等。

2、main_loop()函数内容

void main_loop(void)
{
    const char *s;
    bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, "main_loop");
    if (IS_ENABLED(CONFIG_VERSION_VARIABLE))
        env_set("ver", version_string);  /* set version variable */
    cli_init();
    if (IS_ENABLED(CONFIG_USE_PREBOOT))
        run_preboot_environment_command();
    if (IS_ENABLED(CONFIG_UPDATE_TFTP))
        update_tftp(0UL, NULL, NULL);
    s = bootdelay_process();
    if (cli_process_fdt(&s))
        cli_secure_boot_cmd(s);
    autoboot_command(s);
    cli_loop();
    panic("No CLI available");
}

env_set:设置环境变量,两个参数分别为name和value

cli_init:用于初始化hash shell的一些变量

run_preboot_environment_command:执行预定义的环境变量的命令

bootdelay_process:加载延时处理,一般用于Uboot启动后,有几秒的倒计时,用于进入命令行模式。

cli_loop:命令行模式,主要作用于Uboot的命令行交互。

bootdelay_process

const char *bootdelay_process(void)
{
    char *s;
    int bootdelay;
    bootcount_inc();
    s = env_get("bootdelay");                               //先判断是否有bootdelay环境变量,如果没有,就使用menuconfig中配置的CONFIG_BOOTDELAY时间
    bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
    if (IS_ENABLED(CONFIG_OF_CONTROL))                      //是否使用设备树进行配置
        bootdelay = fdtdec_get_config_int(gd->fdt_blob, "bootdelay",
                          bootdelay);
    debug("### main_loop entered: bootdelay=%d\n\n", bootdelay);
    if (IS_ENABLED(CONFIG_AUTOBOOT_MENU_SHOW))
        bootdelay = menu_show(bootdelay);
    bootretry_init_cmd_timeout();
#ifdef CONFIG_POST
    if (gd->flags & GD_FLG_POSTFAIL) {
        s = env_get("failbootcmd");
    } else
#endif /* CONFIG_POST */
    if (bootcount_error())
        s = env_get("altbootcmd");
    else
        s = env_get("bootcmd");                             //获取bootcmd环境变量,用于后续的命令执行
    if (IS_ENABLED(CONFIG_OF_CONTROL))
        process_fdt_options(gd->fdt_blob);
    stored_bootdelay = bootdelay;
    return s;
}

autoboot_command

void autoboot_command(const char *s)
{
    debug("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
    if (stored_bootdelay != -1 && s && !abortboot(stored_bootdelay)) {
        bool lock;
        int prev;
        lock = IS_ENABLED(CONFIG_AUTOBOOT_KEYED) &&
            !IS_ENABLED(CONFIG_AUTOBOOT_KEYED_CTRLC);
        if (lock)
            prev = disable_ctrlc(1); /* disable Ctrl-C checking */
        run_command_list(s, -1, 0);
        if (lock)
            disable_ctrlc(prev);    /* restore Ctrl-C checking */
    }
    if (IS_ENABLED(CONFIG_USE_AUTOBOOT_MENUKEY) &&
        menukey == AUTOBOOT_MENUKEY) {
        s = env_get("menucmd");
        if (s)
            run_command_list(s, -1, 0);
    }
}

我们看一下判断条件stored_bootdelay != -1 && s && !abortboot(stored_bootdelay

  • stored_bootdelay:为环境变量的值,或者menuconfig设置的值
  • s:为环境变量bootcmd的值,为后续运行的指令
  • abortboot(stored_bootdelay):主要用于判断是否有按键按下。如果按下,则不执行bootcmd命令,进入cli_loop命令行模式;如果不按下,则执行bootcmd命令,跳转到加载Linux启动。

cli_loop

void cli_loop(void)
{
    bootstage_mark(BOOTSTAGE_ID_ENTER_CLI_LOOP);
#ifdef CONFIG_HUSH_PARSER
    parse_file_outer();
    /* This point is never reached */
    for (;;);                   //死循环
#elif defined(CONFIG_CMDLINE)
    cli_simple_loop();
#else
    printf("## U-Boot command line is disabled. Please enable CONFIG_CMDLINE\n");
#endif /*CONFIG_HUSH_PARSER*/
}

如上代码,程序只执行parse_file_outer来处理用户的输入、输出信息。

最后付一个关于main_loop()较为丰富的函数,去掉了宏定义控制的代码

void main_loop (void)
{
static char lastcommand[CFG_CBSIZE] = {
 0, };
int len;
int rc = 1;
int flag;
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) //是否有bootdelay
char *s;
int bootdelay;
#endif
#ifdef CONFIG_BOOTCOUNT_LIMIT //启动次数的限制
unsigned long bootcount = 0;
unsigned long bootlimit = 0;
char *bcs;
char bcs_set[16];
#endif /* CONFIG_BOOTCOUNT_LIMIT */
#ifdef CONFIG_BOOTCOUNT_LIMIT
bootcount = bootcount_load();//读取已经启动的次数
bootcount++;
bootcount_store (bootcount);//将启动次数加1再写回去保存起来
sprintf (bcs_set, "%lu", bootcount);
setenv ("bootcount", bcs_set); //设置已经启动的次数到环境变量bootcount
bcs = getenv ("bootlimit");//从环境变量获取启动次数的上限,此时返回的是字符串还需要转换成整数
bootlimit = bcs ? simple_strtoul (bcs, NULL, 10) : 0;
#endif /* CONFIG_BOOTCOUNT_LIMIT */
#ifdef CONFIG_VERSION_VARIABLE //设置ver环境变量,里面保存的是uboot的版本
{
extern char version_string[];
setenv ("ver", version_string); /* set version variable */
}
#endif /* CONFIG_VERSION_VARIABLE */
#ifdef CONFIG_AUTO_COMPLETE //命令的自动补全功能
install_auto_complete();
#endif
#ifdef CONFIG_FASTBOOT//支持fastboot刷机
if (fastboot_preboot())
run_command("fastboot", 0);
#endif
/* 下面就是实现uboot启动延时机制bootdelay的代码 */
#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_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>");
/*abortboot函数是检测在bootdelay时间内是否有人按键:如果有人按键则返回1; 超过bootdelay的时间没有人按键则返回0,if条件满足则启动内核*/
if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
#ifdef CONFIG_AUTOBOOT_KEYED
int prev = disable_ctrlc(1); /* 禁止 ctrl+c 功能 */
#endif
run_command (s, 0); //启动内核
#ifdef CONFIG_AUTOBOOT_KEYED
disable_ctrlc(prev); /* 恢复 ctrl+c 功能 */
#endif
}
#endif /* CONFIG_BOOTDELAY */
/* * 下面是一个死循环,不停的从控制台读取命令解析,直到执行bootm命令去启动内核 */
for (;;) {
len = readline (CFG_PROMPT); //从控制台读取一行指令,存放在console_buffer
flag = 0; /* assume no special flags for now */
if (len > 0)
strcpy (lastcommand, console_buffer);
else if (len == 0)
flag |= CMD_FLAG_REPEAT;
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;
}
}
}
目录
相关文章
|
6月前
|
存储 缓存 物联网
uboot 启动流程详细分析参考
uboot 启动流程详细分析参考
490 1
|
6月前
|
Linux C语言 芯片
uboot启动流程源码分析(一)
uboot启动流程源码分析(一)
76 0
|
6月前
|
Linux C语言 芯片
【系统启动】uboot启动流程源码分析
【系统启动】uboot启动流程源码分析
148 0
|
存储 Linux Shell
uboot启动流程简要版(基于armv7)
uboot启动流程简要版(基于armv7)
1035 0
uboot启动流程简要版(基于armv7)
|
Linux 芯片 内存技术
uboot和linux内核移植流程简述
uboot和linux内核移植流程简述
278 0
|
存储 安全 Java
Android系统启动流程
今天说《Android体系架构》第一篇内容,关于Android系统启动的过程。
205 0
Android系统启动流程
|
Java
深入理解 NioEventLoop启动流程
深入理解 NioEventLoop启动流程
157 0
|
存储 内存技术
u-boot关于启动流程
u-boot关于启动流程
104 0
u-boot关于启动流程
|
Linux 内存技术
U-boot 大体启动流程
U-boot 大体启动流程
SpringMVC源码分析和启动流程
SpringMvc原理和启动流程
4048 0