| // SPDX-License-Identifier: GPL-2.0-or-later |
| /* |
| * Copyright (c) 2022, Linaro Limited |
| */ |
| |
| #include <blk.h> |
| #include <dfu.h> |
| #include <efi.h> |
| #include <efi_loader.h> |
| #include <fwu.h> |
| #include <log.h> |
| #include <part.h> |
| |
| #include <linux/errno.h> |
| |
| static int get_gpt_dfu_identifier(struct blk_desc *desc, efi_guid_t *image_guid) |
| { |
| int i; |
| struct disk_partition info; |
| efi_guid_t unique_part_guid; |
| |
| 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)) |
| return i; |
| } |
| |
| log_err("No partition found with image_guid %pUs\n", image_guid); |
| return -ENOENT; |
| } |
| |
| static int fwu_alt_num_for_dfu_dev(struct dfu_entity *dfu, int dev_num, |
| int part, unsigned char dfu_dev, |
| u8 *alt_num) |
| { |
| int ret; |
| |
| switch(dfu_dev) { |
| case DFU_DEV_MMC: |
| if (dfu->layout == DFU_RAW_ADDR && |
| dfu->data.mmc.dev_num == dev_num && |
| dfu->data.mmc.part == part) { |
| *alt_num = dfu->alt; |
| ret = 0; |
| } else { |
| ret = -ENOENT; |
| } |
| break; |
| default: |
| ret = -ENOENT; |
| } |
| |
| return ret; |
| } |
| |
| static int fwu_gpt_get_alt_num(struct blk_desc *desc, efi_guid_t *image_guid, |
| u8 *alt_num, unsigned char dfu_dev) |
| { |
| int ret = -1; |
| int i, part, dev_num; |
| struct dfu_entity *dfu; |
| |
| dev_num = desc->devnum; |
| part = get_gpt_dfu_identifier(desc, image_guid); |
| if (part < 0) |
| return -ENOENT; |
| |
| ret = dfu_init_env_entities(NULL, NULL); |
| if (ret) |
| goto out; |
| |
| i = 0; |
| while (true) { |
| dfu = dfu_get_entity(i++); |
| if (!dfu) { |
| ret = -ENOENT; |
| break; |
| } |
| |
| if (dfu->dev_type != dfu_dev) |
| continue; |
| |
| ret = fwu_alt_num_for_dfu_dev(dfu, dev_num, part, dfu_dev, |
| alt_num); |
| if (!ret) |
| break; |
| } |
| |
| out: |
| dfu_free_entities(); |
| |
| return ret; |
| } |
| |
| /** |
| * fwu_plat_get_alt_num() - Get the DFU alt number |
| * @dev: FWU metadata device |
| * @image_guid: GUID value of the image for which the alt num is to |
| * be obtained |
| * @alt_num: The DFU alt number for the image that is to be updated |
| * |
| * Get the DFU alt number for the image that is to be updated. The |
| * image is identified with the image_guid parameter that is passed |
| * to the function. |
| * |
| * Note: This is a weak function and platforms can override this with |
| * their own implementation for obtaining the alt number value. |
| * |
| * Return: 0 if OK, -ve on error |
| * |
| */ |
| __weak int fwu_plat_get_alt_num(struct udevice *dev, efi_guid_t *image_guid, |
| u8 *alt_num) |
| { |
| struct fwu_mdata_gpt_blk_priv *priv = dev_get_priv(dev); |
| |
| return fwu_gpt_get_alt_num(dev_get_uclass_plat(priv->blk_dev), |
| image_guid, alt_num, DFU_DEV_MMC); |
| } |