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

一个嵌入式系统,一般情况下都是正常启动模式,如果需要系统升级,或系统恢复出厂状态,就会需要用到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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值