diff options
author | Ji Luo <ji.luo@nxp.com> | 2019-01-14 18:28:08 +0800 |
---|---|---|
committer | Ji Luo <ji.luo@nxp.com> | 2019-01-18 12:07:21 +0800 |
commit | 71562aae3b8123ccd7503e596e478951568fcd24 (patch) | |
tree | 30dd62bf0a3534a144ba5b7b8ff50a7fa3094172 /lib | |
parent | 1614541095c7e91989556b52b7d7605f7d8570af (diff) |
MA-13938 [Android] imx8q: Support dual bootloader feature
Support dual bootloader feature for imx8q which uses the
container format. Move the A/B slot select and verify to
SPL stage, the bootloader rollback index will be stored
at the last 8K bytes of eMMC rpmb storage.
Test: Boot and rbindex verify pass on imx8q.
Change-Id: I0a48210f65984a083037a0cd3f9558951029ed7d
Signed-off-by: Ji Luo <ji.luo@nxp.com>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/avb/fsl/fsl_avb_ab_flow.c | 124 | ||||
-rw-r--r-- | lib/avb/fsl/fsl_avbkey.c | 115 |
2 files changed, 180 insertions, 59 deletions
diff --git a/lib/avb/fsl/fsl_avb_ab_flow.c b/lib/avb/fsl/fsl_avb_ab_flow.c index eee630cdf4..f015bad105 100644 --- a/lib/avb/fsl/fsl_avb_ab_flow.c +++ b/lib/avb/fsl/fsl_avb_ab_flow.c @@ -63,6 +63,8 @@ bool fsl_slot_is_bootable(AvbABSlotData* slot) { #define PARTITION_BOOTLOADER "bootloader" extern int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value); +extern int mmc_load_image_parse_container(struct spl_image_info *spl_image, + struct mmc *mmc, unsigned long sector); /* Pre-declaration of h_spl_load_read(), see detail implementation in * common/spl/spl_mmc.c. @@ -164,10 +166,10 @@ int fsl_load_metadata_dual_uboot(struct blk_desc *dev_desc, printf("Can't get partition info of partition: misc\n"); return -1; } else { - read_from_partition_in_bytes( - dev_desc, &info, FSL_AB_METADATA_MISC_PARTITION_OFFSET, - sizeof(AvbABData), - (void *)ab_data, &num_bytes ); + read_from_partition_in_bytes(dev_desc, &info, + FSL_AB_METADATA_MISC_PARTITION_OFFSET, + sizeof(AvbABData), + (void *)ab_data, &num_bytes ); if (num_bytes != sizeof(AvbABData)) { printf("Error--read metadata fail!\n"); return -1; @@ -262,6 +264,119 @@ static int spl_verify_rbidx(struct mmc *mmc, AvbABSlotData *slot, } +#ifdef CONFIG_PARSE_CONTAINER +int mmc_load_image_parse_container_dual_uboot( + struct spl_image_info *spl_image, struct mmc *mmc) +{ + disk_partition_t info; + int ret = 0, n = 0; + char partition_name[PARTITION_NAME_LEN]; + struct blk_desc *dev_desc; + AvbABData ab_data, ab_data_orig; + size_t slot_index_to_boot, target_slot; + struct keyslot_package kp; + + /* Check if gpt is valid */ + dev_desc = mmc_get_blk_desc(mmc); + if (dev_desc) { + if (part_get_info(dev_desc, 1, &info)) { + printf("GPT is invalid, please flash correct GPT!\n"); + return -1; + } + } else { + printf("Get block desc fail!\n"); + return -1; + } + + /* Read RPMB keyslot package */ + read_keyslot_package(&kp); + if (strcmp(kp.magic, KEYPACK_MAGIC)) { + if (rpmbkey_is_set()) { + printf("\nFATAL - RPMB key was destroyed!\n"); + hang(); + } else + printf("keyslot package magic error, do nothing here!\n"); + } else { + /* Set power-on write protection to boot1 partition. */ + if (mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP, BOOT1_PWR_WP)) { + printf("Unable to set power-on write protection to boot1!\n"); + return -1; + } + } + /* Load AB metadata from misc partition */ + if (fsl_load_metadata_dual_uboot(dev_desc, &ab_data, + &ab_data_orig)) { + return -1; + } + + slot_index_to_boot = 2; // Means not 0 or 1 + target_slot = + (ab_data.slots[1].priority > ab_data.slots[0].priority) ? 1 : 0; + + for (n = 0; n < 2; n++) { + if (!fsl_slot_is_bootable(&ab_data.slots[target_slot])) { + target_slot = (target_slot == 1 ? 0 : 1); + continue; + } + /* Choose slot to load. */ + 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 { + ret = mmc_load_image_parse_container(spl_image, mmc, info.start); + + /* Image loaded successfully, go to verify rollback index */ + if (!ret && rpmbkey_is_set()) + 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); + } + + /* Set current slot to unbootable if load/verify fail. */ + if (ret != 0) { + printf("Load or verify bootloader%s fail, setting unbootable..\n", + slot_suffixes[target_slot]); + fsl_slot_set_unbootable(&ab_data.slots[target_slot]); + /* Switch to another slot. */ + target_slot = (target_slot == 1 ? 0 : 1); + } else { + slot_index_to_boot = target_slot; + n = 2; + } + } + + if (slot_index_to_boot == 2) { + /* No bootable slots! */ + printf("No bootable slots found.\n"); + ret = -1; + goto end; + } else if (!ab_data.slots[slot_index_to_boot].successful_boot && + (ab_data.slots[slot_index_to_boot].tries_remaining > 0)) { + ab_data.slots[slot_index_to_boot].tries_remaining -= 1; + } + printf("Booting from bootloader%s...\n", slot_suffixes[slot_index_to_boot]); + +end: + /* Save metadata if changed. */ + if (fsl_save_metadata_if_changed_dual_uboot(dev_desc, &ab_data, &ab_data_orig)) { + ret = -1; + } + + if (ret) + return -1; + else + return 0; +} +#else /* CONFIG_PARSE_CONTAINER */ int mmc_load_image_raw_sector_dual_uboot( struct spl_image_info *spl_image, struct mmc *mmc) { @@ -431,6 +546,7 @@ int spl_fit_get_rbindex(const void *fit, int images) return index; } +#endif /* CONFIG_PARSE_CONTAINER */ /* For normal build */ #elif !defined(CONFIG_SPL_BUILD) diff --git a/lib/avb/fsl/fsl_avbkey.c b/lib/avb/fsl/fsl_avbkey.c index 4ef914aa39..719ff02aac 100644 --- a/lib/avb/fsl/fsl_avbkey.c +++ b/lib/avb/fsl/fsl_avbkey.c @@ -134,6 +134,57 @@ fail: return ret; } +bool rpmbkey_is_set(void) +{ + int mmcc; + bool ret; + uint8_t *buf; + struct mmc *mmc; + char original_part; + struct blk_desc *desc = NULL; + + /* Get current mmc device. */ + mmcc = mmc_get_env_dev(); + mmc = find_mmc_device(mmcc); + if (!mmc) { + printf("error - cannot find '%d' mmc device\n", mmcc); + return false; + } + + desc = mmc_get_blk_desc(mmc); + original_part = desc->hwpart; + + /* Switch to the RPMB partition */ + if (desc->hwpart != MMC_PART_RPMB) { + if (mmc_switch_part(mmc, MMC_PART_RPMB) != 0) { + printf("ERROR - can't switch to rpmb partition \n"); + return false; + } + desc->hwpart = MMC_PART_RPMB; + } + + /* Try to read the first one block, return count '1' means the rpmb + * key has been set, otherwise means the key hasn't been set. + */ + buf = (uint8_t *)memalign(ALIGN_BYTES, desc->blksz); + if (mmc_rpmb_read(mmc, buf, 0, 1, NULL) != 1) + ret = false; + else + ret = true; + + /* return to original partition. */ + if (desc->hwpart != original_part) { + if (mmc_switch_part(mmc, original_part) != 0) + ret = false; + desc->hwpart = original_part; + } + /* remember to free the buffer */ + if (buf != NULL) + free(buf); + + return ret; +} + #ifdef CONFIG_FSL_CAAM_KB int rpmb_read(struct mmc *mmc, uint8_t *buffer, size_t num_bytes, int64_t offset) { @@ -354,7 +405,7 @@ int rpmb_init(void) { ERR("ERROR - get mmc device\n"); return -1; } - /* The bootloader rollback index is stored in the last 8 blocks of + /* The bootloader rollback index is stored in the last 8k bytes of * RPMB which is different from the rollback index for vbmeta and * ATX key versions. */ @@ -642,8 +693,8 @@ int rbkidx_erase(void) { } return 0; } -#endif /* CONFIG_FSL_CAAM_KB */ #endif /* CONFIG_IMX_TRUSTY_OS */ +#endif /* CONFIG_FSL_CAAM_KB */ #else /* AVB_RPMB */ int rbkidx_erase(void) { return 0; @@ -660,8 +711,13 @@ int check_rpmb_blob(struct mmc *mmc) read_keyslot_package(&kp); if (strcmp(kp.magic, KEYPACK_MAGIC)) { - printf("keyslot package magic error, do nothing here!\n"); - return 0; + if (rpmbkey_is_set()) { + printf("\nFATAL - RPMB key was destroyed!\n"); + hang(); + } else { + printf("keyslot package magic error, do nothing here!\n"); + return 0; + } } /* If keyslot package valid, copy it to secure memory */ fill_secure_keyslot_package(&kp); @@ -983,57 +1039,6 @@ int at_disable_vboot_unlock(void) #endif /* CONFIG_AVB_ATX */ #if defined(CONFIG_IMX_TRUSTY_OS) && !defined(CONFIG_AVB_ATX) -bool rpmbkey_is_set(void) -{ - int mmcc; - bool ret; - uint8_t *buf; - struct mmc *mmc; - char original_part; - struct blk_desc *desc = NULL; - - /* Get current mmc device. */ - mmcc = mmc_get_env_dev(); - mmc = find_mmc_device(mmcc); - if (!mmc) { - printf("error - cannot find '%d' mmc device\n", mmcc); - return false; - } - - desc = mmc_get_blk_desc(mmc); - original_part = desc->hwpart; - - /* Switch to the RPMB partition */ - if (desc->hwpart != MMC_PART_RPMB) { - if (mmc_switch_part(mmc, MMC_PART_RPMB) != 0) { - printf("ERROR - can't switch to rpmb partition \n"); - return false; - } - desc->hwpart = MMC_PART_RPMB; - } - - /* Try to read the first one block, return count '1' means the rpmb - * key has been set, otherwise means the key hasn't been set. - */ - buf = (uint8_t *)memalign(ALIGN_BYTES, desc->blksz); - if (mmc_rpmb_read(mmc, buf, 0, 1, NULL) != 1) - ret = false; - else - ret = true; - - /* return to original partition. */ - if (desc->hwpart != original_part) { - if (mmc_switch_part(mmc, original_part) != 0) - ret = false; - desc->hwpart = original_part; - } - /* remember to free the buffer */ - if (buf != NULL) - free(buf); - - return ret; -} - int do_rpmb_key_set(uint8_t *key, uint32_t key_size) { int ret = 0; |