bootz启动 Linux内核过程中涉及的 do_bootm_states 函数

一.  bootz启动Linux

uboot 启动Linux内核使用bootz命令。当然还有其它的启动命令,例如,bootm命令等等。

本文只分析 bootz命令启动 Linux内核的过程中涉及的几个重要函数。具体分析  do_bootm_states 函数执行过程。

本文继上一篇文章,地址如下:

bootz启动 Linux内核过程中涉及的 bootz_start 函数-优快云博客

二.  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;
}

<think>好的,我现在需要详细解释U-Boot的启动流程。首先,我需要回忆一下U-Boot的基本知识。U-Boot是一个开源的引导加载程序,主要用于嵌入式系统。它的启动流程涉及到硬件初始化、环境变量设置、加载操作系统等步骤。用户可能希望了解从加电到加载内核的整个过程,包括各个阶段的具体任务。 首先,我得确认不同架构的启动流程可能有所不同,比如ARM和PowerPC可能有差异。用户没有指定具体架构,所以我需要保持通用性,或者假设以常见的ARM为例。另外,可能需要分阶段描述,比如分为BL1、BL2等阶段,或者是U-Boot自身的启动过程。 接下来,我需要回忆U-Boot的启动阶段。通常,启动流程可以分为几个阶段:SoC内部的ROM代码执行,SPL(Secondary Program Loader),然后是U-Boot主体,最后加载操作系统。每个阶段的具体任务是什么?比如,ROM代码负责初始化最基础的硬件,SPL进行内存初始化,然后加载U-Boot到内存中执行。 然后,可能需要详细说明每个阶段的具体步骤。例如,在SPL阶段,会初始化时钟、内存控制器,设置堆栈,然后加载U-Boot到DDR内存中。U-Boot主体启动后,会进行更复杂的外设初始化,读取环境变量,根据配置加载内核映像,传递参数,最后跳转到内核执行。 需要注意关键点,比如环境变量的存储位置(如NOR Flash、EEPROM)、如何读取,以及启动命令的执行流程,比如bootcmd的设置。此外,设备树(DTB)的加载过程也很重要,特别是在ARM架构中,内核需要设备树来识别硬件配置。 还要考虑可能的错误处理,比如U-Boot如何应对启动失败,比如自动恢复或者进入命令行模式。另外,不同板级支持包(BSP)可能有不同的配置,但核心流程应该是一致的。 需要验证信息的准确性,比如SPL的作用是否仅限于初始化内存和加载U-Boot,是否有例外情况。另外,启动延迟、中断处理、多阶段引导的安全性措施(如签名验证)是否需要提及?用户的问题是关于启动流程的详解,因此可能需要覆盖这些高级主题,但保持主次分明。 最后,结构安排要清晰,可能按顺序分阶段讲解,每个阶段的职责和关键步骤,结合代码示例或流程图是否有助于理解?但用户要求的是文本解释,所以需要用文字描述清楚。同时,注意使用中文术语,比如“设备树”、“环境变量”等,避免术语混淆。 总结思考步骤:确定架构(假设ARM),分阶段描述(ROM→SPL→U-Boot→内核),各阶段任务,关键初始化步骤,环境变量处理,设备树加载,启动命令执行,错误处理。确保覆盖从硬件初始化到内核跳转的全过程,并指出不同配置的可能差异。</think>### U-Boot启动流程详解(以ARM架构为例) #### 一、硬件启动阶段 1. **SoC ROM代码执行**(BL0) - 上电复位后,CPU从固化在芯片内部的ROM代码开始执行 - 主要任务: - 设置初始时钟频率 - 初始化基本存储接口(如BootROM支持的启动介质:NOR Flash/SD卡/eMMC) - 加载SPL(Secondary Program Loader)到SRAM - 验证SPL的数字签名(安全启动场景) - 典型代码片段: ```armasm ldr sp, =0xFFFF0000 ; 设置临时堆栈 bl lowlevel_init ; 初始化时钟和DDR控制器 ldr r0, =SPL_START_ADDR ; 加载SPL到0x80000000 bl load_image_from_mmc bx r0 ; 跳转到SPL ``` #### 二、SPL阶段(BL1) 2. **SPL初始化流程** - 执行位置:SRAM(通常64-256KB) - 核心任务: - 初始化DDR内存控制器 - 设置完整时钟树 - 加载完整U-Boot到DDR - 可选安全校验(如HASH验证) - 关键数据结构: ```c struct spl_image_info { u8 os; /* 操作系统类型(IH_OS_U_BOOT)*/ u32 load_addr; /* 加载地址(如0x87800000) */ size_t size; }; ``` - 典型执行流程: ```c board_init_f() → 初始化基础外设 timer_init() → 设置系统定时器 spl_mmc_load() → 从存储介质加载U-Boot jump_to_image_no_args() → 跳转到U-Boot ``` #### 三、U-Boot主体阶段(BL2) 3. **U-Boot主要初始化流程** - 执行位置:DDR内存(地址如0x87800000) - 阶段划分: - **板级初始化前段**(`board_init_f`) ```c initf_malloc() // 初始化早期内存分配器 arch_cpu_init() // CPU架构相关初始化 board_early_init() // 板级早期GPIO配置 dram_init() // 检测内存容量 ``` - **重定位阶段** ```armasm adr r0, _start ; 获取当前地址 ldr r1, =CONFIG_SYS_TEXT_BASE cmp r0, r1 beq relocated ; 判断是否需要重定位 bl copy_uboot_to_ram relocated: ``` - **板级初始化后段**(`board_init_r`) ```c env_init() // 初始化环境变量存储 stdio_init() // 初始化控制台 initr_net() // 网络设备初始化 run_main_loop() // 进入主循环 ``` 4. **环境变量处理** - 存储位置检测流程: ``` 1. 检查`CONFIG_ENV_IS_IN_MMC` → 查找FAT分区的uboot.env 2. 检查`CONFIG_ENV_IS_IN_SPI_FLASH` → 直接读取SPI Flash偏移量 3. 使用默认环境(CONFIG_USE_DEFAULT_ENV_FILE) ``` - 变量优先级: ```bash 默认环境 < 存储介质环境 < 运行时修改的环境 ``` #### 四、内核加载阶段 5. **bootcmd执行流程** - 典型启动命令解析: ```bash # 常见bootcmd配置 setenv bootcmd 'mmc dev 0; \ fatload mmc 0:1 ${kernel_addr_r} zImage; \ fatload mmc 0:1 ${fdt_addr_r} dtb; \ bootz ${kernel_addr_r} - ${fdt_addr_r}' ``` - 内核加载关键函数调用链: ``` do_bootz() → bootz_start() → image_setup_libfdt() → do_bootm_states() ``` 6. **设备树处理流程** - 设备树修改过程: ```c int ft_system_setup(void *blob, bd_t *bd) { /* 动态添加板级配置 */ fdt_setprop(blob, node, "clock-frequency", &clk, sizeof(clk)); return 0; } ``` - 内存节点更新示例: ```dts / { memory@80000000 { device_type = "memory"; reg = <0x80000000 0x20000000>; // 512MB }; }; ``` #### 五、异常处理机制 7. **启动失败处理** - 自动恢复流程: ``` 1. 检测启动计数器(bootcount) 2. 超过最大失败次数(如3次)后: - 清除环境变量区 - 从备份分区恢复 - 进入紧急下载模式(如USB DFU) ``` - 关键代码: ```c if (bootcount_get() > MAX_BOOTCOUNT) { env_set_default("启动失败,恢复出厂设置", 0); do_reset(NULL, 0, 0, NULL); } ``` #### 六、高级启动配置 8. **多重启动支持** - 典型boot_targets配置: ```bash boot_targets = mmc0 usb pxe dhcp ``` - 优先级判断逻辑: ```c for (i = 0; i < ARRAY_SIZE(boot_targets); i++) { if (device_available(boot_targets[i])) { boot_device = boot_targets[i]; break; } } ``` 9. **安全启动实现** - 签名验证流程: ``` 1. 加载内核镜像和签名(如PKCS7格式) 2. 使用内置公钥验证签名 3. 哈希校验镜像完整性 ``` - 关键配置选项: ```makefile CONFIG_RSA_VERIFY=y CONFIG_FIT_SIGNATURE=y CONFIG_OF_CONTROL=y ``` **启动流程全貌图示**: ``` [ROM Code] → [SPL] → [U-Boot] → [设备树处理] → [内核加载] → [启动OS] │ │ │ │ └─> 基础时钟 环境变量加载 启动参数传递 存储接口初始化 外设驱动初始化 initramfs处理 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值