• uboot启动流程-run_main_loop 到 cmd_process处理说明一


    一.   uboot启动

    uboot命令模式:uboot 启动以后会进入 3 秒倒计时,如果在 3 秒倒计时结束之前按下按下回车键,那么就会进入 uboot 的命令模式。
    如果在 uboot 倒计时结束以后都没有按下回车键,就会自动启动 Linux 核 , 这 个 功 能 就 是 由 run_main_loop 函 数 来 完 成 的 。

    二.  run_main_loop函数 到 cmd_process处理

    1.  run_main_loop函数

    run_main_loop 函 数 定 义 在 文 件 common/board_r.c 中,函数内容如下:
    1. static int run_main_loop(void)
    2. {
    3. #ifdef CONFIG_SANDBOX
    4. sandbox_main_loop_init();
    5. #endif
    6. /* main_loop() can return to retry autoboot, if so just run it again */
    7. for (;;)
    8. main_loop();
    9. return 0;
    10. }

    " for (;;) " " while(1) " 功能一样,死循环里面就一个 main_loop 函数。

    2.  main_loop 函数

    main_loop 函数定义在 common/main.c 文件 里面。 代码如下:
    1. void main_loop(void)
    2. {
    3. const char *s;
    4. bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, "main_loop");
    5. #ifndef CONFIG_SYS_GENERIC_BOARD
    6. puts("Warning: Your board does not use generic board. Please read\n");
    7. puts("doc/README.generic-board and take action. Boards not\n");
    8. puts("upgraded by the late 2014 may break or be removed.\n");
    9. #endif
    10. #ifdef CONFIG_VERSION_VARIABLE
    11. setenv("ver", version_string); /* set version variable */
    12. #endif /* CONFIG_VERSION_VARIABLE */
    13. cli_init();
    14. run_preboot_environment_command();
    15. #if defined(CONFIG_UPDATE_TFTP)
    16. update_tftp(0UL, NULL, NULL);
    17. #endif /* CONFIG_UPDATE_TFTP */
    18. s = bootdelay_process();
    19. if (cli_process_fdt(&s))
    20. cli_secure_boot_cmd(s);
    21. autoboot_command(s);
    22. cli_loop();
    23. }

    main_loop 函数中:

    5 行,调用 bootstage_mark_name 函数,打印出启动进度。

    13 行,如果定义了宏 CONFIG_VERSION_VARIABLE 就会执行函数 setenv ,设置
    变量 ver 的值为 version_string ,也就是设置版本号环境变量。 version_string 定义在文件
    cmd/version.c 中,定义如下:
    const char __weak version_string[] = U_BOOT_VERSION_STRING;
    经过搜索,一系列分析可知,Uboot打印如下:

    U-Boot 2016.03 (Jul 07 2023 - 17:11:27 +0800)

    17 行, cli_init 函数,跟命令初始化有关,初始化 hush shell 相关的变量。
    19 行, run_preboot_environment_command 函数,获取环境变量 perboot 的内容, perboot 是一些预启动命令,一般不使用这个环境变量。
    25 行, bootdelay_process 函数,此函数会读取环境变量 bootdelay bootcmd 的内容, 然后将 bootdelay 的值赋值给全局变量 stored_bootdelay ,返回值为环境变量 bootcmd 的值。
    26 行, 如果定义了 CONFIG_OF_CONTROL 的话函数 cli_process_fdt 就会实现,如果 没有定义 CONFIG_OF_CONTROL 的话函数 cli_process_fdt 直接返回一个 false 在本 uboot 中没有定义 CONFIG_OF_CONTROL ,因此 cli_process_fdt 函数返回值为 false

    29 行, autoboot_command 函数,此函数就是检查倒计时是否结束?倒计时结束之前有 没有被打断?此函数定义在文件 common/autoboot.c

    74 行的 cli_loop 函数,这个就是命令处理函数。如果倒计时结束之前按下按键, 那么就会执行 cli_loop 函数,负责接收好处理输入的命令。

    cli_loop 函数是 uboot 的命令行处理函数,我们在 uboot 中输入各种命令,进行各种操作就
    是有 cli_loop 来处理的,此函数定义在文件 common/cli.c 中。cli_loop函数如下:
    1. void cli_loop(void)
    2. {
    3. #ifdef CONFIG_SYS_HUSH_PARSER
    4. parse_file_outer();
    5. /* This point is never reached */
    6. for (;;);
    7. #else
    8. cli_simple_loop();
    9. #endif /*CONFIG_SYS_HUSH_PARSER*/
    10. }
    11. void cli_init(void)
    12. {
    13. #ifdef CONFIG_SYS_HUSH_PARSER
    14. u_boot_hush_start();
    15. #endif
    16. #if defined(CONFIG_HUSH_INIT_VAR)
    17. hush_init_var();
    18. #endif
    19. }
    在文件 include/configs/mx6_common.h 中有定义宏 CONFIG_SYS_HUSH_PARSER ,而正点原子的 I.MX6ULL 开发板配置头文件 mx6ullevk.h 里面会引用 mx_common.h 这个头文件,因此, CONFIG_SYS_HUSH_PARSER 有定义。
    第 4 行,执行 parse_file_outer函数。
    6 行,是死循环,永远不会执行到这里。

    函数 parse_file_outer 定义在文件 common/cli_hush.c 中,去掉条件编译内容以后的函数内容
    如下:
    1. int parse_file_outer(void)
    2. {
    3. int rcode;
    4. struct in_str input;
    5. setup_file_in_str(&input);
    6. rcode = parse_stream_outer(&input, FLAG_PARSE_SEMICOLON);
    7. return rcode;
    8. }

    6 行,调用函数 setup_file_in_str 初始化变量 input 的成员变量。
    7 行,调用函数 parse_stream_outer 函数,这个函数就是 hush shell 的命令解释器,负责接收命 令行输入,然后解析并执行相应的命令,函数 parse_stream_outer 定义在文件 common/cli_hush.c 中,精简版的函数内容如下:
    1. static int parse_stream_outer(struct in_str *inp, int flag)
    2. {
    3. ......
    4. do {
    5. ......
    6. if (rcode != 1 && ctx.old_flag == 0) {
    7. {
    8. run_list(ctx.list_head);
    9. }
    10. ......
    11. } while (rcode != -1 && !(flag & FLAG_EXIT_FROM_LOOP) &&
    12. (inp->peek != static_peek || b_peek(inp)));
    13. ......
    14. }

    7~21 行中的 do-while 循环就是处理输入命令的。
    9 行调用函数 parse_stream 进行命令解析。
    14 行调用调用 run_list 函数来执行解析出来的命令。
    函数 run_list 会经过一系列的函数调用,最终通过调用 cmd_process 函数来处理命令。

    三.  总结

    函数调用关系如下:

  • 相关阅读:
    分析 java.util.Hashtable 源码
    【Python爬虫原理与基本请求库urllib详解】
    30分钟学会如何使用Shiro
    洛谷P2257 莫比乌斯反演+线性筛
    1万属性,100亿数据,每秒10万吞吐,架构如何设计?
    Linux下查找文件(日志)中的关键字
    R软件和扩展包的升级及R语言数据对象
    【花雕动手做】有趣好玩的音乐可视化系列小项目(15)--横排LED方管灯
    力扣:第81场双周赛
    SQL语句常用英语词汇
  • 原文地址:https://blog.csdn.net/wojiaxiaohuang2014/article/details/133706883