diff options
author | Ji Luo <ji.luo@nxp.com> | 2019-07-18 13:56:45 +0800 |
---|---|---|
committer | Ji Luo <ji.luo@nxp.com> | 2019-07-19 13:14:15 +0800 |
commit | 2a43c3e702720fab67ae9af73634a958a1b62044 (patch) | |
tree | 0399901533ba4e194f3d89235496e04082da32cf /lib | |
parent | 3f94cf98113af6c31e146afcf394f34ff4d2bc00 (diff) |
MA-15158 Set spl recovery mode for dual bootloader
The A/B slot selection is moved to spl, it may lead to hang
if no bootable slots found. The only way to recover the board
is re-flash images with uuu tool, which is quite inconvenient
for some customers who can't enter serial download mode.
This patch will set "spl recovery mode" which will give us a
chance to re-flash images with fastboot commands.
Test: Enter spl recovery mode and flash images when no bootable
slots found.
Change-Id: I31278f5212bde7609fe2f49e77b3849e92c0c516
Signed-off-by: Ji Luo <ji.luo@nxp.com>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/avb/fsl/fsl_avb_ab_flow.c | 138 | ||||
-rw-r--r-- | lib/avb/libavb_ab/avb_ab_flow.h | 8 |
2 files changed, 137 insertions, 9 deletions
diff --git a/lib/avb/fsl/fsl_avb_ab_flow.c b/lib/avb/fsl/fsl_avb_ab_flow.c index 0dc6850434..446d650692 100644 --- a/lib/avb/fsl/fsl_avb_ab_flow.c +++ b/lib/avb/fsl/fsl_avb_ab_flow.c @@ -375,16 +375,50 @@ int mmc_load_image_parse_container_dual_uboot( } if (slot_index_to_boot == 2) { - /* No bootable slots! */ - printf("No bootable slots found.\n"); - ret = -1; - goto end; + /* No bootable slots, try to boot into recovery! */ + printf("No bootable slots found, try to boot into recovery mode...\n"); + + ab_data.spl_recovery = true; + if ((ab_data.last_boot != 0) && (ab_data.last_boot != 1)) + slot_index_to_boot = 0; + else + slot_index_to_boot = ab_data.last_boot; + + snprintf(partition_name, PARTITION_NAME_LEN, + PARTITION_BOOTLOADER"%s", + slot_suffixes[slot_index_to_boot]); + + /* Read part info from gpt */ + if (part_get_info_by_name(dev_desc, partition_name, &info) == -1) { + printf("Can't get partition info of partition bootloader%s\n", + slot_suffixes[slot_index_to_boot]); + ret = -1; + goto end; + } else { + ret = mmc_load_image_parse_container(spl_image, mmc, info.start); + + /* Don't need to check rollback index for xen. */ +#ifndef CONFIG_XEN + /* Image loaded successfully, go to verify rollback index */ + if (!ret && rpmbkey_is_set()) + ret = spl_verify_rbidx(mmc, &ab_data.slots[slot_index_to_boot], spl_image); + + /* Copy rpmb keyslot to secure memory. */ + if (!ret) + fill_secure_keyslot_package(&kp); +#endif + } + + if (ret) + goto end; } else if (!ab_data.slots[slot_index_to_boot].successful_boot && (ab_data.slots[slot_index_to_boot].tries_remaining > 0)) { /* Set the bootloader_verified flag if current slot only has one chance. */ if (ab_data.slots[slot_index_to_boot].tries_remaining == 1) ab_data.slots[slot_index_to_boot].bootloader_verified = 1; ab_data.slots[slot_index_to_boot].tries_remaining -= 1; + + ab_data.last_boot = slot_index_to_boot; } printf("Booting from bootloader%s...\n", slot_suffixes[slot_index_to_boot]); @@ -517,16 +551,72 @@ int mmc_load_image_raw_sector_dual_uboot( } if (slot_index_to_boot == 2) { - /* No bootable slots! */ - printf("No bootable slots found.\n"); - ret = -1; - goto end; + /* No bootable slots, try to boot into recovery! */ + printf("No bootable slots found, try to boot into recovery mode...\n"); + + ab_data.spl_recovery = true; + if ((ab_data.last_boot != 0) && (ab_data.last_boot != 1)) + slot_index_to_boot = 0; + else + slot_index_to_boot = ab_data.last_boot; + + snprintf(partition_name, PARTITION_NAME_LEN, + PARTITION_BOOTLOADER"%s", + slot_suffixes[target_slot]); + + /* Read part info from gpt */ + if (part_get_info_by_name(dev_desc, partition_name, &info) == -1) { + printf("Can't get partition info of partition bootloader%s\n", + slot_suffixes[target_slot]); + ret = -1; + goto end; + } else { + header = (struct image_header *)(CONFIG_SYS_TEXT_BASE - + sizeof(struct image_header)); + + /* read image header to find the image size & load address */ + count = blk_dread(dev_desc, info.start, 1, header); + if (count == 0) { + ret = -1; + goto end; + } + + /* Load fit and check HAB */ + if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) && + image_get_magic(header) == FDT_MAGIC) { + struct spl_load_info load; + + debug("Found FIT\n"); + load.dev = mmc; + load.priv = NULL; + load.filename = NULL; + load.bl_len = mmc->read_bl_len; + load.read = h_spl_load_read; + ret = spl_load_simple_fit(spl_image, &load, + info.start, header); + } else { + ret = -1; + } + + /* Fit image loaded successfully, go to verify rollback index */ + if (!ret) + ret = spl_verify_rbidx(mmc, &ab_data.slots[target_slot], spl_image); + + /* Copy rpmb keyslot to secure memory. */ + if (!ret) + fill_secure_keyslot_package(&kp); + } + + if (ret) + goto end; } else if (!ab_data.slots[slot_index_to_boot].successful_boot && (ab_data.slots[slot_index_to_boot].tries_remaining > 0)) { /* Set the bootloader_verified flag as if current slot only has one chance. */ if (ab_data.slots[slot_index_to_boot].tries_remaining == 1) ab_data.slots[slot_index_to_boot].bootloader_verified = 1; ab_data.slots[slot_index_to_boot].tries_remaining -= 1; + + ab_data.last_boot = slot_index_to_boot; } printf("Booting from bootloader%s...\n", slot_suffixes[slot_index_to_boot]); @@ -801,6 +891,38 @@ out: return ret; } + +extern AvbABOps fsl_avb_ab_ops; +static bool spl_recovery_flag = false; +bool is_spl_recovery(void) +{ + return spl_recovery_flag; +} +void check_spl_recovery(void) +{ + AvbABData ab_data, ab_data_orig; + AvbIOResult io_ret; + + io_ret = fsl_load_metadata(&fsl_avb_ab_ops, &ab_data, &ab_data_orig); + if (io_ret != AVB_IO_RESULT_OK) { + printf("Load metadata fail, go to fail!\n"); + hang(); + } + + spl_recovery_flag = ab_data.spl_recovery; + /* Clear spl recovery flag. */ + ab_data.spl_recovery = false; + fsl_save_metadata_if_changed(&fsl_avb_ab_ops, &ab_data, &ab_data_orig); + + if (spl_recovery_flag) { + printf("Enter spl recovery mode, only fastboot commands are supported!\n"); + + while (1) { + run_command("fastboot 0", 0); + } + } +} + #else /* CONFIG_DUAL_BOOTLOADER */ /* For legacy i.mx6/7, we won't enable A/B due to the limitation of * storage capacity, but we still want to verify boot/recovery with diff --git a/lib/avb/libavb_ab/avb_ab_flow.h b/lib/avb/libavb_ab/avb_ab_flow.h index 3757ba26ac..1e09d398f2 100644 --- a/lib/avb/libavb_ab/avb_ab_flow.h +++ b/lib/avb/libavb_ab/avb_ab_flow.h @@ -93,8 +93,14 @@ typedef struct AvbABData { /* Per-slot metadata. */ AvbABSlotData slots[2]; + /* Last boot slot */ + uint8_t last_boot; + + /* spl recovery mode */ + bool spl_recovery; + /* Reserved for future use. */ - uint8_t reserved2[12]; + uint8_t reserved2[10]; /* CRC32 of all 28 bytes preceding this field. */ uint32_t crc32; |