Message ID | 20211219070605.14894-3-sughosh.ganu@linaro.org |
---|---|
State | New |
Headers | show |
Series | FWU: Add support for FWU Multi Bank Update feature | expand |
Hi Sughosh, 2021年12月19日(日) 16:06 Sughosh Ganu <sughosh.ganu@linaro.org>: > +static int gpt_get_image_alt_num(struct blk_desc *desc, > + efi_guid_t image_type_id, > + u32 update_bank, int *alt_no) > +{ > + int ret, i; > + u32 part; > + struct fwu_mdata *mdata; > + struct fwu_image_entry *img_entry; > + struct fwu_image_bank_info *img_bank_info; > + struct disk_partition info; > + efi_guid_t unique_part_guid; > + efi_guid_t image_guid = NULL_GUID; > + > + ret = gpt_get_mdata(&mdata); > + if (ret < 0) { > + log_err("Unable to read valid FWU metadata\n"); > + goto out; > + } > + > + /* > + * The FWU metadata has been read. Now get the image_uuid for the > + * image with the update_bank. > + */ > + for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; i++) { > + if (!guidcmp(&image_type_id, > + &mdata->img_entry[i].image_type_uuid)) { > + img_entry = &mdata->img_entry[i]; > + img_bank_info = &img_entry->img_bank_info[update_bank]; > + guidcpy(&image_guid, &img_bank_info->image_uuid); > + break; > + } > + } > + > + /* > + * Now read the GPT Partition Table Entries to find a matching > + * partition with UniquePartitionGuid value. We need to iterate > + * through all the GPT partitions since they might be in any > + * order > + */ > + for (i = 1; i < MAX_SEARCH_PARTITIONS; i++) { > + if (part_get_info(desc, i, &info)) > + continue; > + uuid_str_to_bin(info.uuid, unique_part_guid.b, > + UUID_STR_FORMAT_GUID); > + > + if (!guidcmp(&unique_part_guid, &image_guid)) { > + /* Found the partition */ > + part = i; > + *alt_no = fwu_plat_get_alt_num(desc->devnum, &part); This is still GPT depending interface. In my use case (no GPT but raw SPI flash) I don't have devnum. Moreover, this one is used only from the fwu_mdata_gpt_blk.c. Please ensure (and comment) that this is only for GPT user. > + if (*alt_no != -1) > + log_info("alt_num %d for partition %pUl\n", > + *alt_no, &image_guid); > + ret = 0; > + break; > + } > + } > + > + if (*alt_no == -1) { > + log_err("alt_num not found for partition with GUID %pUl\n", > + &image_guid); > + ret = -EINVAL; > + } > + > + if (i == MAX_SEARCH_PARTITIONS) { > + log_err("Partition with the image guid not found\n"); > + ret = -EINVAL; > + } > + > +out: > + free(mdata); > + > + return ret; > +} > + > +int fwu_gpt_update_active_index(u32 active_idx) > +{ > + int ret; > + void *buf; > + struct fwu_mdata *mdata; > + > + if (active_idx > CONFIG_FWU_NUM_BANKS) { > + printf("Active index value to be updated is incorrect\n"); > + return -1; > + } > + > + ret = gpt_get_mdata(&mdata); > + if (ret < 0) { > + log_err("Unable to get valid FWU metadata\n"); > + goto out; > + } > + > + /* > + * Update the active index and previous_active_index fields > + * in the FWU metadata > + */ > + mdata->previous_active_index = mdata->active_index; > + mdata->active_index = active_idx; > + > + > + /* > + * Calculate the crc32 for the updated FWU metadata > + * and put the updated value in the FWU metadata crc32 > + * field > + */ > + buf = &mdata->version; > + mdata->crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32)); > + > + /* > + * Now write this updated FWU metadata to both the > + * FWU metadata partitions > + */ > + ret = gpt_update_mdata(mdata); > + if (ret < 0) { > + log_err("Failed to update FWU metadata partitions\n"); > + ret = -EIO; > + } > + > +out: > + free(mdata); > + > + return ret; > +} > + > +int fwu_gpt_get_image_alt_num(efi_guid_t image_type_id, u32 update_bank, > + int *alt_no) > +{ > + int ret; > + struct blk_desc *desc; > + > + ret = fwu_plat_get_blk_desc(&desc); > + if (ret < 0) { > + log_err("Block device not found\n"); > + return -ENODEV; > + } > + > + return gpt_get_image_alt_num(desc, image_type_id, update_bank, alt_no); > +} > + > +int fwu_gpt_mdata_check(void) > +{ > + /* > + * Check if both the copies of the FWU metadata are > + * valid. If one has gone bad, restore it from the > + * other good copy. > + */ > + return gpt_check_mdata_validity(); > +} > + > +int fwu_gpt_get_mdata(struct fwu_mdata **mdata) > +{ > + return gpt_get_mdata(mdata); > +} > + > +int fwu_gpt_revert_boot_index(void) > +{ > + int ret; > + void *buf; > + u32 cur_active_index; > + struct fwu_mdata *mdata; > + > + ret = gpt_get_mdata(&mdata); > + if (ret < 0) { > + log_err("Unable to get valid FWU metadata\n"); > + goto out; > + } > + > + /* > + * Swap the active index and previous_active_index fields > + * in the FWU metadata > + */ > + cur_active_index = mdata->active_index; > + mdata->active_index = mdata->previous_active_index; > + mdata->previous_active_index = cur_active_index; > + > + /* > + * Calculate the crc32 for the updated FWU metadata > + * and put the updated value in the FWU metadata crc32 > + * field > + */ > + buf = &mdata->version; > + mdata->crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32)); > + > + /* > + * Now write this updated FWU metadata to both the > + * FWU metadata partitions > + */ > + ret = gpt_update_mdata(mdata); If we have the fwu_update_mdata(), you can make this fwu_gpt_revert_boot_index() and above fwu_gpt_update_boot_index() platform agnostic. (in that case "gpt" must be removed), because there is no dependency to GPT. > + if (ret < 0) { > + log_err("Failed to update FWU metadata partitions\n"); > + ret = -EIO; > + } > + > +out: > + free(mdata); > + > + return ret; > +} > + > +static int fwu_gpt_set_clear_image_accept(efi_guid_t *img_type_id, > + u32 bank, u8 action) > +{ > + void *buf; > + int ret, i; > + u32 nimages; > + struct fwu_mdata *mdata; > + struct fwu_image_entry *img_entry; > + struct fwu_image_bank_info *img_bank_info; > + > + ret = gpt_get_mdata(&mdata); > + if (ret < 0) { > + log_err("Unable to get valid FWU metadata\n"); > + goto out; > + } > + > + if (action == IMAGE_ACCEPT_SET) > + bank = mdata->active_index; > + > + nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK; > + img_entry = &mdata->img_entry[0]; > + for (i = 0; i < nimages; i++) { > + if (!guidcmp(&img_entry[i].image_type_uuid, img_type_id)) { > + img_bank_info = &img_entry[i].img_bank_info[bank]; > + if (action == IMAGE_ACCEPT_SET) > + img_bank_info->accepted |= FWU_IMAGE_ACCEPTED; > + else > + img_bank_info->accepted = 0; > + > + buf = &mdata->version; > + mdata->crc32 = crc32(0, buf, sizeof(*mdata) - > + sizeof(u32)); > + > + ret = gpt_update_mdata(mdata); This function is also doing the generic things. Only gpt_update_mdata() is the barrier. I would like to suggest you to add ".update_mdata" member to the fwu_mdata_ops. Thank you, > + goto out; > + } > + } > + > + /* Image not found */ > + ret = -EINVAL; > + > +out: > + free(mdata); > + > + return ret; > +} > + > +int fwu_gpt_accept_image(efi_guid_t *img_type_id) > +{ > + return fwu_gpt_set_clear_image_accept(img_type_id, 0, > + IMAGE_ACCEPT_SET); > +} > + > +int fwu_gpt_clear_accept_image(efi_guid_t *img_type_id, u32 bank) > +{ > + return fwu_gpt_set_clear_image_accept(img_type_id, bank, > + IMAGE_ACCEPT_CLEAR); > +} > + > +struct fwu_mdata_ops fwu_gpt_blk_ops = { > + .get_active_index = fwu_gpt_get_active_index, > + .update_active_index = fwu_gpt_update_active_index, > + .get_image_alt_num = fwu_gpt_get_image_alt_num, > + .mdata_check = fwu_gpt_mdata_check, > + .revert_boot_index = fwu_gpt_revert_boot_index, > + .set_accept_image = fwu_gpt_accept_image, > + .clear_accept_image = fwu_gpt_clear_accept_image, > + .get_mdata = fwu_gpt_get_mdata, > +}; > -- > 2.17.1 >
hi Masami, On Fri, 24 Dec 2021 at 15:29, Masami Hiramatsu <masami.hiramatsu@linaro.org> wrote: > > Hi Sughosh, > > 2021年12月19日(日) 16:06 Sughosh Ganu <sughosh.ganu@linaro.org>: > > > +static int gpt_get_image_alt_num(struct blk_desc *desc, > > + efi_guid_t image_type_id, > > + u32 update_bank, int *alt_no) > > +{ > > + int ret, i; > > + u32 part; > > + struct fwu_mdata *mdata; > > + struct fwu_image_entry *img_entry; > > + struct fwu_image_bank_info *img_bank_info; > > + struct disk_partition info; > > + efi_guid_t unique_part_guid; > > + efi_guid_t image_guid = NULL_GUID; > > + > > + ret = gpt_get_mdata(&mdata); > > + if (ret < 0) { > > + log_err("Unable to read valid FWU metadata\n"); > > + goto out; > > + } > > + > > + /* > > + * The FWU metadata has been read. Now get the image_uuid for the > > + * image with the update_bank. > > + */ > > + for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; i++) { > > + if (!guidcmp(&image_type_id, > > + &mdata->img_entry[i].image_type_uuid)) { > > + img_entry = &mdata->img_entry[i]; > > + img_bank_info = &img_entry->img_bank_info[update_bank]; > > + guidcpy(&image_guid, &img_bank_info->image_uuid); > > + break; > > + } > > + } > > + > > + /* > > + * Now read the GPT Partition Table Entries to find a matching > > + * partition with UniquePartitionGuid value. We need to iterate > > + * through all the GPT partitions since they might be in any > > + * order > > + */ > > + for (i = 1; i < MAX_SEARCH_PARTITIONS; i++) { > > + if (part_get_info(desc, i, &info)) > > + continue; > > + uuid_str_to_bin(info.uuid, unique_part_guid.b, > > + UUID_STR_FORMAT_GUID); > > + > > + if (!guidcmp(&unique_part_guid, &image_guid)) { > > + /* Found the partition */ > > + part = i; > > + *alt_no = fwu_plat_get_alt_num(desc->devnum, &part); > > This is still GPT depending interface. In my use case (no GPT but raw SPI flash) > I don't have devnum. Moreover, this one is used only from the > fwu_mdata_gpt_blk.c. You are right. I will change this api to not have the first parameter. The function will then pass only the identifier which is a void *. > Please ensure (and comment) that this is only for GPT user. > > > + if (*alt_no != -1) > > + log_info("alt_num %d for partition %pUl\n", > > + *alt_no, &image_guid); > > + ret = 0; > > + break; > > + } > > + } > > + > > + if (*alt_no == -1) { > > + log_err("alt_num not found for partition with GUID %pUl\n", > > + &image_guid); > > + ret = -EINVAL; > > + } > > + > > + if (i == MAX_SEARCH_PARTITIONS) { > > + log_err("Partition with the image guid not found\n"); > > + ret = -EINVAL; > > + } > > + > > +out: > > + free(mdata); > > + > > + return ret; > > +} > > + > > +int fwu_gpt_update_active_index(u32 active_idx) > > +{ > > + int ret; > > + void *buf; > > + struct fwu_mdata *mdata; > > + > > + if (active_idx > CONFIG_FWU_NUM_BANKS) { > > + printf("Active index value to be updated is incorrect\n"); > > + return -1; > > + } > > + > > + ret = gpt_get_mdata(&mdata); > > + if (ret < 0) { > > + log_err("Unable to get valid FWU metadata\n"); > > + goto out; > > + } > > + > > + /* > > + * Update the active index and previous_active_index fields > > + * in the FWU metadata > > + */ > > + mdata->previous_active_index = mdata->active_index; > > + mdata->active_index = active_idx; > > + > > + > > + /* > > + * Calculate the crc32 for the updated FWU metadata > > + * and put the updated value in the FWU metadata crc32 > > + * field > > + */ > > + buf = &mdata->version; > > + mdata->crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32)); > > + > > + /* > > + * Now write this updated FWU metadata to both the > > + * FWU metadata partitions > > + */ > > + ret = gpt_update_mdata(mdata); > > + if (ret < 0) { > > + log_err("Failed to update FWU metadata partitions\n"); > > + ret = -EIO; > > + } > > + > > +out: > > + free(mdata); > > + > > + return ret; > > +} > > + > > +int fwu_gpt_get_image_alt_num(efi_guid_t image_type_id, u32 update_bank, > > + int *alt_no) > > +{ > > + int ret; > > + struct blk_desc *desc; > > + > > + ret = fwu_plat_get_blk_desc(&desc); > > + if (ret < 0) { > > + log_err("Block device not found\n"); > > + return -ENODEV; > > + } > > + > > + return gpt_get_image_alt_num(desc, image_type_id, update_bank, alt_no); > > +} > > + > > +int fwu_gpt_mdata_check(void) > > +{ > > + /* > > + * Check if both the copies of the FWU metadata are > > + * valid. If one has gone bad, restore it from the > > + * other good copy. > > + */ > > + return gpt_check_mdata_validity(); > > +} > > + > > +int fwu_gpt_get_mdata(struct fwu_mdata **mdata) > > +{ > > + return gpt_get_mdata(mdata); > > +} > > + > > +int fwu_gpt_revert_boot_index(void) > > +{ > > + int ret; > > + void *buf; > > + u32 cur_active_index; > > + struct fwu_mdata *mdata; > > + > > + ret = gpt_get_mdata(&mdata); > > + if (ret < 0) { > > + log_err("Unable to get valid FWU metadata\n"); > > + goto out; > > + } > > + > > + /* > > + * Swap the active index and previous_active_index fields > > + * in the FWU metadata > > + */ > > + cur_active_index = mdata->active_index; > > + mdata->active_index = mdata->previous_active_index; > > + mdata->previous_active_index = cur_active_index; > > + > > + /* > > + * Calculate the crc32 for the updated FWU metadata > > + * and put the updated value in the FWU metadata crc32 > > + * field > > + */ > > + buf = &mdata->version; > > + mdata->crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32)); > > + > > + /* > > + * Now write this updated FWU metadata to both the > > + * FWU metadata partitions > > + */ > > + ret = gpt_update_mdata(mdata); > > If we have the fwu_update_mdata(), you can make this fwu_gpt_revert_boot_index() > and above fwu_gpt_update_boot_index() platform agnostic. (in that case > "gpt" must > be removed), because there is no dependency to GPT. Okay. I believe you are suggesting having a GPT specific implementation only for fwu_update_mdata, and move fwu_gpt_revert_boot_index and fwu_gpt_update_active_index as common functions with appropriate renaming. I can do that. -sughosh > > > + if (ret < 0) { > > + log_err("Failed to update FWU metadata partitions\n"); > > + ret = -EIO; > > + } > > + > > +out: > > + free(mdata); > > + > > + return ret; > > +} > > + > > +static int fwu_gpt_set_clear_image_accept(efi_guid_t *img_type_id, > > + u32 bank, u8 action) > > +{ > > + void *buf; > > + int ret, i; > > + u32 nimages; > > + struct fwu_mdata *mdata; > > + struct fwu_image_entry *img_entry; > > + struct fwu_image_bank_info *img_bank_info; > > + > > + ret = gpt_get_mdata(&mdata); > > + if (ret < 0) { > > + log_err("Unable to get valid FWU metadata\n"); > > + goto out; > > + } > > + > > + if (action == IMAGE_ACCEPT_SET) > > + bank = mdata->active_index; > > + > > + nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK; > > + img_entry = &mdata->img_entry[0]; > > + for (i = 0; i < nimages; i++) { > > + if (!guidcmp(&img_entry[i].image_type_uuid, img_type_id)) { > > + img_bank_info = &img_entry[i].img_bank_info[bank]; > > + if (action == IMAGE_ACCEPT_SET) > > + img_bank_info->accepted |= FWU_IMAGE_ACCEPTED; > > + else > > + img_bank_info->accepted = 0; > > + > > + buf = &mdata->version; > > + mdata->crc32 = crc32(0, buf, sizeof(*mdata) - > > + sizeof(u32)); > > + > > + ret = gpt_update_mdata(mdata); > > This function is also doing the generic things. Only gpt_update_mdata() is > the barrier. I would like to suggest you to add ".update_mdata" member > to the fwu_mdata_ops. > > > Thank you, > > > + goto out; > > + } > > + } > > + > > + /* Image not found */ > > + ret = -EINVAL; > > + > > +out: > > + free(mdata); > > + > > + return ret; > > +} > > + > > +int fwu_gpt_accept_image(efi_guid_t *img_type_id) > > +{ > > + return fwu_gpt_set_clear_image_accept(img_type_id, 0, > > + IMAGE_ACCEPT_SET); > > +} > > + > > +int fwu_gpt_clear_accept_image(efi_guid_t *img_type_id, u32 bank) > > +{ > > + return fwu_gpt_set_clear_image_accept(img_type_id, bank, > > + IMAGE_ACCEPT_CLEAR); > > +} > > + > > +struct fwu_mdata_ops fwu_gpt_blk_ops = { > > + .get_active_index = fwu_gpt_get_active_index, > > + .update_active_index = fwu_gpt_update_active_index, > > + .get_image_alt_num = fwu_gpt_get_image_alt_num, > > + .mdata_check = fwu_gpt_mdata_check, > > + .revert_boot_index = fwu_gpt_revert_boot_index, > > + .set_accept_image = fwu_gpt_accept_image, > > + .clear_accept_image = fwu_gpt_clear_accept_image, > > + .get_mdata = fwu_gpt_get_mdata, > > +}; > > -- > > 2.17.1 > > > > > -- > Masami Hiramatsu
Hi Sughosh, 2021年12月25日(土) 2:08 Sughosh Ganu <sughosh.ganu@linaro.org>: > > hi Masami, > > On Fri, 24 Dec 2021 at 15:29, Masami Hiramatsu > <masami.hiramatsu@linaro.org> wrote: > > > > Hi Sughosh, > > > > 2021年12月19日(日) 16:06 Sughosh Ganu <sughosh.ganu@linaro.org>: > > > > > +static int gpt_get_image_alt_num(struct blk_desc *desc, > > > + efi_guid_t image_type_id, > > > + u32 update_bank, int *alt_no) > > > +{ > > > + int ret, i; > > > + u32 part; > > > + struct fwu_mdata *mdata; > > > + struct fwu_image_entry *img_entry; > > > + struct fwu_image_bank_info *img_bank_info; > > > + struct disk_partition info; > > > + efi_guid_t unique_part_guid; > > > + efi_guid_t image_guid = NULL_GUID; > > > + > > > + ret = gpt_get_mdata(&mdata); > > > + if (ret < 0) { > > > + log_err("Unable to read valid FWU metadata\n"); > > > + goto out; > > > + } > > > + > > > + /* > > > + * The FWU metadata has been read. Now get the image_uuid for the > > > + * image with the update_bank. > > > + */ > > > + for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; i++) { > > > + if (!guidcmp(&image_type_id, > > > + &mdata->img_entry[i].image_type_uuid)) { > > > + img_entry = &mdata->img_entry[i]; > > > + img_bank_info = &img_entry->img_bank_info[update_bank]; > > > + guidcpy(&image_guid, &img_bank_info->image_uuid); > > > + break; > > > + } > > > + } > > > + > > > + /* > > > + * Now read the GPT Partition Table Entries to find a matching > > > + * partition with UniquePartitionGuid value. We need to iterate > > > + * through all the GPT partitions since they might be in any > > > + * order > > > + */ > > > + for (i = 1; i < MAX_SEARCH_PARTITIONS; i++) { > > > + if (part_get_info(desc, i, &info)) > > > + continue; > > > + uuid_str_to_bin(info.uuid, unique_part_guid.b, > > > + UUID_STR_FORMAT_GUID); > > > + > > > + if (!guidcmp(&unique_part_guid, &image_guid)) { > > > + /* Found the partition */ > > > + part = i; > > > + *alt_no = fwu_plat_get_alt_num(desc->devnum, &part); > > > > This is still GPT depending interface. In my use case (no GPT but raw SPI flash) > > I don't have devnum. Moreover, this one is used only from the > > fwu_mdata_gpt_blk.c. > > You are right. I will change this api to not have the first parameter. > The function will then pass only the identifier which is a void *. What about passing image index and bank index ? :-) > > > Please ensure (and comment) that this is only for GPT user. > > > > > + if (*alt_no != -1) > > > + log_info("alt_num %d for partition %pUl\n", > > > + *alt_no, &image_guid); > > > + ret = 0; > > > + break; > > > + } > > > + } > > > + > > > + if (*alt_no == -1) { > > > + log_err("alt_num not found for partition with GUID %pUl\n", > > > + &image_guid); > > > + ret = -EINVAL; > > > + } > > > + > > > + if (i == MAX_SEARCH_PARTITIONS) { > > > + log_err("Partition with the image guid not found\n"); > > > + ret = -EINVAL; > > > + } > > > + > > > +out: > > > + free(mdata); > > > + > > > + return ret; > > > +} > > > + > > > +int fwu_gpt_update_active_index(u32 active_idx) > > > +{ > > > + int ret; > > > + void *buf; > > > + struct fwu_mdata *mdata; > > > + > > > + if (active_idx > CONFIG_FWU_NUM_BANKS) { > > > + printf("Active index value to be updated is incorrect\n"); > > > + return -1; > > > + } > > > + > > > + ret = gpt_get_mdata(&mdata); > > > + if (ret < 0) { > > > + log_err("Unable to get valid FWU metadata\n"); > > > + goto out; > > > + } > > > + > > > + /* > > > + * Update the active index and previous_active_index fields > > > + * in the FWU metadata > > > + */ > > > + mdata->previous_active_index = mdata->active_index; > > > + mdata->active_index = active_idx; > > > + > > > + > > > + /* > > > + * Calculate the crc32 for the updated FWU metadata > > > + * and put the updated value in the FWU metadata crc32 > > > + * field > > > + */ > > > + buf = &mdata->version; > > > + mdata->crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32)); > > > + > > > + /* > > > + * Now write this updated FWU metadata to both the > > > + * FWU metadata partitions > > > + */ > > > + ret = gpt_update_mdata(mdata); > > > + if (ret < 0) { > > > + log_err("Failed to update FWU metadata partitions\n"); > > > + ret = -EIO; > > > + } > > > + > > > +out: > > > + free(mdata); > > > + > > > + return ret; > > > +} > > > + > > > +int fwu_gpt_get_image_alt_num(efi_guid_t image_type_id, u32 update_bank, > > > + int *alt_no) > > > +{ > > > + int ret; > > > + struct blk_desc *desc; > > > + > > > + ret = fwu_plat_get_blk_desc(&desc); > > > + if (ret < 0) { > > > + log_err("Block device not found\n"); > > > + return -ENODEV; > > > + } > > > + > > > + return gpt_get_image_alt_num(desc, image_type_id, update_bank, alt_no); > > > +} > > > + > > > +int fwu_gpt_mdata_check(void) > > > +{ > > > + /* > > > + * Check if both the copies of the FWU metadata are > > > + * valid. If one has gone bad, restore it from the > > > + * other good copy. > > > + */ > > > + return gpt_check_mdata_validity(); > > > +} > > > + > > > +int fwu_gpt_get_mdata(struct fwu_mdata **mdata) > > > +{ > > > + return gpt_get_mdata(mdata); > > > +} > > > + > > > +int fwu_gpt_revert_boot_index(void) > > > +{ > > > + int ret; > > > + void *buf; > > > + u32 cur_active_index; > > > + struct fwu_mdata *mdata; > > > + > > > + ret = gpt_get_mdata(&mdata); > > > + if (ret < 0) { > > > + log_err("Unable to get valid FWU metadata\n"); > > > + goto out; > > > + } > > > + > > > + /* > > > + * Swap the active index and previous_active_index fields > > > + * in the FWU metadata > > > + */ > > > + cur_active_index = mdata->active_index; > > > + mdata->active_index = mdata->previous_active_index; > > > + mdata->previous_active_index = cur_active_index; > > > + > > > + /* > > > + * Calculate the crc32 for the updated FWU metadata > > > + * and put the updated value in the FWU metadata crc32 > > > + * field > > > + */ > > > + buf = &mdata->version; > > > + mdata->crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32)); > > > + > > > + /* > > > + * Now write this updated FWU metadata to both the > > > + * FWU metadata partitions > > > + */ > > > + ret = gpt_update_mdata(mdata); > > > > If we have the fwu_update_mdata(), you can make this fwu_gpt_revert_boot_index() > > and above fwu_gpt_update_boot_index() platform agnostic. (in that case > > "gpt" must > > be removed), because there is no dependency to GPT. > > Okay. I believe you are suggesting having a GPT specific > implementation only for fwu_update_mdata, and move > fwu_gpt_revert_boot_index and fwu_gpt_update_active_index as common > functions with appropriate renaming. I can do that. Yes, that's right. Then I don't need to repeat the same code :-) Thank you, > > -sughosh > > > > > > + if (ret < 0) { > > > + log_err("Failed to update FWU metadata partitions\n"); > > > + ret = -EIO; > > > + } > > > + > > > +out: > > > + free(mdata); > > > + > > > + return ret; > > > +} > > > + > > > +static int fwu_gpt_set_clear_image_accept(efi_guid_t *img_type_id, > > > + u32 bank, u8 action) > > > +{ > > > + void *buf; > > > + int ret, i; > > > + u32 nimages; > > > + struct fwu_mdata *mdata; > > > + struct fwu_image_entry *img_entry; > > > + struct fwu_image_bank_info *img_bank_info; > > > + > > > + ret = gpt_get_mdata(&mdata); > > > + if (ret < 0) { > > > + log_err("Unable to get valid FWU metadata\n"); > > > + goto out; > > > + } > > > + > > > + if (action == IMAGE_ACCEPT_SET) > > > + bank = mdata->active_index; > > > + > > > + nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK; > > > + img_entry = &mdata->img_entry[0]; > > > + for (i = 0; i < nimages; i++) { > > > + if (!guidcmp(&img_entry[i].image_type_uuid, img_type_id)) { > > > + img_bank_info = &img_entry[i].img_bank_info[bank]; > > > + if (action == IMAGE_ACCEPT_SET) > > > + img_bank_info->accepted |= FWU_IMAGE_ACCEPTED; > > > + else > > > + img_bank_info->accepted = 0; > > > + > > > + buf = &mdata->version; > > > + mdata->crc32 = crc32(0, buf, sizeof(*mdata) - > > > + sizeof(u32)); > > > + > > > + ret = gpt_update_mdata(mdata); > > > > This function is also doing the generic things. Only gpt_update_mdata() is > > the barrier. I would like to suggest you to add ".update_mdata" member > > to the fwu_mdata_ops. > > > > > > Thank you, > > > > > + goto out; > > > + } > > > + } > > > + > > > + /* Image not found */ > > > + ret = -EINVAL; > > > + > > > +out: > > > + free(mdata); > > > + > > > + return ret; > > > +} > > > + > > > +int fwu_gpt_accept_image(efi_guid_t *img_type_id) > > > +{ > > > + return fwu_gpt_set_clear_image_accept(img_type_id, 0, > > > + IMAGE_ACCEPT_SET); > > > +} > > > + > > > +int fwu_gpt_clear_accept_image(efi_guid_t *img_type_id, u32 bank) > > > +{ > > > + return fwu_gpt_set_clear_image_accept(img_type_id, bank, > > > + IMAGE_ACCEPT_CLEAR); > > > +} > > > + > > > +struct fwu_mdata_ops fwu_gpt_blk_ops = { > > > + .get_active_index = fwu_gpt_get_active_index, > > > + .update_active_index = fwu_gpt_update_active_index, > > > + .get_image_alt_num = fwu_gpt_get_image_alt_num, > > > + .mdata_check = fwu_gpt_mdata_check, > > > + .revert_boot_index = fwu_gpt_revert_boot_index, > > > + .set_accept_image = fwu_gpt_accept_image, > > > + .clear_accept_image = fwu_gpt_clear_accept_image, > > > + .get_mdata = fwu_gpt_get_mdata, > > > +}; > > > -- > > > 2.17.1 > > > > > > > > > -- > > Masami Hiramatsu
diff --git a/include/fwu_mdata.h b/include/fwu_mdata.h index 11eb570012..9e24ab4047 100644 --- a/include/fwu_mdata.h +++ b/include/fwu_mdata.h @@ -99,4 +99,6 @@ struct fwu_mdata_ops { int fwu_get_mdata(struct fwu_mdata **mdata); struct fwu_mdata_ops *get_plat_fwu_mdata_ops(void); +extern struct fwu_mdata_ops fwu_gpt_blk_ops; + #endif /* _FWU_MDATA_H_ */ diff --git a/lib/fwu_updates/fwu_mdata_gpt_blk.c b/lib/fwu_updates/fwu_mdata_gpt_blk.c new file mode 100644 index 0000000000..2dcac0c3d4 --- /dev/null +++ b/lib/fwu_updates/fwu_mdata_gpt_blk.c @@ -0,0 +1,634 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2021, Linaro Limited + */ + +#include <blk.h> +#include <efi_loader.h> +#include <fwu.h> +#include <fwu_mdata.h> +#include <malloc.h> +#include <memalign.h> +#include <part.h> +#include <part_efi.h> + +#include <linux/errno.h> +#include <linux/types.h> +#include <u-boot/crc.h> + +#define PRIMARY_PART BIT(0) +#define SECONDARY_PART BIT(1) +#define BOTH_PARTS (PRIMARY_PART | SECONDARY_PART) + +#define MDATA_READ BIT(0) +#define MDATA_WRITE BIT(1) + +#define IMAGE_ACCEPT_SET BIT(0) +#define IMAGE_ACCEPT_CLEAR BIT(1) + +static int gpt_verify_mdata(struct fwu_mdata *mdata, bool pri_part) +{ + u32 calc_crc32; + void *buf; + + buf = &mdata->version; + calc_crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32)); + + if (calc_crc32 != mdata->crc32) { + log_err("crc32 check failed for %s FWU metadata partition\n", + pri_part ? "primary" : "secondary"); + return -1; + } + + return 0; +} + +static int gpt_get_mdata_partitions(struct blk_desc *desc, + u16 *primary_mpart, + u16 *secondary_mpart) +{ + int i, ret; + u32 mdata_parts; + efi_guid_t part_type_guid; + struct disk_partition info; + const efi_guid_t fwu_mdata_guid = FWU_MDATA_GUID; + + for (i = 1; i < MAX_SEARCH_PARTITIONS; i++) { + if (part_get_info(desc, i, &info)) + continue; + uuid_str_to_bin(info.type_guid, part_type_guid.b, + UUID_STR_FORMAT_GUID); + + if (!guidcmp(&fwu_mdata_guid, &part_type_guid)) { + ++mdata_parts; + if (!*primary_mpart) + *primary_mpart = i; + else + *secondary_mpart = i; + } + } + + if (mdata_parts != 2) { + log_err("Expect two copies of the FWU metadata instead of %d\n", + mdata_parts); + ret = -EINVAL; + } else { + ret = 0; + } + + return ret; +} + +static int gpt_get_mdata_disk_part(struct blk_desc *desc, + struct disk_partition *info, + u32 part_num) +{ + int ret; + char *mdata_guid_str = "8a7a84a0-8387-40f6-ab41-a8b9a5a60d23"; + + ret = part_get_info(desc, part_num, info); + if (ret < 0) { + log_err("Unable to get the partition info for the FWU metadata part %d", + part_num); + return -1; + } + + /* Check that it is indeed the FWU metadata partition */ + if (!strncmp(info->type_guid, mdata_guid_str, UUID_STR_LEN)) { + /* Found the FWU metadata partition */ + return 0; + } + + return -1; +} + +static int gpt_read_write_mdata(struct blk_desc *desc, + struct fwu_mdata *mdata, + u8 access, u32 part_num) +{ + int ret; + u32 len, blk_start, blkcnt; + struct disk_partition info; + + ALLOC_CACHE_ALIGN_BUFFER_PAD(struct fwu_mdata, mdata_aligned, 1, + desc->blksz); + + ret = gpt_get_mdata_disk_part(desc, &info, part_num); + if (ret < 0) { + printf("Unable to get the FWU metadata partition\n"); + return -ENODEV; + } + + len = sizeof(*mdata); + blkcnt = BLOCK_CNT(len, desc); + if (blkcnt > info.size) { + log_err("Block count exceeds FWU metadata partition size\n"); + return -ERANGE; + } + + blk_start = info.start; + if (access == MDATA_READ) { + if (blk_dread(desc, blk_start, blkcnt, mdata_aligned) != blkcnt) { + log_err("Error reading FWU metadata from the device\n"); + return -EIO; + } + memcpy(mdata, mdata_aligned, sizeof(struct fwu_mdata)); + } else { + if (blk_dwrite(desc, blk_start, blkcnt, mdata) != blkcnt) { + log_err("Error writing FWU metadata to the device\n"); + return -EIO; + } + } + + return 0; +} + +static int gpt_read_mdata(struct blk_desc *desc, + struct fwu_mdata *mdata, u32 part_num) +{ + return gpt_read_write_mdata(desc, mdata, MDATA_READ, part_num); +} + +static int gpt_write_mdata_partition(struct blk_desc *desc, + struct fwu_mdata *mdata, + u32 part_num) +{ + return gpt_read_write_mdata(desc, mdata, MDATA_WRITE, part_num); +} + +static int gpt_update_mdata(struct fwu_mdata *mdata) +{ + int ret; + struct blk_desc *desc; + u16 primary_mpart = 0, secondary_mpart = 0; + + ret = fwu_plat_get_blk_desc(&desc); + if (ret < 0) { + log_err("Block device not found\n"); + return -ENODEV; + } + + ret = gpt_get_mdata_partitions(desc, &primary_mpart, + &secondary_mpart); + + if (ret < 0) { + log_err("Error getting the FWU metadata partitions\n"); + return -ENODEV; + } + + /* First write the primary partition*/ + ret = gpt_write_mdata_partition(desc, mdata, primary_mpart); + if (ret < 0) { + log_err("Updating primary FWU metadata partition failed\n"); + return ret; + } + + /* And now the replica */ + ret = gpt_write_mdata_partition(desc, mdata, secondary_mpart); + if (ret < 0) { + log_err("Updating secondary FWU metadata partition failed\n"); + return ret; + } + + return 0; +} + +static int gpt_get_mdata(struct fwu_mdata **mdata) +{ + int ret; + struct blk_desc *desc; + u16 primary_mpart = 0, secondary_mpart = 0; + + ret = fwu_plat_get_blk_desc(&desc); + if (ret < 0) { + log_err("Block device not found\n"); + return -ENODEV; + } + + ret = gpt_get_mdata_partitions(desc, &primary_mpart, + &secondary_mpart); + + if (ret < 0) { + log_err("Error getting the FWU metadata partitions\n"); + return -ENODEV; + } + + *mdata = malloc(sizeof(struct fwu_mdata)); + if (!*mdata) { + log_err("Unable to allocate memory for reading FWU metadata\n"); + return -ENOMEM; + } + + ret = gpt_read_mdata(desc, *mdata, primary_mpart); + if (ret < 0) { + log_err("Failed to read the FWU metadata from the device\n"); + return -EIO; + } + + ret = gpt_verify_mdata(*mdata, 1); + if (!ret) + return 0; + + /* + * Verification of the primary FWU metadata copy failed. + * Try to read the replica. + */ + memset(*mdata, 0, sizeof(struct fwu_mdata)); + ret = gpt_read_mdata(desc, *mdata, secondary_mpart); + if (ret < 0) { + log_err("Failed to read the FWU metadata from the device\n"); + return -EIO; + } + + ret = gpt_verify_mdata(*mdata, 0); + if (!ret) + return 0; + + /* Both the FWU metadata copies are corrupted. */ + return -1; +} + +static int gpt_check_mdata_validity(void) +{ + int ret; + struct blk_desc *desc; + struct fwu_mdata pri_mdata; + struct fwu_mdata secondary_mdata; + u16 primary_mpart = 0, secondary_mpart = 0; + u16 valid_partitions, invalid_partitions; + + ret = fwu_plat_get_blk_desc(&desc); + if (ret < 0) { + log_err("Block device not found\n"); + return -ENODEV; + } + + /* + * Two FWU metadata partitions are expected. + * If we don't have two, user needs to create + * them first + */ + valid_partitions = 0; + ret = gpt_get_mdata_partitions(desc, &primary_mpart, + &secondary_mpart); + + if (ret < 0) { + log_err("Error getting the FWU metadata partitions\n"); + return -ENODEV; + } + + ret = gpt_read_mdata(desc, &pri_mdata, primary_mpart); + if (ret < 0) { + log_err("Failed to read the FWU metadata from the device\n"); + goto secondary_read; + } + + ret = gpt_verify_mdata(&pri_mdata, 1); + if (!ret) + valid_partitions |= PRIMARY_PART; + +secondary_read: + /* Now check the secondary partition */ + ret = gpt_read_mdata(desc, &secondary_mdata, secondary_mpart); + if (ret < 0) { + log_err("Failed to read the FWU metadata from the device\n"); + goto mdata_restore; + } + + ret = gpt_verify_mdata(&secondary_mdata, 0); + if (!ret) + valid_partitions |= SECONDARY_PART; + +mdata_restore: + if (valid_partitions == (PRIMARY_PART | SECONDARY_PART)) { + ret = -1; + /* + * Before returning, check that both the + * FWU metadata copies are the same. If not, + * the FWU metadata copies need to be + * re-populated. + */ + if (!memcmp(&pri_mdata, &secondary_mdata, + sizeof(struct fwu_mdata))) { + ret = 0; + } else { + log_err("Both FWU metadata copies are valid but do not match. Please check!\n"); + } + goto out; + } + + ret = -1; + if (!(valid_partitions & BOTH_PARTS)) + goto out; + + invalid_partitions = valid_partitions ^ BOTH_PARTS; + ret = gpt_write_mdata_partition(desc, + (invalid_partitions == PRIMARY_PART) ? + &secondary_mdata : &pri_mdata, + (invalid_partitions == PRIMARY_PART) ? + primary_mpart : secondary_mpart); + + if (ret < 0) + log_err("Restoring %s FWU metadata partition failed\n", + (invalid_partitions == PRIMARY_PART) ? + "primary" : "secondary"); + +out: + return ret; +} + +int fwu_gpt_get_active_index(u32 *active_idx) +{ + int ret; + struct fwu_mdata *mdata; + + ret = gpt_get_mdata(&mdata); + if (ret < 0) { + log_err("Unable to get valid FWU metadata\n"); + goto out; + } + + /* + * Found the FWU metadata partition, now read the active_index + * value + */ + *active_idx = mdata->active_index; + if (*active_idx > CONFIG_FWU_NUM_BANKS - 1) { + printf("Active index value read is incorrect\n"); + ret = -EINVAL; + goto out; + } + +out: + free(mdata); + + return ret; +} + +static int gpt_get_image_alt_num(struct blk_desc *desc, + efi_guid_t image_type_id, + u32 update_bank, int *alt_no) +{ + int ret, i; + u32 part; + struct fwu_mdata *mdata; + struct fwu_image_entry *img_entry; + struct fwu_image_bank_info *img_bank_info; + struct disk_partition info; + efi_guid_t unique_part_guid; + efi_guid_t image_guid = NULL_GUID; + + ret = gpt_get_mdata(&mdata); + if (ret < 0) { + log_err("Unable to read valid FWU metadata\n"); + goto out; + } + + /* + * The FWU metadata has been read. Now get the image_uuid for the + * image with the update_bank. + */ + for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; i++) { + if (!guidcmp(&image_type_id, + &mdata->img_entry[i].image_type_uuid)) { + img_entry = &mdata->img_entry[i]; + img_bank_info = &img_entry->img_bank_info[update_bank]; + guidcpy(&image_guid, &img_bank_info->image_uuid); + break; + } + } + + /* + * Now read the GPT Partition Table Entries to find a matching + * partition with UniquePartitionGuid value. We need to iterate + * through all the GPT partitions since they might be in any + * order + */ + for (i = 1; i < MAX_SEARCH_PARTITIONS; i++) { + if (part_get_info(desc, i, &info)) + continue; + uuid_str_to_bin(info.uuid, unique_part_guid.b, + UUID_STR_FORMAT_GUID); + + if (!guidcmp(&unique_part_guid, &image_guid)) { + /* Found the partition */ + part = i; + *alt_no = fwu_plat_get_alt_num(desc->devnum, &part); + if (*alt_no != -1) + log_info("alt_num %d for partition %pUl\n", + *alt_no, &image_guid); + ret = 0; + break; + } + } + + if (*alt_no == -1) { + log_err("alt_num not found for partition with GUID %pUl\n", + &image_guid); + ret = -EINVAL; + } + + if (i == MAX_SEARCH_PARTITIONS) { + log_err("Partition with the image guid not found\n"); + ret = -EINVAL; + } + +out: + free(mdata); + + return ret; +} + +int fwu_gpt_update_active_index(u32 active_idx) +{ + int ret; + void *buf; + struct fwu_mdata *mdata; + + if (active_idx > CONFIG_FWU_NUM_BANKS) { + printf("Active index value to be updated is incorrect\n"); + return -1; + } + + ret = gpt_get_mdata(&mdata); + if (ret < 0) { + log_err("Unable to get valid FWU metadata\n"); + goto out; + } + + /* + * Update the active index and previous_active_index fields + * in the FWU metadata + */ + mdata->previous_active_index = mdata->active_index; + mdata->active_index = active_idx; + + + /* + * Calculate the crc32 for the updated FWU metadata + * and put the updated value in the FWU metadata crc32 + * field + */ + buf = &mdata->version; + mdata->crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32)); + + /* + * Now write this updated FWU metadata to both the + * FWU metadata partitions + */ + ret = gpt_update_mdata(mdata); + if (ret < 0) { + log_err("Failed to update FWU metadata partitions\n"); + ret = -EIO; + } + +out: + free(mdata); + + return ret; +} + +int fwu_gpt_get_image_alt_num(efi_guid_t image_type_id, u32 update_bank, + int *alt_no) +{ + int ret; + struct blk_desc *desc; + + ret = fwu_plat_get_blk_desc(&desc); + if (ret < 0) { + log_err("Block device not found\n"); + return -ENODEV; + } + + return gpt_get_image_alt_num(desc, image_type_id, update_bank, alt_no); +} + +int fwu_gpt_mdata_check(void) +{ + /* + * Check if both the copies of the FWU metadata are + * valid. If one has gone bad, restore it from the + * other good copy. + */ + return gpt_check_mdata_validity(); +} + +int fwu_gpt_get_mdata(struct fwu_mdata **mdata) +{ + return gpt_get_mdata(mdata); +} + +int fwu_gpt_revert_boot_index(void) +{ + int ret; + void *buf; + u32 cur_active_index; + struct fwu_mdata *mdata; + + ret = gpt_get_mdata(&mdata); + if (ret < 0) { + log_err("Unable to get valid FWU metadata\n"); + goto out; + } + + /* + * Swap the active index and previous_active_index fields + * in the FWU metadata + */ + cur_active_index = mdata->active_index; + mdata->active_index = mdata->previous_active_index; + mdata->previous_active_index = cur_active_index; + + /* + * Calculate the crc32 for the updated FWU metadata + * and put the updated value in the FWU metadata crc32 + * field + */ + buf = &mdata->version; + mdata->crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32)); + + /* + * Now write this updated FWU metadata to both the + * FWU metadata partitions + */ + ret = gpt_update_mdata(mdata); + if (ret < 0) { + log_err("Failed to update FWU metadata partitions\n"); + ret = -EIO; + } + +out: + free(mdata); + + return ret; +} + +static int fwu_gpt_set_clear_image_accept(efi_guid_t *img_type_id, + u32 bank, u8 action) +{ + void *buf; + int ret, i; + u32 nimages; + struct fwu_mdata *mdata; + struct fwu_image_entry *img_entry; + struct fwu_image_bank_info *img_bank_info; + + ret = gpt_get_mdata(&mdata); + if (ret < 0) { + log_err("Unable to get valid FWU metadata\n"); + goto out; + } + + if (action == IMAGE_ACCEPT_SET) + bank = mdata->active_index; + + nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK; + img_entry = &mdata->img_entry[0]; + for (i = 0; i < nimages; i++) { + if (!guidcmp(&img_entry[i].image_type_uuid, img_type_id)) { + img_bank_info = &img_entry[i].img_bank_info[bank]; + if (action == IMAGE_ACCEPT_SET) + img_bank_info->accepted |= FWU_IMAGE_ACCEPTED; + else + img_bank_info->accepted = 0; + + buf = &mdata->version; + mdata->crc32 = crc32(0, buf, sizeof(*mdata) - + sizeof(u32)); + + ret = gpt_update_mdata(mdata); + goto out; + } + } + + /* Image not found */ + ret = -EINVAL; + +out: + free(mdata); + + return ret; +} + +int fwu_gpt_accept_image(efi_guid_t *img_type_id) +{ + return fwu_gpt_set_clear_image_accept(img_type_id, 0, + IMAGE_ACCEPT_SET); +} + +int fwu_gpt_clear_accept_image(efi_guid_t *img_type_id, u32 bank) +{ + return fwu_gpt_set_clear_image_accept(img_type_id, bank, + IMAGE_ACCEPT_CLEAR); +} + +struct fwu_mdata_ops fwu_gpt_blk_ops = { + .get_active_index = fwu_gpt_get_active_index, + .update_active_index = fwu_gpt_update_active_index, + .get_image_alt_num = fwu_gpt_get_image_alt_num, + .mdata_check = fwu_gpt_mdata_check, + .revert_boot_index = fwu_gpt_revert_boot_index, + .set_accept_image = fwu_gpt_accept_image, + .clear_accept_image = fwu_gpt_clear_accept_image, + .get_mdata = fwu_gpt_get_mdata, +};
In the FWU Multi Bank Update feature, the information about the updatable images is stored as part of the metadata, on a separate partition. Add functions for reading from and writing to the metadata when the updatable images and the metadata are stored on a block device which is formated with GPT based partition scheme. Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org> --- Changes since V1: * Rename metadata with mdata for all symbols * Use BIT for all macros * Use the logic suggested by Patrick to get the partition type guids and partition guid's instead of defining a new api * Call the platform function fwu_plat_get_alt_num for getting the alt_num for the image partition, instead of the earlier hard-coded approach. * Change the logic in gpt_check_mdata_validity as suggested by Ilias. * Other smaller code style changes suggested by Ilias include/fwu_mdata.h | 2 + lib/fwu_updates/fwu_mdata_gpt_blk.c | 634 ++++++++++++++++++++++++++++ 2 files changed, 636 insertions(+) create mode 100644 lib/fwu_updates/fwu_mdata_gpt_blk.c