uboot中正常启动模式和recovery启动模式切换的实现

本文详细介绍了嵌入式系统中的Recovery模式及其启动流程。重点讲解了通过U-Boot实现Recovery模式的方法,包括按键检测、环境参数设置等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一个嵌入式系统,一般情况下都是正常启动模式,如果需要系统升级,或系统恢复出厂状态,就会需要用到recovery启动模式,它会从另外备份的kernel和rootfs启动。

在uboot中, check_recovery_mode()这个函数,就是用来实现这个功能的:

这个函数在lib_arm/board.c 的start_armboot (void)中被调用:

void start_armboot (void)
{
        init_fnc_t **init_fnc_ptr;
        char *s;
#if defined(CONFIG_VFD) || defined(CONFIG_LCD)
        unsigned long addr;
#endif
...
#ifdef CONFIG_ANDROID_RECOVERY
        check_recovery_mode();
#endif
...
        }

        /* NOTREACHED - no way out of command loop except booting */
}
只要定义了 CONFIG_ANDROID_RECOVERY, 这个函数就会被调用。

该函数定义如下:

/* export to lib_arm/board.c */
void check_recovery_mode(void)
{
        if (check_key_pressing())
                setup_recovery_env();
#if 0
        else if (check_recovery_cmd_file()) {
                puts("Recovery command file founded!\n");
                setup_recovery_env();
        }
#endif
}
check_key_pressing()就是进入recovery模式的按键检查,若对应的按键被按下,就进入recovery模式,如果没有就正常启动。

#ifdef CONFIG_MXC_KPD

#define PRESSED_HOME    0x01
#define PRESSED_POWER   0x02
#define RECOVERY_KEY_MASK (PRESSED_HOME | PRESSED_POWER)

inline int test_key(int value, struct kpp_key_info *ki)
{
        return (ki->val == value) && (ki->evt == KDepress);
}

int check_key_pressing(void)
{
        struct kpp_key_info *key_info;
        int state = 0, keys, i;

        mxc_kpp_init();

        puts("Detecting HOME+POWER key for recovery ...\n");

        /* Check for home + power */
        keys = mxc_kpp_getc(&key_info);
        if (keys < 2)
                return 0;

        for (i = 0; i < keys; i++) {
                if (test_key(CONFIG_POWER_KEY, &key_info[i]))
                        state |= PRESSED_HOME;
                else if (test_key(CONFIG_HOME_KEY, &key_info[i]))
                        state |= PRESSED_POWER;
        }

        free(key_info);

        if ((state & RECOVERY_KEY_MASK) == RECOVERY_KEY_MASK)
                return 1;

        return 0;
}
#else
/* If not using mxc keypad, currently we will detect power key on board */
#define CPLD_BASE_ADDR 0xF4000000
#define KEY_STATUS 0xA
#define KEY_F1 0x1
#define KEY_F4 0x8

int check_key_pressing(void)
{
        volatile unsigned short tmp = 0;

        tmp = *(volatile unsigned short *)(CPLD_BASE_ADDR + KEY_STATUS);

        if(((tmp & KEY_F1) != 0) && ((tmp & KEY_F4) != 0))
                return 1;

        return 0;
}
#endif
这里用了if -else 完成了两个按键检测功能,第一个是MXC自带的键盘初始化和检测机制,第二个是我自己写的都键盘的内存地址。
setup_recovery_env() 就是设置进入recovery模式需要的enviroment parameters

void setup_recovery_env(void)
{
        char *env, *boot_args, *boot_cmd;
        int bootdev = get_boot_device();
        printf(" bootdev = %d..\n", bootdev);

        boot_cmd = supported_reco_envs[bootdev].cmd;
        boot_args = supported_reco_envs[bootdev].args;

        if (boot_cmd == NULL) {
                printf("Unsupported bootup device for recovery\n");
                return;
        }

        printf("setup env for recovery..\n");

        env = getenv("bootargs_sf");
        /* Set env to recovery mode */
        /* Only set recovery env when these env not exist, give user a
         * chance to change their recovery env */
        if (!env)
                setenv("bootarg_sf", boot_args);

        env = getenv("bootcmd_sf");
        if (!env)
                setenv("bootcmd_sf", boot_cmd);
        setenv("bootcmd", "run bootcmd_sf");
}

这里用到一个全局变量, 用来保存recovery模式启动时的evn参数:

