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

本文详细介绍了U-Boot启动过程中的run_main_loop函数和main_loop函数的作用,包括倒计时、版本变量设置、命令处理以及hushshell的运用。同时概述了uboot启动时的命令模式和内核自动启动机制。

一.   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 
/* * (C) Copyright 2000 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * * SPDX-License-Identifier: GPL-2.0+ */ /* #define DEBUG */ #include <common.h> #include <autoboot.h> #include <cli.h> #include <version.h> #include <SsRecovery.h> #if defined(CONFIG_XZ) && defined(FACTORY_BOOT_COMPILE) #include <xz/xz.h> #include <xz/xz_config.h> #include <xz/xz_lzma2.h> #include <xz/xz_stream.h> #endif #ifdef FACTORY_BOOT_COMPILE #define BG_GREEN_FONT_WHITE "\033[42;37m" #define COLOR_NONE "\033[0m" #endif DECLARE_GLOBAL_DATA_PTR; /* * Board-specific Platform code can reimplement show_boot_progress () if needed */ __weak void show_boot_progress(int val) {} static void modem_init(void) { #ifdef CONFIG_MODEM_SUPPORT debug("DEBUG: main_loop: gd->do_mdm_init=%lu\n", gd->do_mdm_init); if (gd->do_mdm_init) { char *str = getenv("mdm_cmd"); setenv("preboot", str); /* set or delete definition */ mdm_init(); /* wait for modem connection */ } #endif /* CONFIG_MODEM_SUPPORT */ } static void run_preboot_environment_command(void) { #ifdef CONFIG_PREBOOT char *p; p = getenv("preboot"); if (p != NULL) { # ifdef CONFIG_AUTOBOOT_KEYED int prev = disable_ctrlc(1); /* disable Control C checking */ # endif run_command_list(p, -1, 0); # ifdef CONFIG_AUTOBOOT_KEYED disable_ctrlc(prev); /* restore Control C checking */ # endif } #endif /* CONFIG_PREBOOT */ } #if defined(FACTORY_BOOT_COMPILE) && defined(FACTORY_BOOT_ONLY) /* 当只使用factory_boot时,要将main_loop()中uboot的引导功能编进factory_boot */ #undef FACTORY_BOOT_COMPILE #define U_BOOT_COMPILE #endif /* We come here after U-Boot is initialised and ready to process commands */ void main_loop(void) { #if defined(U_BOOT_COMPILE) || defined(DBG_U_BOOT_COMPILE) const char *s; #endif int ret = 0; 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 #if defined(CONFIG_TP_SERIAL_FORBIDDEN) && defined(U_BOOT_COMPILE) printf("SERIAL FORBIDDEN!\n"); u16 *p; p = 0x1f203d4c; *p = 0x3010; #endif modem_init(); #ifdef CONFIG_VERSION_VARIABLE setenv("ver", version_string); /* set version variable */ #endif /* CONFIG_VERSION_VARIABLE */ cli_init(); run_preboot_environment_command(); #ifdef CONFIG_AUTO_UPGRADE_SD run_command("sdupgrade", 0); #endif #ifdef CONFIG_SSTAR_AUTORUN_DSTAR run_command("sdstar", 0); #endif #if defined(CONFIG_UPDATE_TFTP) update_tftp(0UL); #endif /* CONFIG_UPDATE_TFTP */ #if defined(CONFIG_CMD_DFU) extern int update_dfu(void); update_dfu(); #endif /* CONFIG_CMD_DFU */ #ifdef CONFIG_MS_EMMC_RECOVERY RecoveryCheck(); #endif #if defined(U_BOOT_COMPILE) || defined(DBG_U_BOOT_COMPILE) s = bootdelay_process(); if (cli_process_fdt(&s)) cli_secure_boot_cmd(s); #ifdef CONFIG_TP_TAPO_SPMINIOS ret = validateFirmwareWithRecover(); if (!ret) { setenv("bootargs", CONFIG_SP_BOOTARGS); } else { setenv("bootargs", CONFIG_SPMINIOS_BOOTARGS); } #endif #ifdef CONFIG_TAPO_NAND_UPGRADE ret = validateFirmwareWithUpgrade(); #endif autoboot_command(s); #endif #ifdef FACTORY_BOOT_COMPILE bootdelay_process(); if (disable_boot()) { printf(BG_GREEN_FONT_WHITE"abort, init eth"COLOR_NONE"...\n"); run_command_list("estart", -1, 0); goto loop; } #ifdef CONFIG_TAPO_NAND_UPGRADE ret = processUboot(); #endif { printf("Firmware check pass!\n"); /* CONFIG_LOADADDR is 0x21000000, the addr for load normal boot image if ISP_IN_FLASH, normal boot image is stored in 0x40000 of flash; or it is stored in 0x30000 of flash. */ //ssc377, not use CONFIG_MS_SPINAND #ifdef CONFIG_MS_NAND_ONEBIN #ifdef BOOTLOADER_OFFSET char cmd_buf[257] = {0}; snprintf(cmd_buf, 256, "nand read.e 0x21000000 0x%0x 0x40000", BOOTLOADER_OFFSET); run_command_list(cmd_buf, -1, 0); #else run_command_list("nand read.e 0x21000000 0x600000 0x40000", -1, 0); #endif #else #ifdef ISP_IN_FLASH printf("IMG_RADIO_LEN defined, RADIO_LEN = 0x%0x\n", RADIO_LEN); char cmd_buf[128] = {0}; snprintf(cmd_buf, 512, "sf probe 0;sf read 0x21000000 0x%0x 0x%0x", BOOTLOADER_OFFSET, BOOTLOADER_LEN); run_command_list(cmd_buf, -1, 0); #else run_command_list("sf probe 0;sf read 0x21000000 0x30000 0x10000", -1, 0); #endif #endif struct xz_buf b; struct xz_dec *s; xz_crc32_init(); /* * Support up to 64 MiB dictionary. The actually needed memory * is allocated once the headers have been parsed. */ s = xz_dec_init(XZ_SINGLE, 16 * 1024); if (s == NULL) { printf("xz_dec_init ERROR!!\n"); } b.in = (unsigned char *)(CONFIG_LOADADDR + NORMAL_BOOT_IMAGE_OFFSET); // ignore 40 bytes image header b.in_pos = 0; b.in_size = NORMAL_BOOT_IMAGE_SIZE; b.out = (unsigned char *)(NORMAL_BOOT_LOADADDR); b.out_pos = 0; b.out_size = NORMAL_BOOT_MAX_SIZE; printf("XZ params: in_addr 0x%x, in_size 0x%x, out_addr 0x%x, out_size 0x%x\n", (unsigned int)b.in, (unsigned int)b.in_size, (unsigned int)b.out, (unsigned int)b.out_size); ret = xz_dec_run(s, &b); printf("XZ: uncompress ret %d, size = %d\n", ret, b.out_size); xz_dec_end(s); /*?a??ì?×aubootuboot???ˉòì3£?êìa£??óé?cache2ù×÷£??′ê1cache?′?aò2??ó°?ì*/ flush_dcache_all(); invalidate_icache_all(); /* NORMAL_BOOT_LOADADDR is 0x220A0000, the addr for running normal boot*/ char run_buf[128] = {0}; snprintf(run_buf, 128, "go 0x%0x", (unsigned char *)NORMAL_BOOT_LOADADDR); run_command(run_buf, 0); } loop: #endif cli_loop(); }
最新发布
10-08
这段代码是个U-Boot(Universal Boot Loader)的主循环函数`main_loop()`,主要用于嵌入式系统的启动过程。代码中包含了多种条件编译选项,以支持不同平台和功能。以下是代码的主要功能和逻辑分析: --- ### **代码功能分析** 1. **初始化阶段** - 调用`modem_init()`函数,用于初始化调制解调器(如果启用了`CONFIG_MODEM_SUPPORT`)。 - 调用`run_preboot_environment_command()`函数,运行预启动环境命令(如果启用了`CONFIG_PREBOOT`)。 2. **命令行接口(CLI)初始化** - 调用`cli_init()`函数,初始化命令行接口。 3. **自动升级功能** - 如果启用了`CONFIG_AUTO_UPGRADE_SD`,运行`sdupgrade`命令。 - 如果启用了`CONFIG_SSTAR_AUTORUN_DSTAR`,运行`sdstar`命令。 - 如果启用了`CONFIG_UPDATE_TFTP`,调用`update_tftp()`函数进行TFTP升级。 - 如果启用了`CONFIG_CMD_DFU`,调用`update_dfu()`函数进行DFU(Device Firmware Upgrade)升级。 - 如果启用了`CONFIG_MS_EMMC_RECOVERY`,调用`RecoveryCheck()`函数检查恢复模式。 4. **引导阶段** - 调用`bootdelay_process()`函数,处理启动延迟。 - 调用`cli_process_fdt()`函数,处理设备树(FDT)。 - 调用`cli_secure_boot_cmd()`函数,执行安全启动命令。 - 如果启用了`CONFIG_TP_TAPO_SPMINIOS`,调用`validateFirmwareWithRecover()`函数验证固件并设置启动参数。 - 如果启用了`CONFIG_TAPO_NAND_UPGRADE`,调用`validateFirmwareWithUpgrade()`函数验证固件并进行NAND升级。 - 最后调用`autoboot_command()`函数执行自动启动命令。 5. **工厂启动模式(Factory Boot)** - 如果启用了`FACTORY_BOOT_COMPILE`,进入工厂启动模式。 - 调用`disable_boot()`函数判断是否需要中止启动- 如果中止启动,打印提示信息并运行`estart`命令。 - 如果启用了`CONFIG_TAPO_NAND_UPGRADE`,调用`processUboot()`函数处理U-Boot。 - 从NAND或SPI Flash中读取正常启动镜像。 - 使用XZ解压算法解压镜像。 - 清除缓存并跳转到解压后的镜像地址执行。 6. **命令行循环** - 调用`cli_loop()`函数,进入命令行循环,等待用户输入命令。 --- ### **关键函数解析** - `modem_init()`:初始化调制解调器,等待连接。 - `run_preboot_environment_command()`:运行预启动命令。 - `bootdelay_process()`:处理启动延迟,允许用户中断启动过程。 - `cli_process_fdt()`:处理设备树文件(FDT)。 - `autoboot_command()`:执行自动启动命令,通常是启动Linux内核。 - `xz_dec_init()`和`xz_dec_run()`:用于解压XZ格式的镜像。 - `flush_dcache_all()`和`invalidate_icache_all()`:清除缓存,确保解压后的代码可以正确执行。 - `go`命令:跳转到指定地址执行代码。 --- ### **代码特点** - **条件编译**:通过`#ifdef`和`#if defined()`等宏定义,支持多种平台和功能。 - **模块化设计**:代码结构清晰,各功能模块独立,便于维护和扩展。 - **安全性**:支持安全启动(Secure Boot)和固件验证。 - **灵活性**:支持多种启动方式(如TFTP、DFU、NAND、SPI Flash等)。 --- ### **示例代码** ```c void main_loop(void) { // 初始化调制解调器 modem_init(); // 运行预启动命令 run_preboot_environment_command(); // 初始化CLI cli_init(); // 自动升级功能 #ifdef CONFIG_AUTO_UPGRADE_SD run_command("sdupgrade", 0); #endif // 处理设备树和启动参数 const char *s = bootdelay_process(); if (cli_process_fdt(&s)) cli_secure_boot_cmd(s); // 自动启动命令 autoboot_command(s); // 进入命令行循环 cli_loop(); } ``` --- ### **总结** 这段代码是个典型的嵌入式系统启动代码,主要功能包括初始化硬件、处理启动参数、支持多种升级方式、解压并启动内核等。通过条件编译和模块化设计,代码具有良好的可移植性和扩展性。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值