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 中,函数内容如下:
static int run_main_loop(void)
{
#ifdef CONFIG_SANDBOX
	sandbox_main_loop_init();
#endif
	/* main_loop() can return to retry autoboot, if so just run it again */
	for (;;)
		main_loop();
	return 0;
}

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

2.  main_loop 函数

main_loop 函数定义在 common/main.c 文件 里面。 代码如下:
void main_loop(void)
{
	const char *s;

	bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, "main_loop");

#ifndef CONFIG_SYS_GENERIC_BOARD
	puts("Warning: Your board does not use generic board. Please read\n");
	puts("doc/README.generic-board and take action. Boards not\n");
	puts("upgraded by the late 2014 may break or be removed.\n");
#endif

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

	cli_init();

	run_preboot_environment_command();

#if defined(CONFIG_UPDATE_TFTP)
	update_tftp(0UL, NULL, NULL);
#endif /* CONFIG_UPDATE_TFTP */

	s = bootdelay_process();
	if (cli_process_fdt(&s))
		cli_secure_boot_cmd(s);

	autoboot_command(s);

	cli_loop();
}

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函数如下:
void cli_loop(void)
{
#ifdef CONFIG_SYS_HUSH_PARSER
	parse_file_outer();
	/* This point is never reached */
	for (;;);
#else
	cli_simple_loop();
#endif /*CONFIG_SYS_HUSH_PARSER*/
}

void cli_init(void)
{
#ifdef CONFIG_SYS_HUSH_PARSER
	u_boot_hush_start();
#endif

#if defined(CONFIG_HUSH_INIT_VAR)
	hush_init_var();
#endif
}
在文件 include/configs/mx6_common.h 中有定义宏 CONFIG_SYS_HUSH_PARSER ,而正点原子的 I.MX6ULL 开发板配置头文件 mx6ullevk.h 里面会引用 mx_common.h 这个头文件,因此 , CONFIG_SYS_HUSH_PARSER 有定义。
第 205 行,执行 parse_file_outer函数。
207 行,是死循环,永远不会执行到这里。

函数 parse_file_outer 定义在文件 common/cli_hush.c 中,去掉条件编译内容以后的函数内容
如下:
int parse_file_outer(void)
{
 int rcode;
 struct in_str input;

 setup_file_in_str(&input);
 rcode = parse_stream_outer(&input, FLAG_PARSE_SEMICOLON);
 return rcode;
}

6 行调用函数 setup_file_in_str 初始化变量 input 的成员变量。
7 行调用函数 parse_stream_outer ,这个函数就是 hush shell 的命令解释器,负责接收命 令行输入,然后解析并执行相应的命令,函数 parse_stream_outer 定义在文件 common/cli_hush.c 中,精简版的函数内容如下:
static int parse_stream_outer(struct in_str *inp, int flag)
{
......

do {
......
    if (rcode != 1 && ctx.old_flag == 0) {
    {
        run_list(ctx.list_head);
    }
......

} while (rcode != -1 && !(flag & FLAG_EXIT_FROM_LOOP) &&
 (inp->peek != static_peek || b_peek(inp)));
......
}

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

三.  总结

函数调用关系如下:

uboot启动流程-run_main_loop 到 cmd_process处理说明一_第1张图片

你可能感兴趣的:(uboot,系统移植篇,arm开发,linux)