struct reco_envs supported_reco_envs[BOOT_DEV_NUM] = {
        {
         .cmd = NULL,
         .args = NULL,
         },
        {
         .cmd = NULL,
         .args = NULL,
         },
        {
         .cmd = NULL,
         .args = NULL,
         },
        {
         .cmd = NULL,
         .args = NULL,
         },
        {
         .cmd = NULL,
         .args = NULL,
         },
        {
         .cmd = CONFIG_RECOVERY_BOOTCMD_SPI_NOR,
         .args = CONFIG_RECOVERY_BOOTARGS_SPI_NOR,
         },
        {
         .cmd = NULL,
         .args = NULL,
         },
        {
         .cmd = NULL,
         .args = NULL,
         },
        {
         .cmd = NULL,
         .args = NULL,
         },
};

/*
 * Recovery Configs
 */
#define CONFIG_ANDROID_RECOVERY
#define CONFIG_RECOVERY_BOOTARGS_SPI_NOR \
        "setenv bootargs_sf setenv bootargs console=ttymxc0,115200 ip=dhcp root=/dev/mtdblock3 rootwait rw"
#define CONFIG_RECOVERY_BOOTCMD_SPI_NOR \
        "setenv bootcmd_sf run bootargs_sf;sf probe 1;sf read ${loadaddr} 80000 300000;bootm ${loadaddr}"


env参数设置如下:

正常启动,从MMC启动

setenv bootcmd_mmc run bootargs_base bootargs_mmc\;mmc dev 0\;ext2load mmc 0:1 ${loadaddr} /boot/uImage\;bootm ${loadaddr}
setenv bootcmd run bootcmd_mmc
recovery模式启动,从spi-flash中启动

setenv bootargs_sf setenv bootargs console=ttymxc0,115200 ip=dhcp root=/dev/mtdblock3 rootwait rw
setenv bootcmd_sf run bootargs_sf\;sf probe 1\;sf read ${loadaddr} 80000 300000\;bootm ${loadaddr}
setenv bootcmd run bootcmd_sf


在MTK6580平台上实现开机Logo动画的自定义切换,首先需要了解Android开机流程的各个阶段以及如何通过修改系统文件来达到自定义效果。具体步骤包括: 参考资源链接:[MTK6580上实现Android开机Logo与动画自定义教程](https://wenku.youkuaiyun.com/doc/6412b66dbe7fbd1778d46ae9?spm=1055.2569.3001.10343) 1. **Bootloader阶段的Logo替换**: 找到Bootloader目录下的Logo图片文件,通常是`logo.bmp`或`bootlogo.bmp`,并将其替换为你想要的图片。图片分辨率要与原图一致,一般放在`mediatek/proprietary/bootable/bootloader/uboot/images`目录下。替换后,需要重新编译Bootloader来使更改生效。 2. **Kernel阶段的Logo替换**: 修改`ProjectConfig.mk`文件,设置`BOOT_LOGO`变量指向你的Logo图片路径。该图片文件通常位于`mediatek/proprietary/bootable/bootloader/lk/dev/logo`目录。确保在编译之前添加或替换Logo文件,并重新编译内核。 3. **Bootanimation阶段的动画替换**: 在`system/media/bootanimation.zip`文件中替换或添加动画压缩包。此压缩包包含多个帧,按照文件名顺序播放,形成动画效果。可以自定义动画的帧率持续时间,通过修改`bootanimation.cfg`配置文件实现。 4. **条件性Logo动画切换**: 在`protect_f`分区中创建`.dat`文件,作为不同Logo动画切换的标识。通过编写Java代码或在系统启动脚本中实现逻辑判断,根据文件存在与否来加载对应的Logo或动画。例如,在Recovery模式下启动时,可以检查特定文件是否存在,从而决定是否加载特殊的Recovery动画。 5. **确保自定义设置持久化**: 为了保证用户在恢复出厂设置后自定义设置不丢失,需在`protect_f`分区下创建不可删除的文件作为标记。这通常涉及到对分区表的修改,确保文件在任何情况下都不会被移除。 结合以上步骤,可以实现MTK6580平台上Android开机Logo动画的自定义切换。为了更深入地了解这一过程并解决可能遇到的问题,建议查阅《MTK6580上实现Android开机Logo与动画自定义教程》。该教程详细介绍了每个阶段的实现方法注意事项,能够帮助开发者顺利完成定制工作,并且在遇到难题时提供有效的解决方案。 参考资源链接:[MTK6580上实现Android开机Logo与动画自定义教程](https://wenku.youkuaiyun.com/doc/6412b66dbe7fbd1778d46ae9?spm=1055.2569.3001.10343)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值