一. bootz启动Linux
uboot 启动Linux内核使用bootz命令。当然还有其它的启动命令,例如,bootm命令等等。
本文只分析 bootz命令启动 Linux内核的过程中涉及的几个重要函数。具体分析 do_bootm_states 函数执行过程。
本文继上一篇文章,地址如下:
bootz启动 Linux内核过程中涉及的 bootz_start 函数-CSDN博客
二. bootz 启动 Linux 内核涉及函数
bootz 命令的执行函数为 do_bootz函数。而 do_bootz函数主要调用如下函数:
bootz_start 函数,bootm_disable_interrupts 函数,设置 images.os.os ,do_bootm_states 函数。
1. do_bootm_states 函数
do_bootz函数
最 后 调 用 的 就 是 do_bootm_states函 数,而且 在 bootz_start
中 也 调 用 了
do_bootm_states
函数 ,看 来
do_bootm_states
函数 还 是很重要的函数。此函 数 定 义 在 文件
common/bootm.c
中。
在
do_bootz
函数中,会用到
BOOTM_STATE_OS_PREP 、BOOTM_STATE_OS_FAKE_GO 和
BOOTM_STATE_OS_GO
这三个
BOOT
状态。
bootz_start
函数中会用到
BOOTM_STATE_START
一个
BOOT
状态。为了精简代码,方便分析。
do_bootm_states
进行精简,只留下下面这
4
个
BOOT
状态对应:
BOOTM_STATE_OS_PREP
BOOTM_STATE_OS_FAKE_GO
BOOTM_STATE_OS_GO
BOOTM_STATE_START
四种 BOOT 状态对应的部分代码如下:
int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
int states, bootm_headers_t *images, int boot_progress)
{
boot_os_fn *boot_fn;
ulong iflag = 0;
int ret = 0, need_boot_fn;
images->state |= states;
............
/* From now on, we need the OS boot function */
if (ret)
return ret;
boot_fn = bootm_os_get_boot_func(images->os.os);
need_boot_fn = states & (BOOTM_STATE_OS_CMDLINE |
BOOTM_STATE_OS_BD_T | BOOTM_STATE_OS_PREP |
BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO);
if (boot_fn == NULL && need_boot_fn) {
if (iflag)
enable_interrupts();
printf("ERROR: booting os '%s' (%d) is not supported\n",
genimg_get_os_name(images->os.os), images->os.os);
bootstage_error(BOOTSTAGE_ID_CHECK_BOOT_OS);
return 1;
}
............
if (!ret && (states & BOOTM_STATE_OS_PREP))
ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, images);
#ifdef CONFIG_TRACE
/* Pretend to run the OS, then run a user command */
if (!ret && (states & BOOTM_STATE_OS_FAKE_GO)) {
char *cmd_list = getenv("fakegocmd");
ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_FAKE_GO,
images, boot_fn);
if (!ret && cmd_list)
ret = run_command_list(cmd_list, -1, flag);
}
#endif
/* Check for unsupported subcommand. */
if (ret) {
puts("subcommand not supported\n");
return ret;
}
/* Now run the OS! We hope this do not return */
if (!ret && (states & BOOTM_STATE_OS_GO))
ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_GO,
images, boot_fn);
.............
return ret;
}
第15行,在BOOT状态时即 BOOTM_STATE_START
阶段,
bootz_start
会执行这一段代码,这里调用
bootm_start 函数。
第
20
行非常重要!通过函数
bootm_os_get_boot_func
来查找系统启动函数,参数
images->os.os
就是系统类型,根据这
个系统类型来选择对应的启动函数,在
do_bootz
中设置
images.os.os= IH_OS_LINUX
。函数返
回值就是找到的系统启动函数,这里找到的
Linux
系统启动函数为
do_bootm_linux
,
boot_fn=do_bootm_linux
,后面执行
boot_fn
函数的地方实际上是执行的
do_bootm_linux
函数。
第
26
行,处理
BOOTM_STATE_OS_PREP
状态,调用函数
do_bootm_linux
,
do_bootm_linux
函数也是调用
boot_prep_linux
来完成具体的处理过程。
boot_prep_linux
主要用于处理环境变量
bootargs
,
bootargs
保存着传递给
Linux kernel
的参数。
第
34~37
行,是处理
BOOTM_STATE_OS_FAKE_GO
状态的,因为我们没使能
TRACE
功能,因此,宏
CONFIG_TRACE
也就没有定义,所以这段程序不会编译。
第 49 行,调用 boot_selected_os函数启动 Linux
内核,此函数第
4
个参数为
Linux
系统镜
像头,第
5
个参数就是
Linux
系统启动
do_bootm_linux 函数
。
boot_selected_os
函数定义在文件common/bootm_os.c
中,函数内容如下:
int boot_selected_os(int argc, char * const argv[], int state, bootm_headers_t *images, boot_os_fn *boot_fn)
{
arch_preboot_os();
boot_fn(state, argc, argv, images);
/* Stand-alone may return when 'autostart' is 'no' */
if (images->os.type == IH_TYPE_STANDALONE ||
state == BOOTM_STATE_OS_FAKE_GO) /* We expect to return */
return 0;
bootstage_error(BOOTSTAGE_ID_BOOT_OS_RETURNED);
#ifdef DEBUG
puts("\n## Control returned to monitor - resetting...\n");
#endif
return BOOTM_ERR_RESET;
}
第
4
行,调用
boot_fn
函数,也就是
do_bootm_linux
函数来启动
Linux
内核。
do_bootm_linux 函数简化代码如下,这里只列出此处会执行到代码:
int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
int states, bootm_headers_t *images, int boot_progress)
{
boot_os_fn *boot_fn;
ulong iflag = 0;
int ret = 0, need_boot_fn;
images->state |= states;
.............
if (!ret && (states & BOOTM_STATE_OS_GO))
ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_GO,
images, boot_fn);
.............
return ret;
}