美文网首页
Android reboot recovery and norm

Android reboot recovery and norm

作者: Nothing_655f | 来源:发表于2020-08-11 19:14 被阅读0次

Android reboot recovery and normal 的一种实现流程

Uboot 判断

uboot\common\main.c

void main_loop(void) 中调用了几个重要的函数

void main_loop(void) 
{
    run_preboot_environment_command
    bootdelay_process
    autoboot_command
}

main_loop调用了run_preboot_environment_command, 该函数执行了 preboot定义的行为

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 */
}

preboot 的定义在 这里uboot\include\env_default.h

        #ifdef  CONFIG_PREBOOT
        "preboot="  CONFIG_PREBOOT          "\0"
        #endif

所以有一些预先设定的操作可以定义在 CONFIG_PREBOOT 这个宏当中,来看看我所用平台中定义的行为

#define CONFIG_PREBOOT  \
            "run bcb_cmd; "\
            "run factory_reset_poweroff_protect;"\
            "run upgrade_check;"\
            "run init_display;"\
            "run storeargs;"\
            "run switch_bootmode;"

CONFIG_PREBOOT 中有两个流程需要关注 bcb_cmd 和 switch_bootmode

bcb_cmd

先介绍下 bcb

BCB是Bootloader与Recovery的通信接口,也是Bootloader与Main system之间的通信接口。存储在flash中的MISC分区。占用三个page,其本身就是一个结构体,详细成员以及各成员含义例如以下,位于/bootloader/revocery/bootloader.h文件里:

struct bootloader_message{
char command[32];
    char status[32];
    char recovery[1024];
};

l command字段:当要重新启动进入Recovery模式或更新radio、bootloader固件时。linux会更新这个值。当固件更新完毕后Bootloader也会更新这个值。另外在成功更新后结束Recovery时。会清除这个成员的值,防止重新启动时再次进入Recovery模式。
l status字段:在完毕对应的更新后。Bootloader会将运行结果写入到这个字段。
l recovery字段:可被Main System写入,也可被Recovery服务程序写入。该文件的内容格式为:

    “recovery\n
    <recovery command>\n
    <recovery command>”

该文件存储的就是一个字符串,必须以recovery\n开头,否则这个字段的全部内容域会被忽略。“recovery\n”之后的部分,是/cache/recovery/command支持的命令。
能够将其理解为Recovery操作过程中对命令操作的备份。Recovery对其操作的过程为:先读取BCB然后读取/cache/recovery/command,然后将二者又一次写回BCB。这样在进入Main system之前。确保操作被运行。在操作之后进入Main system之前。Recovery又会清空BCB的command域和recovery域,这样确保重新启动后不再进入Recovery模式。

而定义的 bcb_cmd=get_valid_slot 其介绍为

This command will choose valid slot to boot up which saved it misc partition by mark to decide whether execute command

switch_bootmode

        "switch_bootmode="\
            "get_rebootmode;"\
            "if test ${reboot_mode} = factory_reset; then "\
                    "run recovery_from_flash;"\
            "else if test ${reboot_mode} = update; then "\
                    "run update;"\
            "else if test ${reboot_mode} = cold_boot; then "\
                    "run powermode_check;"\
            "else if test ${reboot_mode} = fastboot; then "\
                "fastboot;"\
            "fi;fi;fi;fi;"\
            "\0" \

1.先获取rebootmode

​ get_rebootmode do_get_rebootmode

int do_get_rebootmode (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
    uint32_t reboot_mode_val;
    reboot_mode_val = ((readl(AO_SEC_SD_CFG15) >> 12) & 0xf);
    debug("reboot_mode(0x%x)=0x%x\n", AO_SEC_SD_CFG15, reboot_mode_val);
}
通过读取寄存器值返回 reboot_mode对应如下
        #define XXX_COLD_BOOT               0
        #define XXX_NORMAL_BOOT             1
        #define XXX_FACTORY_RESET_REBOOT    2
        #define XXX_UPDATE_REBOOT           3
        #define XXX_FASTBOOT_REBOOT         4
        #define XXX_SUSPEND_REBOOT          5
        #define XXX_HIBERNATE_REBOOT        6
        #define XXX_BOOTLOADER_REBOOT       7 /* fastboot bootloader */
        #define XXX_SHUTDOWN_REBOOT                 8
        #define XXX_CRASH_REBOOT            11
        #define XXX_KERNEL_PANIC            12
        #define XXX_WATCHDOG_REBOOT         13

