// 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 #include #include #include #include #if defined(CONFIG_CHIP_NOCS) && defined(CONFIG_MESON_S6) #include #endif//if defined(CONFIG_CHIP_NOCS) && defined(CONFIG_MESON_S6) #if defined(CONFIG_EFUSE_OBJ_API) && defined(CONFIG_CMD_EFUSE) extern efuse_obj_field_t efuse_field; #endif//#ifdef CONFIG_EFUSE_OBJ_API int __attribute__((weak)) store_logic_read(const char *name, loff_t off, size_t size, void *buf) { return store_read(name, off, size, buf);} #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 MAX_VBMETA_SIZE (8 * 1024) #define BOOT_CTRL_MAGIC 0x42414342 /* Bootloader Control AB */ static void reboot_by_reason(unsigned int r) { struct arm_smccc_res res; arm_smccc_smc(SET_REBOOT_REASON, r, 0, 0, 0, 0, 0, 0, &res); if (res.a0) printf("failed to set reboot reason\n"); run_command("wdt dev watchdog", 0); run_command("wdt expire", 0); } //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; 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); } 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); } 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; #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"); } #if defined(CONFIG_CHIP_NOCS) && defined(CONFIG_MESON_S6) #define S6_FPK_OFFSET 0x7320 #define S6_STORAGE_BOOT_BLOB_HEADER_SIZE 4096 #define S6_BB1ST_SIZE 251360 static int nocs_read_fpk(unsigned char *fpke, unsigned int fpk_offset) { unsigned char *buffer = NULL; int capacity_boot = 0x2000 * 512; int iret = 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("nocs_read_fpk 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); iret = store_boot_read("bootloader", 1, 0, buffer); if (iret) { printf("Failed to read boot0\n"); free(buffer); buffer = NULL; return -1; } memcpy(fpke, &buffer[fpk_offset], 16); printf("FPKE from boot0: "); for (int i = 0; i < 16; i++) { printf(" %02x", fpke[i]); } printf("\n"); free(buffer); buffer = NULL; return 0; } static void update_fpk_for_nocs(unsigned char *buffer, unsigned int fpk_offset, unsigned int bb1st_size, unsigned int storage_boot_blob_size) { unsigned char sha256_data[32]; unsigned char fpke[16] = {0}; if ((fpk_offset + 16) > BOOTLOADER_MAX_SIZE - BOOTLOADER_OFFSET) { printf("fpk_offset is invalid 0x%x \n", fpk_offset); return; } if ((bb1st_size + storage_boot_blob_size) > BOOTLOADER_MAX_SIZE - BOOTLOADER_OFFSET) { printf("bb1st_size 0x%x and storage_boot_blob_size 0x%x are invalid \n", bb1st_size, storage_boot_blob_size); return ; } if (nocs_read_fpk(fpke, fpk_offset) != 0) { printf("ERROR! nocs_read_fpk failed...\n"); return; } memcpy(&buffer[fpk_offset], fpke, 16); /* update the 1st blob's hash */ sha256_csum_wd(&buffer[storage_boot_blob_size], bb1st_size - 32, sha256_data, CHUNKSZ_SHA256); printf("new hash for boot0: "); for (int i = 0; i < 32; i++) { printf(" %02x", sha256_data[i]); } printf("\n"); memcpy(&buffer[bb1st_size + storage_boot_blob_size - 32], sha256_data, 32); return; } #endif//#if defined(CONFIG_CHIP_NOCS) && defined(CONFIG_MESON_S6) 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; } #ifdef CONFIG_MESON_S7D iret = update_boot_hdr_4_s7d_reva(buffer, BOOTLOADER_MAX_SIZE - BOOTLOADER_OFFSET, 0); if (iret) { printf("Failed to write s7d reva boot0\n"); free(buffer); return -1; } #endif//#ifdef CONFIG_MESON_S7D #if defined(CONFIG_CHIP_NOCS) && defined(CONFIG_MESON_S6) update_fpk_for_nocs(buffer, S6_FPK_OFFSET, S6_BB1ST_SIZE, S6_STORAGE_BOOT_BLOB_HEADER_SIZE); #endif//#if defined(CONFIG_CHIP_NOCS) && defined(CONFIG_MESON_S6) 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; } /** *set merge status */ int set_mergestatus_cancel(struct misc_virtual_ab_message *message) { char *partition = "misc"; char vab_buf[1024] = {0}; if (store_read((const char *)partition, SYSTEM_SPACE_OFFSET_IN_MISC, 1024, (unsigned char *)vab_buf) < 0) { printf("failed to store read %s.\n", partition); return -1; } memcpy(message, vab_buf, sizeof(struct misc_virtual_ab_message)); printf("message.merge_status: %d\n", message->merge_status); if (message->merge_status == SNAPSHOTTED || message->merge_status == MERGING) { message->merge_status = CANCELLED; printf("set message.merge_status CANCELLED\n"); } store_write((const char *)partition, SYSTEM_SPACE_OFFSET_IN_MISC, 1024, (unsigned char *)vab_buf); return 0; } char *get_vbmeta_slot(void) { char *partition = "misc"; struct bootloader_control boot_ctrl; char vab_buf[64] = {0}; if (store_read((const char *)partition, 2048, 32, (unsigned char *)vab_buf) < 0) { printf("failed to store read %s.\n", partition); return "_a"; } memcpy(&boot_ctrl, vab_buf, sizeof(struct bootloader_control)); if (boot_ctrl.magic != BOOT_CTRL_MAGIC) { //first bootup default slot a return "_a"; } if (boot_ctrl.slot_info[0].priority > boot_ctrl.slot_info[1].priority) return "_a"; else return "_b"; } // according to the value of the board, // reset the product to set the serial // to distinguish different products. void set_product(void) { char *board = env_get("board"); char *str = NULL; char *dup_str = NULL; str = strstr(board, "_"); if (!str) { env_set("product", board); return; } dup_str = strdup(str); if (!(strstr(dup_str, "_"))) env_set("product", str + 1); else env_set("product", strtok(str, "_")); free(dup_str); return; } void fastboot_step_check(char *rebootmode, int gpt_flag) { char *bootloaderindex = NULL; struct mmc *mmc = NULL; if (store_get_type() == BOOT_EMMC) mmc = find_mmc_device(1); //get bootloader index bootloaderindex = env_get("forUpgrade_bootloaderIndex"); if (!bootloaderindex) { wrnP("can not get bootloader index, so skip fastboot step check\n"); return; } 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)) { struct blk_desc *dev_desc = mmc_get_blk_desc(mmc); if (dev_desc && ((gpt_flag == 1 && !strcmp(bootloaderindex, "1")) || (gpt_flag == 0 && !strcmp(bootloaderindex, "0")))) { printf("new bootloader error, please fastboot to another one\n"); env_set("fastboot_step", "0"); 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); cli_init(); cli_loop(); } } } 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; if (store_get_type() == BOOT_EMMC) mmc = find_mmc_device(1); if (mmc) capacity_boot = mmc->capacity_boot; 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); 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 + 0x3DFE00)) { printf("printf normal bootloader.img, no gpt partition table\n"); ret = -1; goto exit; } else { erase_flag = check_gpt_change(dev_desc, buffer + 0x3DFE00); if (erase_flag == 4 && has_boot_slot == 0) { printf("null ab critical partition change, refused to upgrade\n"); ret = -1; 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 exit; } 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 } if (write_mbr_and_gpt_partitions(dev_desc, buffer + 0x3DFE00)) { 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; } printf("%s: writing GPT partitions ok\n", __func__); } } 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; } } 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) { if (IS_ENABLED(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 = NULL; 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); } return 0; } //add non ab recovery update flow here int non_ab_update(char *rebootmode) { int match_flag = 0; char *rebootstatus = NULL; char *checkresult = NULL; char *bootloaderindex = NULL; char *expect_index = NULL; char *robustota = NULL; char *write_boot = env_get("write_boot"); recovery_update(); if (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) env_set("check_result", "succ"); //reboot_status init rebootstatus = env_get("reboot_status"); if (!rebootstatus) { env_set("reboot_status", "reboot_init"); rebootstatus = env_get("reboot_status"); } if (!rebootstatus) { 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 forUpgrade_robustOta and check if support robustota robustota = env_get("forUpgrade_robustOta"); if (!robustota || !strcmp(robustota, "false")) return -1; //no secure check need if (!strcmp(rebootstatus, "reboot_init")) { printf("rebootstatus is reboot_init, skip check\n"); return -1; } //get bootloader index bootloaderindex = env_get("forUpgrade_bootloaderIndex"); if (!bootloaderindex) { wrnP("can not get bootloader index, so skip secure check\n"); return -1; } //get expect index expect_index = env_get("expect_index"); if (!expect_index) { 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; } if (!strcmp(rebootstatus, "reboot_next")) { env_set("reboot_status", "reboot_finish"); run_command("saveenv", 0); run_command("get_rebootmode", 0); if (rebootmode && (strcmp(rebootmode, "quiescent") == 0)) run_command("reboot next,quiescent", 0); else run_command("reboot next", 0); } else if (!strcmp(rebootstatus, "reboot_finish")) { 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"); } 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); } run_recovery_from_flash(); return 0; } else { env_set("check_result", "succ"); } return 0; } //add ab update and ab rollback flow here int ab_update_rollback(char *rebootmode, int gpt_flag) { int match_flag = 0; char *rebootstatus = NULL; char *bootloaderindex = NULL; char *expect_index = NULL; //update bootloader_a/b/up to boot0 char *write_boot = env_get("write_boot"); if (write_boot && !strcmp(write_boot, "1")) { printf("need to write boot0\n"); run_command("check_uboot_state boot1", 0); if (write_bootloader(1)) { 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)) reboot_by_reason(AMLOGIC_QUIESCENT_REBOOT); else reboot_by_reason(AMLOGIC_NORMAL_BOOT); } //check rescueparty and rollback 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 (gpt_flag == 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 (gpt_flag == 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)) reboot_by_reason(AMLOGIC_QUIESCENT_REBOOT); else reboot_by_reason(AMLOGIC_NORMAL_BOOT); } //get bootloader index bootloaderindex = env_get("forUpgrade_bootloaderIndex"); if (bootloaderindex == NULL) { wrnP("can not get bootloader index, so skip secure 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); rebootstatus = env_get("reboot_status"); //if reboot next need check bootloader rollback if (rebootstatus && !strcmp(rebootstatus, "reboot_next")) { wrnP("--secure check reboot_next---\n"); //bootloader index, expect == current, no need reboot next if (match_flag != 0) { wrnP("bootloader wrong, start rollback\n"); if (gpt_flag == 1) { 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)) reboot_by_reason(AMLOGIC_QUIESCENT_REBOOT); else reboot_by_reason(AMLOGIC_NORMAL_BOOT); return 0; }else { wrnP("current index is expect, no need reboot next, set reboot_status reboot_init\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 (CONFIG_IS_ENABLED(AML_OTA_ERASE_DDR_PARAMETER)) { run_command("echo erase ddr-parameter for OTA", 0); run_command("store rsv erase ddr-parameter;reboot", 0); } } } return 0; } static int build_userdebug(void) { 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 }; 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 0; } 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; } static int do_secureboot_check(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { char *rebootmode = NULL; int gpt_flag = 0; int ret = -1; // set product first to set serial. set_product(); #ifdef CONFIG_MMC_MESON_GX struct mmc *mmc = NULL; //int capacity_boot = 0; if (store_get_type() == BOOT_EMMC) { mmc = find_mmc_device(1); if (mmc) ret = aml_gpt_valid(mmc); } #endif //check is gpt mode if (ret == 0) gpt_flag = 1; //unsupport update dt in boothal, update dt in uboot run_command("update_dt;", 0); bootloader_wp(); //set default env before check env_set("recovery_mode", "false"); //if recovery mode, need disable dv, if factoryreset, need default uboot env aml_recovery(); #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"); env_set("nocs_mode", "true"); gpt_flag = 1; } 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); //get boot status run_command("amlbootsta -p -s", 0); if (IS_ENABLED(CONFIG_MMC_MESON_GX)) fastboot_step_check(rebootmode, gpt_flag); if (has_boot_slot == 1) ab_update_rollback(rebootmode, gpt_flag); else non_ab_update(rebootmode); 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[]) { char *silent_build = NULL; int userdebug = 0; 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); } silent_build = env_get("silent_build"); if (silent_build && !strcmp(silent_build, "1")) { userdebug = build_userdebug(); if (!userdebug) { run_command("setenv silent 1", 0); env_set("loglevel", "2"); } } 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" );