// SPDX-License-Identifier: (GPL-2.0+ OR MIT) /* * Copyright (c) 2019 Amlogic, Inc. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(CONFIG_EFUSE_OBJ_API) && defined(CONFIG_CMD_EFUSE) extern efuse_obj_field_t efuse_field; #endif//#ifdef CONFIG_EFUSE_OBJ_API typedef boot_img_hdr_t boot_img_hdr; #define debugP(fmt...) //printf("[DbgBootSta]L%d:", __LINE__),printf(fmt) #define errorP(fmt...) printf("ErrBootSta(L%d):", __LINE__),printf(fmt) #define wrnP(fmt...) printf("wrn:"fmt) #define MsgP(fmt...) printf("[BootSta]"fmt) #define BOOTLOADER_OFFSET 512 #define BOOTLOADER_MAX_SIZE (4 * 1024 * 1024) #define MIB_SIZE (1024 * 1024) #define GPT_OFFSET 0x3DFE00 #define GPT2_OFFSET 0x3EC600 #define DTS_GPT_OFFSET 0x3E0000 #define MAX_VBMETA_SIZE (8 * 1024) //check SWPL-31296 for details static int do_get_bootloader_status(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { bool printStat = false; bool saveenv = false; debugP("Initial value for argc=%d\n", argc); while (argc > 1 && **(argv + 1) == '-') { char *arg = *++argv; --argc; while (*++arg) { switch (*arg) { case 'p': /* print */ printStat = true; break; case 's': /* saveenv */ saveenv = true; break; default: return CMD_RET_USAGE; } } } debugP("Final value for argc=%d\n", argc); //1,forUpgrade_socType, cpu familyId const cpu_id_t cpuid = get_cpu_id(); const int familyId = cpuid.family_id; env_set_hex("forUpgrade_socType", familyId); //2,forUpgrade_secureBoot const bool secureboot = IS_FEAT_BOOT_VERIFY(); env_set("forUpgrade_secureBoot", secureboot ? "true" : "false"); //3,forUpgrade_robustOta bool supportRobustOta = false; switch (familyId) { case 0x32://sc2 case 0x36://t7 case 0x37://s4 case 0x38://t3 case 0x3A://s4d supportRobustOta = true; break; case MESON_CPU_MAJOR_ID_T5W: case MESON_CPU_MAJOR_ID_TXHD2: supportRobustOta = false; break; default: { if (familyId > 0x3A) { supportRobustOta = true; } } break; } env_set("forUpgrade_robustOta", supportRobustOta ? "true" : "false"); //4,forUpgrade_flashType const char* BootDevices[] = { "BOOT_EMMC", "BOOT_SD", "BOOT_NAND_NFTL", "BOOT_NAND_MTD", "BOOT_SNAND", "BOOT_SNOR", }; const char* bootDevice = "BOOT_NONE"; enum boot_type_e bootType = store_get_type(); int i = 0; for (; i < ARRAY_SIZE(BootDevices); ++i) { if ((1<= 9 && printStat) run_command("printenv forUpgrade_socType forUpgrade_secureBoot " " forUpgrade_robustOta forUpgrade_flashType forUpgrade_bootloaderCopies " " forUpgrade_bootloaderIndex forUpgrade_1stBootIndex", 0); //8,production mode for ver4 boot.img bootconfig env_set_ulong("production_mode", CONFIG_IS_ENABLED(AML_PRODUCT_MODE)); if (printStat) run_command("printenv production_mode", 0); if (saveenv) { #if CONFIG_IS_ENABLED(AML_UPDATE_ENV) run_command("update_env_part -p forUpgrade_robustOta forUpgrade_bootloaderIndex", 0 ); #else run_command("saveenv", 0); #endif } return CMD_RET_SUCCESS; } static void run_recovery_from_flash(void) { env_set("dolby_status","0"); run_command("run init_display", 0); run_command("run storeargs", 0); run_command("get_rebootmode", 0); run_command("if test ${reboot_mode} = quiescent; then "\ "setenv bootconfig ${bootconfig} androidboot.quiescent=1; fi;", 0); run_command("if test ${reboot_mode} = recovery_quiescent; then "\ "setenv bootconfig ${bootconfig} androidboot.quiescent=1; fi;", 0); run_command("run recovery_from_flash", 0); } static void run_recovery_from_cache(void) { char *loadaddr_kernel = env_get("loadaddr_kernel"); if (loadaddr_kernel != NULL) { env_set("loadaddr",loadaddr_kernel); } else { env_set("loadaddr","0x01080000"); } env_set("dolby_status","0"); run_command("run bcb_cmd;", 0); run_command("run init_display", 0); run_command("run storeargs", 0); run_command("get_rebootmode", 0); run_command("if test ${reboot_mode} = quiescent; then "\ "setenv bootconfig ${bootconfig} androidboot.quiescent=1; fi;", 0); run_command("if test ${reboot_mode} = recovery_quiescent; then "\ "setenv bootconfig ${bootconfig} androidboot.quiescent=1; fi;", 0); run_command("if ext4load mmc 1:2 ${dtb_mem_addr} /recovery/dtb.img; then "\ "echo cache dtb.img loaded;"\ "else "\ "imgread dtb recovery ${dtb_mem_addr};"\ "fi;", 0); run_command("if test ${reboot_vendor_boot} = true; then "\ "setenv vendor_boot_mode true; fi;", 0); run_command("if test ${vendor_boot_mode} = true; then "\ "setenv bootargs ${bootargs} ${fs_type} aml_dt=${aml_dt} recovery_part=${recovery_part} recovery_offset=${recovery_offset};"\ "imgread kernel ${recovery_part} ${loadaddr} ${recovery_offset};"\ "avb memory recovery ${loadaddr};"\ "avb recovery 1;"\ "else "\ "if ext4load mmc 1:2 ${loadaddr} /recovery/recovery.img; then "\ "if avb memory recovery ${loadaddr}; then " \ "avb recovery 1;" \ "echo cache recovery.img loaded; fi;"\ "fi;" \ "fi;", 0); env_set("check_result","recovery_succ"); env_set("recovery_mode", "true"); run_command("bootm ${loadaddr}", 0); env_set("check_result","recovery_fail"); env_set("reboot_status","reboot_recovery"); run_command("saveenv", 0); run_command("reboot", 0);//need reboot old bootloader } int write_bootloader_back(const char *bootloaderindex, int dstindex) { int iRet = 0; int copy = 0; int ret = -1; unsigned char* buffer = NULL; int capacity_boot = 0; if (strcmp(bootloaderindex, "1") == 0) { copy = 1; } else if (strcmp(bootloaderindex, "2") == 0) { copy = 2; } else if (strcmp(bootloaderindex, "0") == 0) { copy = 0; } #ifdef CONFIG_MMC_MESON_GX struct mmc *mmc = NULL; if (store_get_type() == BOOT_EMMC) mmc = find_mmc_device(1); if (mmc) capacity_boot = mmc->capacity_boot; #endif printf("write_bootloader_back_capacity_boot: %x\n", capacity_boot); buffer = (unsigned char *)malloc(capacity_boot); if (!buffer) { printf("ERROR! fail to allocate memory ...\n"); goto exit; } memset(buffer, 0, capacity_boot); iRet = store_boot_read("bootloader", copy, 0, buffer); if (iRet) { errorP("Fail read bootloader from rsv with sz\n"); goto exit; } iRet = store_boot_write("bootloader", dstindex, 0, buffer); if (iRet) { printf("Failed to write bootloader\n"); goto exit; } else { ret = 0; } exit: if (buffer) { free(buffer); //buffer = NULL; } return ret; } //bootloader write protect static void bootloader_wp(void) { #ifdef CONFIG_MMC_MESON_GX if (store_get_type() == BOOT_EMMC) {//emmc device if (IS_FEAT_BOOT_VERIFY()) { //secure boot enable if (BOOTLOADER_MODE_ADVANCE_INIT) { //new arch chip env_set("bootloader_wp", "1"); } } } #endif } static void aml_recovery(void) { char *mode = NULL; char command[32]; char miscbuf[4096] = {0}; run_command("get_rebootmode", 0); //get reboot_mode mode = env_get("reboot_mode"); if (mode == NULL) { wrnP("can not get reboot mode, so skip recovery check\n"); } else { if ((!strcmp(mode, "factory_reset")) || (!strcmp(mode, "update"))) { env_set("dolby_status","0"); } } #ifdef CONFIG_BOOTLOADER_CONTROL_BLOCK int ret = 0; extern int boot_info_open_partition(char *miscbuf); ret = boot_info_open_partition(miscbuf); if (ret != 0) { wrnP("open misc partition failed, so skip recovery check"); return; } #endif //if run recovery, need disable dolby memcpy(command, miscbuf, 32); if (!memcmp(command, "boot-recovery", strlen("boot-recovery"))) { env_set("dolby_status","0"); return; } } void update_rollback(void) { char *slot = NULL; int ret = -1; int gpt_flag = -1; char *rebootmode = env_get("reboot_mode"); #ifdef CONFIG_MMC_MESON_GX struct mmc *mmc = NULL; if (store_get_type() == BOOT_EMMC) mmc = find_mmc_device(1); if (mmc) gpt_flag = aml_gpt_valid(mmc); #endif if (gpt_flag == 0) ret = 0; #if defined(CONFIG_EFUSE_OBJ_API) && defined(CONFIG_CMD_EFUSE) run_command("efuse_obj get FEAT_DISABLE_EMMC_USER", 0); //dis_user_flag = run_command("efuse_obj get FEAT_DISABLE_EMMC_USER", 0); if (*efuse_field.data == 1) ret = 0; #endif//#ifdef CONFIG_EFUSE_OBJ_API slot = env_get("slot-suffixes"); if (!slot) { run_command("get_valid_slot", 0); slot = env_get("slot-suffixes"); } if (strcmp(slot, "0") == 0) { if (ret != 0) { wrnP("normal mode\n"); write_bootloader_back("2", 0); env_set("expect_index", "0"); } else { wrnP("gpt or disable user bootloader mode\n"); run_command("check_uboot_state 0", 0); write_bootloader_back("2", 1); env_set("expect_index", "1"); } wrnP("back to slot b\n"); run_command("set_roll_flag 1", 0); run_command("set_active_slot b", 0); } else if (strcmp(slot, "1") == 0) { if (ret != 0) { wrnP("normal mode\n"); write_bootloader_back("1", 0); env_set("expect_index", "0"); } else { wrnP("gpt or disable user bootloader mode\n"); run_command("check_uboot_state 1", 0); write_bootloader_back("2", 1); env_set("expect_index", "1"); } wrnP("back to slot a\n"); run_command("set_roll_flag 1", 0); run_command("set_active_slot a", 0); } env_set("update_env", "1"); env_set("reboot_status", "reboot_next"); env_set("update_dts_gpt", "0"); env_set("write_boot", "0"); run_command("saveenv", 0); if (rebootmode && (strcmp(rebootmode, "quiescent") == 0)) run_command("reboot quiescent", 0); else run_command("reboot", 0); } #ifdef CONFIG_MMC_MESON_GX static int write_bootloader_to_logical(void) { unsigned char *buffer = NULL; int capacity_boot = 0x2000 * 512; int iRet = 0; char partname[32] = {0}; char back_partname[32] = {0}; char *slot_name = NULL; #ifdef CONFIG_MMC_MESON_GX struct mmc *mmc = NULL; if (store_get_type() == BOOT_EMMC) mmc = find_mmc_device(1); if (mmc) capacity_boot = mmc->capacity_boot; #endif printf("capacity_boot in write uboot to logical: 0x%x\n", capacity_boot); buffer = (unsigned char *)malloc(capacity_boot); if (!buffer) { printf("ERROR! fail to allocate memory ...\n"); return -1; } memset(buffer, 0, capacity_boot); slot_name = env_get("active_slot"); if (slot_name && (strcmp(slot_name, "_a") == 0)) { strcpy((char *)partname, "bootloader_a"); strcpy((char *)back_partname, "bootloader_b"); } else if (slot_name && (strcmp(slot_name, "_b") == 0)) { strcpy((char *)partname, "bootloader_b"); strcpy((char *)back_partname, "bootloader_a"); } iRet = store_boot_read("bootloader", 1, 0, buffer); if (iRet) { printf("Failed to read bootloader\n"); free(buffer); return -1; } printf("write boot0 to %s\n", partname); iRet = store_logic_write(partname, 0, BOOTLOADER_MAX_SIZE - BOOTLOADER_OFFSET, buffer); if (iRet) { errorP("Fail to write 0x%xB to part[%s] at offset 0\n", BOOTLOADER_MAX_SIZE - BOOTLOADER_OFFSET, partname); free(buffer); return -1; } iRet = store_boot_read("bootloader", 2, 0, buffer); if (iRet) { printf("Failed to read boot1\n"); free(buffer); return -1; } printf("write boot1 to %s\n", back_partname); iRet = store_logic_write(back_partname, 0, BOOTLOADER_MAX_SIZE - BOOTLOADER_OFFSET, buffer); if (iRet) { errorP("Fail to write 0x%xB to part[%s] at offset 0\n", BOOTLOADER_MAX_SIZE - BOOTLOADER_OFFSET, back_partname); free(buffer); return -1; } free(buffer); return 0; } #endif static int write_bootloader(int i) { unsigned char *buffer = NULL; int capacity_boot = 0x2000 * 512; int iRet = 0; char partname[32] = {0}; char *slot_name = NULL; #ifdef CONFIG_MMC_MESON_GX struct mmc *mmc = NULL; if (store_get_type() == BOOT_EMMC) mmc = find_mmc_device(1); if (mmc) capacity_boot = mmc->capacity_boot; #endif printf("capacity_boot: 0x%x\n", capacity_boot); buffer = (unsigned char *)malloc(capacity_boot); if (!buffer) { printf("ERROR! fail to allocate memory ...\n"); return -1; } memset(buffer, 0, capacity_boot); slot_name = env_get("active_slot"); if (slot_name && (strcmp(slot_name, "_a") == 0)) strcpy((char *)partname, "bootloader_a"); else if (slot_name && (strcmp(slot_name, "_b") == 0)) strcpy((char *)partname, "bootloader_b"); else strcpy((char *)partname, "bootloader_up"); iRet = store_logic_read(partname, 0, BOOTLOADER_MAX_SIZE - BOOTLOADER_OFFSET, buffer); if (iRet) { errorP("Fail to read 0x%xB from part[%s] at offset 0\n", BOOTLOADER_MAX_SIZE - BOOTLOADER_OFFSET, partname); free(buffer); return -1; } iRet = store_boot_write("bootloader", i, BOOTLOADER_MAX_SIZE - BOOTLOADER_OFFSET, buffer); if (iRet) { printf("Failed to write boot0\n"); free(buffer); return -1; } free(buffer); return 0; } static int update_gpt(int flag) { int ret = 0; #ifdef CONFIG_MMC_MESON_GX unsigned char *buffer = NULL; int capacity_boot = 0x2000 * 512; int iRet = 0; struct mmc *mmc = NULL; struct blk_desc *dev_desc; int write_gpt = 0; int gpt_flag = -1; if (store_get_type() == BOOT_EMMC) mmc = find_mmc_device(1); if (mmc) gpt_flag = aml_gpt_valid(mmc); if (mmc) capacity_boot = mmc->capacity_boot; printf("capacity_boot: 0x%x\n", capacity_boot); printf("flag: %d\n", flag); buffer = (unsigned char *)malloc(capacity_boot); if (!buffer) { printf("ERROR! fail to allocate memory ...\n"); return -1; } memset(buffer, 0, capacity_boot); if (flag == 0) { iRet = store_boot_read("bootloader", 1, 0, buffer); if (iRet) { printf("Failed to read boot0\n"); ret = -1; goto exit; } } else if (flag == 1 || flag == 2) { iRet = store_boot_read("bootloader", 0, 0, buffer); if (iRet) { printf("Failed to read bootloader\n"); ret = -1; goto exit; } } else if (flag == 3) { printf("null ab mode\n"); iRet = store_logic_read("bootloader_up", 0, BOOTLOADER_MAX_SIZE - BOOTLOADER_OFFSET, buffer); if (iRet) { printf("Fail to read 0x%xB from bootloader_up\n", BOOTLOADER_MAX_SIZE - BOOTLOADER_OFFSET); ret = -1; goto exit; } } if (mmc) { printf("try to read gpt data from bootloader.img\n"); int erase_flag = 0; dev_desc = blk_get_dev("mmc", 1); if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) { printf("invalid mmc device\n"); ret = -1; goto exit; } if (is_valid_gpt_buf(dev_desc, buffer + GPT_OFFSET) && is_valid_gpt_buf(dev_desc, buffer + GPT2_OFFSET) && is_valid_gpt_buf(dev_desc, buffer + DTS_GPT_OFFSET)) { printf("printf normal bootloader.img, no gpt partition table\n"); char *dts_flag = env_get("dts_to_gpt"); char *write_boot = env_get("write_boot"); if (write_boot && !strcmp(write_boot, "1")) { if (dts_flag && (strcmp(dts_flag, "1") == 0)) { printf("write dtb back when rollback\n"); erase_gpt_part_table(dev_desc); if (run_command("imgread dtb ${boot_part} ${dtb_mem_addr}", 0)) { printf("Fail in load dtb\n"); } else { printf("write dtb back\n"); run_command("emmc dtb_write ${dtb_mem_addr} 0", 0); } } } ret = -1; goto exit; } else { if (!is_valid_gpt_buf(dev_desc, buffer + GPT_OFFSET)) { erase_flag = check_gpt_change(dev_desc, buffer + GPT_OFFSET); } else if (!is_valid_gpt_buf(dev_desc, buffer + DTS_GPT_OFFSET)) { erase_flag = check_gpt_change(dev_desc, buffer + DTS_GPT_OFFSET); } else if (!is_valid_gpt_buf(dev_desc, buffer + GPT2_OFFSET)) { erase_flag = check_gpt_change(dev_desc, buffer + GPT2_OFFSET); } else { printf("printf normal bootloader.img, no gpt partition table\n"); } if (erase_flag == 4 && has_boot_slot == 0) { printf("null ab critical partition change, refused to upgrade\n"); ret = 5; goto exit; } else if (has_boot_slot == 1 && (erase_flag == 3 || erase_flag == 4)) { printf("Important partition changes, refused to upgrade\n"); ret = 1; goto exit; } else if (erase_flag == 0) { printf("partition doesn't change, needn't update\n"); ret = -1; goto clean; } if (flag == 1 || flag == 2) { printf("update from dts to gpt, erase first\n"); erase_gpt_part_table(dev_desc); } if (flag == 2) { #if CONFIG_IS_ENABLED(AML_UPDATE_ENV) env_set("dts_to_gpt", "1"); run_command("update_env_part -p dts_to_gpt;", 0); #else run_command("defenv_reserve;setenv dts_to_gpt 1;saveenv;", 0); #endif } run_command("store boot_erase bootloader 0;", 0); if (!is_valid_gpt_buf(dev_desc, buffer + GPT_OFFSET)) { write_gpt = write_mbr_and_gpt_partitions(dev_desc, buffer + GPT_OFFSET); } else if (!is_valid_gpt_buf(dev_desc, buffer + DTS_GPT_OFFSET)) { write_gpt = write_mbr_and_gpt_partitions(dev_desc, buffer + DTS_GPT_OFFSET); } else if (!is_valid_gpt_buf(dev_desc, buffer + GPT2_OFFSET)) { write_gpt = write_mbr_and_gpt_partitions(dev_desc, buffer + GPT2_OFFSET); } else { printf("printf normal bootloader.img, no gpt partition table\n"); } if (write_gpt) { printf("%s: writing GPT partitions failed\n", __func__); ret = 1; goto exit; } if (mmc_device_init(mmc) != 0) { printf(" update gpt partition table fail\n"); ret = 2; goto exit; } if (erase_flag == 5) { printf("userdata size change, adjust backup gpt\n"); ret = -1; } printf("%s: writing GPT partitions ok\n", __func__); } } clean: if (flag == 0) { if (has_boot_slot == 1 && gpt_flag != 0) write_bootloader_to_logical(); memset(buffer + GPT_OFFSET, 0, capacity_boot - GPT_OFFSET); iRet = store_boot_write("bootloader", 1, 0, buffer); if (iRet) { printf("Failed to write boot0\n"); ret = -1; goto exit; } } if (has_boot_slot == 1 && (flag == 1 || flag == 2)) { printf("update from dts to gpt, backup old bootloader\n"); char *slot = NULL; slot = env_get("slot-suffixes"); if (!slot) { run_command("get_valid_slot", 0); slot = env_get("slot-suffixes"); } if (strcmp(slot, "0") == 0) { printf("active is a, b is old, don't need backup\n"); } else if (strcmp(slot, "1") == 0) { printf("active is b, a is old, backup boot0 to boot1\n"); iRet = write_bootloader_back("1", 2); if (iRet != 0) { printf("Failed to write boot1\n"); ret = 3; goto exit; } } iRet = store_boot_write("bootloader", 1, 0, buffer); if (iRet) { printf("Failed to write boot0\n"); ret = 4; goto exit; } if (has_boot_slot == 1 && gpt_flag != 0) write_bootloader_to_logical(); memset(buffer + GPT_OFFSET, 0, capacity_boot - GPT_OFFSET); iRet = store_boot_write("bootloader", 1, 0, buffer); if (iRet) { printf("Failed to write boot0\n"); ret = 4; goto exit; } } exit: if (buffer) free(buffer); if (mmc) run_command("mmc dev 1 0;", 0); if (mmc && ret > 0) { if (ret == 1 || ret == 2 || ret == 3) { printf("rollback\n"); update_rollback(); } else if (ret == 4) { printf("write back boot0, rollback\n"); write_bootloader_back("2", 1); update_rollback(); } } #endif return ret; } int recovery_update(void) { #ifdef CONFIG_MMC_MESON_GX char bufcmd[64]; unsigned long long size = 0; char *recovery_need_update = NULL; struct partitions *partition = NULL; //"ANDROID!" const unsigned char imghead[] = { 0x41, 0x4e, 0x44, 0x52, 0x4f, 0x49, 0x44, 0x21 }; if (store_get_type() != BOOT_EMMC) return 0; //check recoverybak partition exist partition = find_mmc_partition_by_name("recoverybak"); if (!partition) { printf("can not find recoverybak, skip\n"); return 0; } //check if need update recovery from recoverybak recovery_need_update = env_get("recovery_need_update"); if (!recovery_need_update || strcmp(recovery_need_update, "1")) return 0; //read recoverybak header data for check sprintf(bufcmd, "store read $loadaddr recoverybak 0 0x%x", 16); run_command(bufcmd, 0); unsigned char *loadaddr = (unsigned char *)simple_strtoul(env_get("loadaddr"), NULL, 16); //check recoverybak head is start "ANDROID!" if (memcmp((void *)imghead, loadaddr, 8)) { printf("not valid recovery image, skip update recovery\n"); return 0; } //write recoverybak data to recovery while (size < partition->size) { unsigned long long write_size = 0; unsigned long long left_size = partition->size - size; if (left_size > 10 * MIB_SIZE) write_size = 10 * MIB_SIZE; else write_size = partition->size - size; sprintf(bufcmd, "store read $loadaddr recoverybak 0x%llx 0x%llx", size, write_size); run_command(bufcmd, 0); sprintf(bufcmd, "store write $loadaddr recovery 0x%llx 0x%llx", size, write_size); run_command(bufcmd, 0); size += write_size; } //clean recovery_need_update to 0 env_set("recovery_need_update", "0"); #if CONFIG_IS_ENABLED(AML_UPDATE_ENV) run_command("update_env_part -p recovery_need_update;", 0); #else run_command("saveenv", 0); #endif #endif return 0; } static int build_userdebug(void) { #ifdef CONFIG_AVB2 int i = 0; int ret = 0; char *vbmeta_slot = NULL; int userdebug = 0; char vbmeta_name[16] = {0}; char vbuf[MAX_VBMETA_SIZE] = {0}; //"userdebug" 0x75 0x73 0x65 0x72 0x64 0x65 0x62 0x75 0x67 const unsigned char buildtype[] = { 0x75, 0x73, 0x65, 0x72, 0x64, 0x65, 0x62, 0x75, 0x67 }; printf("avb2 enable, get user/userdebug from vbmeta partition.\n"); char *get_vbmeta_slot(void); vbmeta_slot = get_vbmeta_slot(); if (has_boot_slot == 0) strcpy(vbmeta_name, "vbmeta"); else sprintf(vbmeta_name, "vbmeta%s", vbmeta_slot); ret = store_read(vbmeta_name, 0, MAX_VBMETA_SIZE, vbuf); if (ret) { printf("store read %s failed, skip!\n", vbmeta_name); return -1; } for (i = 0; i < MAX_VBMETA_SIZE - 10; i++) { if (vbuf[i] == 0x75) { if (!memcmp(vbuf + i, buildtype, 9)) { printf("find userdebug flag\n"); userdebug = 1; break; } } } return userdebug; #else printf("avb2 disable, skip.\n"); return -1; #endif } static int do_secureboot_check(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { int match_flag = 0; char *rebootstatus = NULL; char *checkresult = NULL; char *bootloaderindex = NULL; char *expect_index = NULL; char *robustota = NULL; char *update_env = NULL; char *rebootmode = NULL; int gpt_flag = -1; int ret = -1; #ifdef CONFIG_MMC_MESON_GX struct mmc *mmc = NULL; //int capacity_boot = 0; if (store_get_type() == BOOT_EMMC) mmc = find_mmc_device(1); #endif recovery_update(); bootloader_wp(); build_userdebug(); //set default env before check env_set("recovery_mode", "false"); //if recovery mode, need disable dv, if factoryreset, need default uboot env aml_recovery(); #ifdef CONFIG_MMC_MESON_GX if (mmc) gpt_flag = aml_gpt_valid(mmc); #endif if (gpt_flag == 0) ret = 0; #if defined(CONFIG_EFUSE_OBJ_API) && defined(CONFIG_CMD_EFUSE) run_command("efuse_obj get FEAT_DISABLE_EMMC_USER", 0); if (*efuse_field.data == 1) { wrnP("efuse_field.data == 1\n"); ret = 0; env_set("nocs_mode", "true"); } else { wrnP("efuse_field.data != 1\n"); env_set("nocs_mode", "false"); } #endif//#ifdef CONFIG_EFUSE_OBJ_API run_command("get_rebootmode", 0); rebootmode = env_get("reboot_mode"); if (!rebootmode) { wrnP("can not get reboot mode, so skip secure check\n"); return -1; } printf("rebootmode is %s\n", rebootmode); if (rebootmode && (strcmp(rebootmode, "rescueparty") == 0)) { printf("rebootmode is rescueparty, need rollback\n"); env_set("rollback_reason", "rescueparty"); #if CONFIG_IS_ENABLED(AML_UPDATE_ENV) run_command("update_env_part -p rollback_reason;", 0); #else run_command("saveenv", 0); #endif char *slot; #ifdef CONFIG_FASTBOOT struct misc_virtual_ab_message message; set_mergestatus_cancel(&message); #endif slot = env_get("slot-suffixes"); if (!slot) { run_command("get_valid_slot", 0); slot = env_get("slot-suffixes"); } if (strcmp(slot, "0") == 0) { if (ret != 0) { wrnP("normal mode\n"); write_bootloader_back("2", 0); env_set("expect_index", "0"); } else { wrnP("gpt or disable user bootloader mode\n"); write_bootloader_back("2", 1); env_set("expect_index", "1"); } wrnP("back to slot b\n"); run_command("set_roll_flag 1", 0); run_command("set_active_slot b", 0); } else if (strcmp(slot, "1") == 0) { if (ret != 0) { wrnP("normal mode\n"); write_bootloader_back("1", 0); env_set("expect_index", "0"); } else { wrnP("gpt or disable user bootloader mode\n"); write_bootloader_back("2", 1); env_set("expect_index", "1"); } wrnP("back to slot a\n"); run_command("set_roll_flag 1", 0); run_command("set_active_slot a", 0); } env_set("update_env", "1"); env_set("reboot_status", "reboot_next"); run_command("saveenv", 0); if (rebootmode && (strcmp(rebootmode, "quiescent") == 0)) run_command("reboot quiescent", 0); else run_command("reboot", 0); } char *recovery_check = env_get("recovery_check_part"); int update_flag = -1; int rc = 0; char *recovery_prepare = env_get("recovery_prepare_ok"); if (recovery_prepare && !strcmp(recovery_prepare, "1")) { if (has_boot_slot == 0 && recovery_check && (!strcmp(recovery_check, "1") || !strcmp(recovery_check, "4"))) { printf("non ab for kernel 5.15, check part table\n"); if (!strcmp(recovery_check, "1")) { printf("try write boot1\n"); rc = write_bootloader(1); if (rc) { printf("write boot1 fail, OTA error\n"); env_set("recovery_check_part", "3"); } else { printf("check & update part\n"); update_flag = update_gpt(3); } } else if (!strcmp(recovery_check, "4")) { printf("check & update part\n"); update_flag = update_gpt(1); } run_command("defenv_reserv; saveenv;", 0); run_command("run bcb_cmd", 0); if (update_flag < 1) { printf("check & update part ok......\n"); env_set("recovery_check_part", "2"); printf("boot from boot0\n"); env_set("reboot_status", "reboot_next"); env_set("expect_index", "1"); #if CONFIG_IS_ENABLED(AML_UPDATE_ENV) run_command("update_env_part -p reboot_status;", 0); run_command("update_env_part -p expect_index;", 0); #endif } else { printf("check & update part error\n"); if (!strcmp(recovery_check, "1")) { printf("write boot0 back\n"); write_bootloader_back("2", 1); } else if (!strcmp(recovery_check, "4")) { printf("write bootloader back\n"); write_bootloader_back("2", 1); write_bootloader_back("2", 0); } env_set("recovery_check_part", "3"); env_set("upgrade_step", "4"); #if CONFIG_IS_ENABLED(AML_UPDATE_ENV) run_command("update_env_part -p upgrade_step;", 0); #endif } #if CONFIG_IS_ENABLED(AML_UPDATE_ENV) run_command("update_env_part -p recovery_check_part;", 0); #else run_command("saveenv", 0); #endif if (rebootmode && (strcmp(rebootmode, "quiescent") == 0)) run_command("reboot quiescent", 0); else run_command("reboot", 0); } if (has_boot_slot == 0 && recovery_check && (!strcmp(recovery_check, "3"))) { printf("check part error, run_recovery_from_flash\n"); run_recovery_from_flash(); return 0; } } else { if (has_boot_slot == 0 && recovery_check && !strcmp(recovery_check, "4")) { printf("back to old bootloader\n"); write_bootloader_back("2", 0); if (rebootmode && (strcmp(rebootmode, "quiescent") == 0)) run_command("reboot quiescent", 0); else run_command("reboot", 0); } } char *write_boot = env_get("write_boot"); if (has_boot_slot == 0 && write_boot && (!strcmp(write_boot, "1"))) { printf("non ab for kernel 5.15 update bootloader\n"); write_bootloader(1); write_bootloader(2); env_set("write_boot", "0"); env_set("upgrade_step", "1"); run_command("saveenv", 0); if (rebootmode && (strcmp(rebootmode, "quiescent") == 0)) run_command("reboot quiescent", 0); else run_command("reboot", 0); } //check_result init checkresult = env_get("check_result"); if (checkresult == NULL) { env_set("check_result","succ"); } //reboot_status init rebootstatus = env_get("reboot_status"); if (rebootstatus == NULL) { env_set("reboot_status","reboot_init"); rebootstatus = env_get("reboot_status"); } if (rebootstatus == NULL) { printf("rebootstatus is NULL, skip check\n"); return -1; } //check reboot_end if (!strcmp(rebootstatus, "reboot_end")) { env_set("reboot_status","reboot_init"); run_command("saveenv", 0); } //get boot status run_command("amlbootsta -p -s", 0); if (has_boot_slot == 0) { //get forUpgrade_robustOta and check if support robustota robustota = env_get("forUpgrade_robustOta"); if (!robustota || !strcmp(robustota, "false")) return -1; } //get bootloader index bootloaderindex = env_get("forUpgrade_bootloaderIndex"); if (bootloaderindex == NULL) { wrnP("can not get bootloader index, so skip secure check\n"); return -1; } char *update_dts_gpt = NULL; if (write_boot && !strcmp(write_boot, "1")) { printf("need to write boot0\n"); run_command("check_uboot_state boot1", 0); rc = write_bootloader(1); if (rc) { printf("write boot0 fail, need to rollback!\n"); env_set("rollback_reason", "boot0_update_fail"); #if CONFIG_IS_ENABLED(AML_UPDATE_ENV) run_command("update_env_part -p rollback_reason;", 0); #else run_command("saveenv", 0); #endif update_rollback(); } else { update_gpt(0); printf("write boot0 success, need to reset!\n"); env_set("write_boot", "0"); env_set("reboot_status", "reboot_next"); env_set("expect_index", "1"); env_set("update_env", "1"); run_command("saveenv", 0); if (rebootmode && (strcmp(rebootmode, "quiescent") == 0)) run_command("reboot quiescent", 0); else run_command("reboot", 0); } } update_dts_gpt = env_get("update_dts_gpt"); if (has_boot_slot == 1) { if (rc == 0 && update_dts_gpt && !strcmp(update_dts_gpt, "1")) { printf("update from dts to gpt\n"); update_flag = update_gpt(1); if (update_flag != -1) { env_set("update_dts_gpt", "0"); env_set("dts_to_gpt", "1"); env_set("reboot_status", "reboot_next"); env_set("expect_index", "1"); env_set("update_env", "1"); run_command("saveenv", 0); if (rebootmode && (strcmp(rebootmode, "quiescent") == 0)) run_command("reboot quiescent", 0); else run_command("reboot", 0); } } else { printf("rebootstatus is %s\n", rebootstatus); if (rc == 0 && !strcmp(rebootstatus, "reboot_next")) { printf("update gpt\n"); update_flag = update_gpt(0); env_set("update_gpt", "0"); strcpy(write_boot, "0"); env_set("write_boot", "0"); #if CONFIG_IS_ENABLED(AML_UPDATE_ENV) run_command("update_env_part -p update_gpt;", 0); run_command("update_env_part -p write_boot;", 0); #else run_command("saveenv", 0); #endif if (update_flag != -1) { env_set("expect_index", "1"); if (gpt_flag != 0) env_set("dts_to_gpt", "1"); #if CONFIG_IS_ENABLED(AML_UPDATE_ENV) run_command("update_env_part -p expect_index;", 0); if (gpt_flag != 0) run_command("update_env_part -p dts_to_gpt;", 0); #else run_command("saveenv", 0); #endif if (rebootmode && (strcmp(rebootmode, "quiescent") == 0)) run_command("reboot quiescent", 0); else run_command("reboot", 0); } } } } #ifdef CONFIG_MMC_MESON_GX #ifdef CONFIG_CMD_BOOTCTOL_VAB if (mmc && is_android_image() && (!strcmp(rebootstatus, "reboot_next"))) { struct blk_desc *dev_desc = mmc_get_blk_desc(mmc); if (dev_desc && !strcmp(bootloaderindex, "0")) { printf("try to read gpt data from bootloader.img\n"); update_flag = update_gpt(2); if (update_flag != -1) { printf("reset......\n"); env_set("reboot_status", "reboot_next"); env_set("expect_index", "1"); env_set("update_env", "1"); #if CONFIG_IS_ENABLED(AML_UPDATE_ENV) run_command("update_env_part -p reboot_status;", 0); run_command("update_env_part -p expect_index;", 0); run_command("update_env_part -p update_env;", 0); #else run_command("saveenv", 0); #endif if (rebootmode && (strcmp(rebootmode, "quiescent") == 0)) run_command("reboot quiescent", 0); else run_command("reboot", 0); } } } #endif //unsupport update dt in boothal, update dt in uboot if (gpt_flag != 0 && !strcmp(rebootstatus, "reboot_next")) { printf("dts partition table mode, check partition changes\n"); run_command("update_dt;", 0); } char *fastboot_step = env_get("fastboot_step"); if (mmc && fastboot_step && (strcmp(fastboot_step, "1") == 0)) { printf("reboot to new bootloader burned by fastboot\n"); env_set("update_env", "1"); env_set("fastboot_step", "2"); run_command("saveenv", 0); if (rebootmode && (strcmp(rebootmode, "fastboot") == 0)) run_command("reboot next,bootloader", 0); else run_command("reboot next", 0); } if (mmc && fastboot_step && (strcmp(fastboot_step, "2") == 0 || strcmp(fastboot_step, "3") == 0)) { struct blk_desc *dev_desc = mmc_get_blk_desc(mmc); if (dev_desc && ((ret == 0 && !strcmp(bootloaderindex, "1")) || (ret != 0 && !strcmp(bootloaderindex, "0")))) { printf("new bootloader error, please fastboot to another one\n"); env_set("fastboot_step", "3"); #if CONFIG_IS_ENABLED(AML_UPDATE_ENV) run_command("update_env_part -p fastboot_step;", 0); #else run_command("defenv_reserve;setenv fastboot_step 0;saveenv;", 0); #endif run_command("run enter_fastboot", 0); } } #endif //no secure check need if (!strcmp(rebootstatus, "reboot_init")) { printf("rebootstatus is reboot_init, skip check\n"); return -1; } //get expect index expect_index = env_get("expect_index"); if (expect_index == NULL) { wrnP("can not get expect index, so skip secure check\n"); return -1; } wrnP("expect_index is : %s\n", expect_index); match_flag = strcmp(bootloaderindex, expect_index); //ignore reboot next check if power off during reboot next to finish if (rebootmode && (strcmp(rebootmode, "cold_boot") == 0)) { if (!strcmp(rebootstatus, "reboot_finish")) { match_flag = 0; } } //first reboot, command from recovery, need reboot next if (!strcmp(rebootstatus,"reboot_next")) { wrnP("--secure check reboot_next---\n"); //bootloader index, expect == current, no need reboot next if (match_flag == 0) { wrnP("current index is expect, no need reboot next, run cache recovery\n"); env_set("reboot_status", "reboot_init"); #if CONFIG_IS_ENABLED(AML_UPDATE_ENV) run_command("update_env_part -p reboot_status;", 0); #else run_command("saveenv", 0); #endif if (has_boot_slot == 1) { wrnP("ab mode\n"); } else { run_recovery_from_cache(); return 0; } } else { wrnP("now ready start reboot next\n"); if (has_boot_slot == 1) { #ifdef CONFIG_MMC_MESON_GX if (mmc != NULL) gpt_flag = aml_gpt_valid(mmc); #endif if (gpt_flag == 0) ret = 0; #if defined(CONFIG_EFUSE_OBJ_API) && defined(CONFIG_CMD_EFUSE) run_command("efuse_obj get FEAT_DISABLE_EMMC_USER", 0); if (*efuse_field.data == 1) ret = 0; #endif//#ifdef CONFIG_EFUSE_OBJ_API if (ret == 0) { wrnP("gpt or disable user bootloader mode, write boot1 to boot0\n"); write_bootloader_back("2", 1); #ifdef CONFIG_FASTBOOT struct misc_virtual_ab_message message; set_mergestatus_cancel(&message); #endif char *slot; slot = env_get("slot-suffixes"); if (!slot) { run_command("get_valid_slot", 0); slot = env_get("slot-suffixes"); } if (strcmp(slot, "0") == 0) { wrnP("back to slot b\n"); run_command("set_roll_flag 1", 0); run_command("set_active_slot b", 0); } else if (strcmp(slot, "1") == 0) { wrnP("back to slot a\n"); run_command("set_roll_flag 1", 0); run_command("set_active_slot a", 0); } env_set("expect_index", "1"); } else { write_bootloader_back(bootloaderindex, 0); #ifdef CONFIG_FASTBOOT struct misc_virtual_ab_message message; set_mergestatus_cancel(&message); #endif if (strcmp(bootloaderindex, "1") == 0) { wrnP("back to slot a\n"); run_command("set_roll_flag 1", 0); run_command("set_active_slot a", 0); } else if (strcmp(bootloaderindex, "2") == 0) { wrnP("back to slot b\n"); run_command("set_roll_flag 1", 0); run_command("set_active_slot b", 0); } env_set("expect_index", "0"); } env_set("update_env", "1"); env_set("reboot_status", "reboot_next"); run_command("saveenv", 0); if (rebootmode && (strcmp(rebootmode, "quiescent") == 0)) run_command("reboot quiescent", 0); else run_command("reboot", 0); } else { env_set("reboot_status","reboot_finish"); run_command("saveenv", 0); run_command("get_rebootmode", 0); run_command("if test ${reboot_mode} = quiescent; then reboot next,quiescent; else reboot next; fi;", 0); } return 0; } } else if (!strcmp(rebootstatus,"reboot_finish")) {//second reboot, reboot next from uboot wrnP("--secure check reboot_finish---\n"); env_set("reboot_status","reboot_end"); run_command("saveenv", 0); if (match_flag == 0) { wrnP("reboot next succ, bootloader secure check pass......\n"); if (has_boot_slot == 1) { printf("ab mode, default all uboot env\n"); update_env = env_get("update_env"); if (!update_env) { errorP("can not get update_env\n"); return -1; } if (strcmp(update_env, "1") == 0) { printf("ab mode, default all uboot env\n"); run_command("defenv_reserv;saveenv;", 0); run_command("run bcb_cmd", 0); env_set("update_env","0"); if (strcmp(bootloaderindex, "2") == 0) { wrnP("rom always boot as boot0--> boot1\n"); wrnP("So if boot1 is ok, write it to boot0\n"); run_command("copy_slot_bootable 2 1", 0); } run_command("saveenv", 0); } } else { run_recovery_from_cache(); return 0; } } else { //bootloader check failed, run recovery show error wrnP("reboot next fail, bootloader secure check fail(curr:%s, expect:%s)......\n",bootloaderindex, expect_index); env_set("check_result","bootloader_fail"); run_command("saveenv", 0); if (has_boot_slot == 1) { wrnP("ab mode\n"); #ifdef CONFIG_FASTBOOT struct misc_virtual_ab_message message; set_mergestatus_cancel(&message); #endif if (strcmp(bootloaderindex, "1") == 0) { wrnP("back to slot a\n"); run_command("set_roll_flag 1", 0); run_command("set_active_slot a", 0); } else if (strcmp(bootloaderindex, "2") == 0) { wrnP("back to slot b\n"); run_command("set_roll_flag 1", 0); run_command("set_active_slot b", 0); } #ifdef CONFIG_MMC_MESON_GX if (mmc != NULL) gpt_flag = aml_gpt_valid(mmc); #endif if (gpt_flag == 0) ret = 0; #if defined(CONFIG_EFUSE_OBJ_API) && defined(CONFIG_CMD_EFUSE) run_command("efuse_obj get FEAT_DISABLE_EMMC_USER", 0); if (*efuse_field.data == 1) ret = 0; #endif//#ifdef CONFIG_EFUSE_OBJ_API if (ret == 0) { wrnP("gpt or disable user bootloader mode\n"); env_set("update_env","0"); env_set("reboot_status","reboot_init"); run_command("saveenv", 0); } else { write_bootloader_back(bootloaderindex, 0); env_set("update_env","1"); env_set("reboot_status","reboot_next"); env_set("expect_index","0"); run_command("saveenv", 0); if (rebootmode && (strcmp(rebootmode, "quiescent") == 0)) run_command("reboot quiescent", 0); else run_command("reboot", 0); } } else { run_recovery_from_flash(); return 0; } } } else if (!strcmp(rebootstatus,"reboot_recovery")) { //recovery check failed, run recovery show error wrnP("--secure check reboot_recovery---\n"); env_set("reboot_status","reboot_end"); run_command("saveenv", 0); run_recovery_from_flash(); return 0; } else { env_set("check_result","succ"); } return 0; } //usb_burn check for env and display static void factory_usb_burn_status_check(void) { if (env_get_hex("usbDiskNewBoot", 0) && env_get_hex("usbDiskBootCpy", 0xff) != 0xff) { const int want_cpy = env_get_ulong("usbDiskBootCpy", 10, 0xff); const int boot_cpy = store_bootup_bootidx("bootloader"); if (want_cpy != boot_cpy) { pr_err("Fail check boot index, want %d but %d\n", want_cpy, boot_cpy); env_set_ulong("usbDiskChkOk", 0); //delete usbDiskBootCpy to avoid always enter check run_command("env set usbDiskBootCpy", 0); run_command("env set usbDiskNewBoot", 0); run_command("env default preboot; saveenv", 0); printf("USB_BURN img bootloader cannot bootup, so END upgrade\n"); return; } printf("okay check img bootloader for usb_burn\n"); printf("update env for usb_burn\n"); run_command("printenv usbDiskNewBoot sdcburncfg usbDiskUpgrade preboot", 0); run_command("defenv_reserve usbDiskNewBoot sdcburncfg usbDiskUpgrade preboot", 0); run_command("printenv usbDiskNewBoot sdcburncfg usbDiskUpgrade preboot", 0); run_command("env set usbDiskBootCpy ff", 0); run_command("env set usbDiskChkOk 1;saveenv", 0); return; } } static int do_update_uboot_env(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { const int write_boot = env_get_ulong("write_boot", 10, 0); const int update_dts_gpt = env_get_ulong("update_dts_gpt", 10, 0); //skip update env if need update bootloader if (write_boot || update_dts_gpt) { run_command("echo write_boot ${write_boot}, update_dts_gpt ${update_dts_gpt}", 0); return 0; } //default uboot env need before anyone use it //after factory reset if (env_get("default_env")) { printf("factory reset, need default all uboot env.\n"); run_command("defenv_reserv; setenv upgrade_step 2; saveenv;", 0); } //after ab update char *update_env = env_get("update_env"); if (update_env && (strcmp(update_env, "1") == 0)) { printf("ab mode, default all uboot env\n"); run_command("defenv_reserv; setenv upgrade_step 2; saveenv;", 0); } //after recovery update char *upgrade_step = env_get("upgrade_step"); if (upgrade_step && (strcmp(upgrade_step, "1") == 0)) { printf("after recovery update, need update uboot env\n"); run_command("defenv_reserv; setenv upgrade_step 2; saveenv;", 0); } factory_usb_burn_status_check(); return 0; } U_BOOT_CMD_COMPLETE( amlbootsta, 3, 0, do_get_bootloader_status, "get bootloader status in env", "[-p] print bootloader status\n" "[-s] saveenv after generate bootloader status\n", var_complete ); U_BOOT_CMD_COMPLETE( amlsecurecheck, 1, 0, do_secureboot_check, "try bootloader/dtb/recovery secure check", "" "", var_complete ); U_BOOT_CMD(aml_update_env, 1, 0, do_update_uboot_env, "aml_update_env", "\nThis command will update uboot env\n" "So you can execute command: aml_update_env" );