2、根据reboot mode 切换对应流程

switch_bootmode 中用到的reboot mode 是 factory_reset update cold_boot fastboot 这几种

factory_reset是进recovery 界面

update 是选择了ota 包后直接进入的recovery 升级流程

以reboot mode 为update caes 为例,其流程如下

        "update="\
            /*first usb burning, second sdc_burn, third ext-sd autoscr/recovery, last udisk autoscr/recovery*/\
            "run usb_burning; "\
            "run sdc_burning; "\
            "if mmcinfo; then "\
                "run recovery_from_sdcard;"\
            "fi;"\
            "if usb start 0; then "\
                "run recovery_from_udisk;"\
            "fi;"\
            "run recovery_from_flash;"\
            "\0"\
        "recovery_from_sdcard="\
            "if fatload mmc 0 ${loadaddr} xxx_autoscript; then autoscr ${loadaddr}; fi;"\
            "if fatload mmc 0 ${loadaddr} recovery.img; then "\
                    "if fatload mmc 0 ${dtb_mem_addr} dtb.img; then echo sd dtb.img loaded; fi;"\
                    "wipeisb; "\
                    "bootm ${loadaddr};fi;"\
            "\0"\
        "recovery_from_udisk="\
            "if fatload usb 0 ${loadaddr} xxx_autoscript; then autoscr ${loadaddr}; fi;"\
            "if fatload usb 0 ${loadaddr} recovery.img; then "\
                "if fatload usb 0 ${dtb_mem_addr} dtb.img; then echo udisk dtb.img loaded; fi;"\
                "wipeisb; "\
                "bootm ${loadaddr};fi;"\
            "\0"\
        "recovery_from_flash="\
            "setenv bootargs ${bootargs} xxx_dt=${xxx_dt} recovery_part={recovery_part} recovery_offset={recovery_offset};"\
            "if imgread kernel ${recovery_part} ${loadaddr} ${recovery_offset}; then wipeisb; bootm ${loadaddr}; fi"\
            "\0"\

可以看到做了一些前置的判断后 是通过 bootm ${loadaddr}; 跳转到下一个流程的启动地址

以recovery_from_flash 为例,设置bootargs 参数 和dt 以及recovery 地址,然后使用 imgread kernel 可以 recovery 参数后启动kernel

正常开机流程

recovery的流程看完了,看下正常开机的流程,即main_loop 中 bootdelay_process() 和autoboot_command

bootdelay_process()
{
    // ...
    s = getenv("bootcmd");
}

这个bootcmd 也是有个默认的宏定义值

uboot\include\env_default.h

             #ifdef CONFIG_BOOTCOMMAND
                "bootcmd="  CONFIG_BOOTCOMMAND      "\0"
            #endif

在我的工程文件中定义的 CONFIG_BOOTCOMMAND如下

#define CONFIG_BOOTCOMMAND "run storeboot"
        "storeboot="\
        "if imgread kernel ${boot_part} ${loadaddr}; then bootm ${loadaddr}; fi;"\
        "run update;"\
        "\0"\

所以可以看到传给autoboot_command 的字符串是 "run storeboot"

void autoboot_command(const char *s)
{
    printf("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");

    if (stored_bootdelay != -1 && s && !abortboot(stored_bootdelay)) {
#if defined(CONFIG_AUTOBOOT_KEYED) && !defined(CONFIG_AUTOBOOT_KEYED_CTRLC)
        int prev = disable_ctrlc(1);    /* disable Control C checking */
#endif
        run_command_list(s, -1, 0);
#if defined(CONFIG_AUTOBOOT_KEYED) && !defined(CONFIG_AUTOBOOT_KEYED_CTRLC)
        disable_ctrlc(prev);    /* restore Control C checking */
#endif
    }
#ifdef CONFIG_MENUKEY
    if (menukey == CONFIG_MENUKEY) {
        s = getenv("menucmd");
        if (s)
            run_command_list(s, -1, 0);
    }
#endif /* CONFIG_MENUKEY */
}

这里介绍下其中的 autoboot_command调用的的 abortboot , 如下两个函数会判断是否有对应的输入来决定是否进入boot console

static int abortboot(int bootdelay)
{
#ifdef CONFIG_AUTOBOOT_KEYED
    return abortboot_keyed(bootdelay);  /*  delaykey[] = {
            { .str = getenv("bootdelaykey"),  .retry = 1 },
            { .str = getenv("bootdelaykey2"), .retry = 1 },
            { .str = getenv("bootstopkey"),   .retry = 0 },
            { .str = getenv("bootstopkey2"),  .retry = 0 },
        };*/
#else
    return abortboot_normal(bootdelay);  // Hit Enter or space or Ctrl+C key to stop autoboot -- 
#endif
}

Kernel 设定reboot mode

Kernel 3.14

kernel reboot.c 会调用 machine_power_off 和 machine_restart

这边的平台是arm64 平台,其对应函数实现是在 arch/arm64/kernel/processs.c

processs.c 中有调用了 pm_power_off arm_pm_restart

所以可以通过注册了 pm 的全局方法 pm_power_off arm_pm_restart来实现设定对应的寄存器值

static int aml_restart_probe(struct platform_device *pdev)
{
    pm_power_off = do_xxx_poweroff;
    arm_pm_restart = do_xxx_restart;
    return 0;
}
    static void do_xxx_poweroff(void)
    {
        /* TODO: Add poweroff capability */
        meson_common_restart('h', "charging_reboot");
    }
        void meson_common_restart(char mode, const char *cmd)
        {
            u32 reboot_reason = MESON_NORMAL_BOOT;
            if (cmd) {
                if (strcmp(cmd, "charging_reboot") == 0)
                    reboot_reason = MESON_CHARGING_REBOOT;
                else if (strcmp(cmd, "recovery") == 0 ||
                     strcmp(cmd, "factory_reset") == 0)
                    reboot_reason = MESON_FACTORY_RESET_REBOOT;
                else if (strcmp(cmd, "update") == 0)
                    reboot_reason = MESON_UPDATE_REBOOT;
                else if (strcmp(cmd, "report_crash") == 0)
                    reboot_reason = MESON_CRASH_REBOOT;
                else if (strcmp(cmd, "factory_testl_reboot") == 0)
                    reboot_reason = MESON_FACTORY_TEST_REBOOT;
                else if (strcmp(cmd, "switch_system") == 0)
                    reboot_reason = MESON_SYSTEM_SWITCH_REBOOT;
                else if (strcmp(cmd, "safe_mode") == 0)
                    reboot_reason = MESON_SAFE_REBOOT;
                else if (strcmp(cmd, "lock_system") == 0)
                    reboot_reason = MESON_LOCK_REBOOT;
                else if (strcmp(cmd, "usb_burner_reboot") == 0)
                    reboot_reason = MESON_USB_BURNER_REBOOT;
                else if (strcmp(cmd, "uboot_suspend") == 0)
                    reboot_reason = MESON_UBOOT_SUSPEND;
            }
            xxx_write_aobus(AO_RTI_STATUS_REG1, reboot_reason);
            if (is_meson_m8m2_cpu())
                xxx_write_cbus(WATCHDOG_TC, (1<<19) | 100);
            if (is_meson_m8_cpu())
                xxx_write_cbus(WATCHDOG_TC, (1<<22) | 100);
        }

Android Framework流程

这里是Android的标准流程,这里可以参考这份资料

https://www.jb51.net/article/79844.htm

https://www.2cto.com/kf/201609/550976.html

https://blog.csdn.net/wangjun7121/article/details/88127388

相关文章

网友评论

      本文标题:Android reboot recovery and norm

      本文链接:https://www.haomeiwen.com/subject/ictqdktx.html