From patchwork Thu Nov 25 07:01:40 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sughosh Ganu X-Patchwork-Id: 519360 Delivered-To: patch@linaro.org Received: by 2002:ac0:c605:0:0:0:0:0 with SMTP id p5csp357486imj; Wed, 24 Nov 2021 23:03:48 -0800 (PST) X-Google-Smtp-Source: ABdhPJwADflxQ+0QekG67KbI7z4UuxGa89P9UjFKilUBwHuZdSUYV+XT75JxAk2oicB4T+95wvBf X-Received: by 2002:a17:906:e103:: with SMTP id gj3mr28620388ejb.456.1637823828631; Wed, 24 Nov 2021 23:03:48 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1637823828; cv=none; d=google.com; s=arc-20160816; b=lgx7On5F8A2zZ1tjttkI6hxQBcnc+yGeTbO2ICRqCHsDXXmEXM5Su5p2zmKwtOlYaf vJ4I49xb7+EK8BWn/mBcCijDOM1SYPOxTUVoul2CTNyeejIofLRd1XI/aAdWAghPLyPo sKtrf+sdu+kTEJ1ClaZk7NTXBWWGTj9KpY0QGyVF4/mB5RbUCnYoi7+w0M+S8Pt8dsnJ G8fJvoy31EtCXt3ff9R0sgDMqxBUhRYNm5Q86KIKDbhDMNBlYfQ3uMNTrOLcFcGWPJKA pDpYGeiGPABta1OfQDvQ7D49SmeuvbY32zbZbqvjHCrpsptYhdel+VtET+G/kvRQfqoq OymA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:references:in-reply-to :message-id:date:subject:cc:to:from; bh=TRRMigymu8SYg1x8C/oX2bw10o7otvsWQs6aNoDTHdE=; b=deQO2w1bTpgFQGztX8GJR+yS26qok+ZGx8dJ3Nh3FX65tpldQzO/c8S19JXVuDIKTh tg3dQPZ8Ks3T/IhpbaBuXu83j3Z4rGJtvpmLpO38IlBzLMByvraPxZpmp/j0nXMo6cIe DjOsmeKhx6Hz2N8B7i7M7M2CLk2873RkRfB/40Dp1kx+Ku3OOeQufLFl/sDguWS2kgT5 Q5MKRfRcD/kcvT/gRKGsHAsaprfh7qUbT8ewFBS54lv3+P0slxg3hYwcgPkdk8ojn0Yj ovmxav4WqgoUpeWWFSuFpUa7F/uxvTHouIC9oJDO/lU5Nr6o9fjQuT8mxHzGxL44d4wd CaEg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from phobos.denx.de (phobos.denx.de. [2a01:238:438b:c500:173d:9f52:ddab:ee01]) by mx.google.com with ESMTPS id do3si6795849ejc.653.2021.11.24.23.03.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Nov 2021 23:03:48 -0800 (PST) Received-SPF: pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; Authentication-Results: mx.google.com; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 4B9A28365E; Thu, 25 Nov 2021 08:03:27 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by phobos.denx.de (Postfix, from userid 109) id D82F082F89; Thu, 25 Nov 2021 08:03:20 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-1.2 required=5.0 tests=BAYES_00,SPF_HELO_NONE, SPF_SOFTFAIL autolearn=no autolearn_force=no version=3.4.2 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by phobos.denx.de (Postfix) with ESMTP id 3B3C583257 for ; Thu, 25 Nov 2021 08:03:12 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=fail smtp.mailfrom=sughosh.ganu@linaro.org Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 824D61515; Wed, 24 Nov 2021 23:03:11 -0800 (PST) Received: from a076522.blr.arm.com (a076522.blr.arm.com [10.162.16.44]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 8131E3F5A1; Wed, 24 Nov 2021 23:03:07 -0800 (PST) From: Sughosh Ganu To: u-boot@lists.denx.de Cc: Patrick Delaunay , Patrice Chotard , Heinrich Schuchardt , Alexander Graf , Simon Glass , Bin Meng , Peng Fan , AKASHI Takahiro , Ilias Apalodimas , Jose Marinho , Grant Likely , Jason Liu , Sughosh Ganu Subject: [RFC PATCH 04/10] FWU: Add metadata access functions for GPT partitioned block devices Date: Thu, 25 Nov 2021 12:31:40 +0530 Message-Id: <20211125070146.2389-5-sughosh.ganu@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20211125070146.2389-1-sughosh.ganu@linaro.org> References: <20211125070146.2389-1-sughosh.ganu@linaro.org> X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.37 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.2 at phobos.denx.de X-Virus-Status: Clean 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 --- lib/fwu_updates/fwu_metadata_gpt_blk.c | 716 +++++++++++++++++++++++++ 1 file changed, 716 insertions(+) create mode 100644 lib/fwu_updates/fwu_metadata_gpt_blk.c diff --git a/lib/fwu_updates/fwu_metadata_gpt_blk.c b/lib/fwu_updates/fwu_metadata_gpt_blk.c new file mode 100644 index 0000000000..98cc53f706 --- /dev/null +++ b/lib/fwu_updates/fwu_metadata_gpt_blk.c @@ -0,0 +1,716 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2021, Linaro Limited + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define PRIMARY_VALID 0x1 +#define SECONDARY_VALID 0x2 + +#define MDATA_READ (u8)0x1 +#define MDATA_WRITE (u8)0x2 + +#define IMAGE_ACCEPT_SET (u8)0x1 +#define IMAGE_ACCEPT_CLEAR (u8)0x2 + +static int gpt_verify_metadata(struct fwu_metadata *metadata, bool pri_part) +{ + u32 calc_crc32; + void *buf; + + buf = &metadata->version; + calc_crc32 = crc32(0, buf, sizeof(*metadata) - sizeof(u32)); + + if (calc_crc32 != metadata->crc32) { + log_err("crc32 check failed for %s metadata partition\n", + pri_part ? "primary" : "secondary"); + return -1; + } + + return 0; +} + +static int gpt_get_metadata_partitions(struct blk_desc *desc, + u32 *primary_mpart, + u32 *secondary_mpart) +{ + int i, ret; + u32 nparts, mparts; + gpt_entry *gpt_pte = NULL; + const efi_guid_t fwu_metadata_guid = FWU_METADATA_GUID; + + ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, + desc->blksz); + + ret = get_gpt_hdr_parts(desc, gpt_head, &gpt_pte); + if (ret < 0) { + log_err("Error getting GPT header and partitions\n"); + ret = -EIO; + goto out; + } + + nparts = gpt_head->num_partition_entries; + for (i = 0, mparts = 0; i < nparts; i++) { + if (!guidcmp(&fwu_metadata_guid, + &gpt_pte[i].partition_type_guid)) { + ++mparts; + if (!*primary_mpart) + *primary_mpart = i + 1; + else + *secondary_mpart = i + 1; + } + } + + if (mparts != 2) { + log_err("Expect two copies of the metadata instead of %d\n", + mparts); + ret = -EINVAL; + } else { + ret = 0; + } +out: + free(gpt_pte); + + return ret; +} + +static int gpt_get_metadata_disk_part(struct blk_desc *desc, + struct disk_partition *info, + u32 part_num) +{ + int ret; + char *metadata_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 metadata part %d", + part_num); + return -1; + } + + /* Check that it is indeed the metadata partition */ + if (!strncmp(info->type_guid, metadata_guid_str, UUID_STR_LEN)) { + /* Found the metadata partition */ + return 0; + } + + return -1; +} + +static int gpt_read_write_metadata(struct blk_desc *desc, + struct fwu_metadata *metadata, + u8 access, u32 part_num) +{ + int ret; + u32 len, blk_start, blkcnt; + struct disk_partition info; + + ALLOC_CACHE_ALIGN_BUFFER_PAD(struct fwu_metadata, mdata, 1, desc->blksz); + + ret = gpt_get_metadata_disk_part(desc, &info, part_num); + if (ret < 0) { + printf("Unable to get the metadata partition\n"); + return -ENODEV; + } + + len = sizeof(*metadata); + blkcnt = BLOCK_CNT(len, desc); + if (blkcnt > info.size) { + log_err("Block count exceeds metadata partition size\n"); + return -ERANGE; + } + + blk_start = info.start; + if (access == MDATA_READ) { + if (blk_dread(desc, blk_start, blkcnt, mdata) != blkcnt) { + log_err("Error reading metadata from the device\n"); + return -EIO; + } + memcpy(metadata, mdata, sizeof(struct fwu_metadata)); + } else { + if (blk_dwrite(desc, blk_start, blkcnt, metadata) != blkcnt) { + log_err("Error writing metadata to the device\n"); + return -EIO; + } + } + + return 0; +} + +static int gpt_read_metadata(struct blk_desc *desc, + struct fwu_metadata *metadata, u32 part_num) +{ + return gpt_read_write_metadata(desc, metadata, MDATA_READ, part_num); +} + +static int gpt_write_metadata_partition(struct blk_desc *desc, + struct fwu_metadata *metadata, + u32 part_num) +{ + return gpt_read_write_metadata(desc, metadata, MDATA_WRITE, part_num); +} + +static int gpt_update_metadata(struct fwu_metadata *metadata) +{ + int ret; + struct blk_desc *desc; + u32 primary_mpart, secondary_mpart; + + ret = fwu_plat_get_blk_desc(&desc); + if (ret < 0) { + log_err("Block device not found\n"); + return -ENODEV; + } + + primary_mpart = secondary_mpart = 0; + ret = gpt_get_metadata_partitions(desc, &primary_mpart, + &secondary_mpart); + + if (ret < 0) { + log_err("Error getting the metadata partitions\n"); + return -ENODEV; + } + + /* First write the primary partition*/ + ret = gpt_write_metadata_partition(desc, metadata, primary_mpart); + if (ret < 0) { + log_err("Updating primary metadata partition failed\n"); + return ret; + } + + /* And now the replica */ + ret = gpt_write_metadata_partition(desc, metadata, secondary_mpart); + if (ret < 0) { + log_err("Updating secondary metadata partition failed\n"); + return ret; + } + + return 0; +} + +static int gpt_get_valid_metadata(struct fwu_metadata **metadata) +{ + int ret; + struct blk_desc *desc; + u32 primary_mpart, secondary_mpart; + + ret = fwu_plat_get_blk_desc(&desc); + if (ret < 0) { + log_err("Block device not found\n"); + return -ENODEV; + } + + primary_mpart = secondary_mpart = 0; + ret = gpt_get_metadata_partitions(desc, &primary_mpart, + &secondary_mpart); + + if (ret < 0) { + log_err("Error getting the metadata partitions\n"); + return -ENODEV; + } + + *metadata = malloc(sizeof(struct fwu_metadata)); + if (!*metadata) { + log_err("Unable to allocate memory for reading metadata\n"); + return -ENOMEM; + } + + ret = gpt_read_metadata(desc, *metadata, primary_mpart); + if (ret < 0) { + log_err("Failed to read the metadata from the device\n"); + return -EIO; + } + + ret = gpt_verify_metadata(*metadata, 1); + if (!ret) + return 0; + + /* + * Verification of the primary metadata copy failed. + * Try to read the replica. + */ + memset(*metadata, 0, sizeof(struct fwu_metadata)); + ret = gpt_read_metadata(desc, *metadata, secondary_mpart); + if (ret < 0) { + log_err("Failed to read the metadata from the device\n"); + return -EIO; + } + + ret = gpt_verify_metadata(*metadata, 0); + if (!ret) + return 0; + + /* Both the metadata copies are corrupted. */ + return -1; +} + +static int gpt_check_metadata_validity(void) +{ + int ret; + struct blk_desc *desc; + struct fwu_metadata *pri_metadata; + struct fwu_metadata *secondary_metadata; + u32 primary_mpart, secondary_mpart; + u32 valid_partitions; + + ret = fwu_plat_get_blk_desc(&desc); + if (ret < 0) { + log_err("Block device not found\n"); + return -ENODEV; + } + + /* + * Two metadata partitions are expected. + * If we don't have two, user needs to create + * them first + */ + primary_mpart = secondary_mpart = 0; + valid_partitions = 0; + ret = gpt_get_metadata_partitions(desc, &primary_mpart, + &secondary_mpart); + + if (ret < 0) { + log_err("Error getting the metadata partitions\n"); + return -ENODEV; + } + + pri_metadata = malloc(sizeof(*pri_metadata)); + if (!pri_metadata) { + log_err("Unable to allocate memory for reading metadata\n"); + return -ENOMEM; + } + + secondary_metadata = malloc(sizeof(*secondary_metadata)); + if (!secondary_metadata) { + log_err("Unable to allocate memory for reading metadata\n"); + return -ENOMEM; + } + + ret = gpt_read_metadata(desc, pri_metadata, primary_mpart); + if (ret < 0) { + log_err("Failed to read the metadata from the device\n"); + ret = -EIO; + goto out; + } + + ret = gpt_verify_metadata(pri_metadata, 1); + if (!ret) + valid_partitions |= PRIMARY_VALID; + + /* Now check the secondary partition */ + ret = gpt_read_metadata(desc, secondary_metadata, secondary_mpart); + if (ret < 0) { + log_err("Failed to read the metadata from the device\n"); + ret = -EIO; + goto out; + } + + ret = gpt_verify_metadata(secondary_metadata, 0); + if (!ret) + valid_partitions |= SECONDARY_VALID; + + if (valid_partitions == (PRIMARY_VALID | SECONDARY_VALID)) { + ret = -1; + /* + * Before returning, check that both the + * metadata copies are the same. If not, + * the metadata copies need to be + * re-populated. + */ + if (!memcmp(pri_metadata, secondary_metadata, + sizeof(*pri_metadata))) + ret = 0; + goto out; + } else if (valid_partitions == SECONDARY_VALID) { + ret = gpt_write_metadata_partition(desc, secondary_metadata, + primary_mpart); + if (ret < 0) { + log_err("Restoring primary metadata partition failed\n"); + goto out; + } + } else if (valid_partitions == PRIMARY_VALID) { + ret = gpt_write_metadata_partition(desc, pri_metadata, + secondary_mpart); + if (ret < 0) { + log_err("Restoring secondary metadata partition failed\n"); + goto out; + } + } else { + ret = -1; + } + +out: + free(pri_metadata); + + return ret; +} + +static int gpt_fill_partition_guid_array(struct blk_desc *desc, + efi_guid_t **part_guid_arr, + u32 *nparts) +{ + int ret, i; + u32 parts; + gpt_entry *gpt_pte = NULL; + const efi_guid_t null_guid = NULL_GUID; + + ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, + desc->blksz); + + ret = get_gpt_hdr_parts(desc, gpt_head, &gpt_pte); + if (ret < 0) { + log_err("Error getting GPT header and partitions\n"); + ret = -EIO; + goto out; + } + + *nparts = gpt_head->num_partition_entries; + + /* + * There could be a scenario where the number of partition entries + * configured in the GPT header is the default value of 128. Find + * the actual number of populated partitioned entries + */ + for (i = 0, parts = 0; i < *nparts; i++) { + if (!guidcmp(&gpt_pte[i].partition_type_guid, &null_guid)) + continue; + ++parts; + } + + *nparts = parts; + *part_guid_arr = malloc(sizeof(efi_guid_t) * *nparts); + if (!part_guid_arr) { + log_err("Unable to allocate memory for guid array\n"); + ret = -ENOMEM; + goto out; + } + + for (i = 0; i < *nparts; i++) { + guidcpy((*part_guid_arr + i), + &gpt_pte[i].partition_type_guid); + } + +out: + free(gpt_pte); + return ret; +} + +int fwu_gpt_get_active_index(u32 *active_idx) +{ + int ret; + struct fwu_metadata *metadata; + + ret = gpt_get_valid_metadata(&metadata); + if (ret < 0) { + log_err("Unable to get valid metadata\n"); + goto out; + } + + /* + * Found the metadata partition, now read the active_index + * value + */ + *active_idx = metadata->active_index; + if (*active_idx > CONFIG_FWU_NUM_BANKS - 1) { + printf("Active index value read is incorrect\n"); + ret = -EINVAL; + goto out; + } + +out: + free(metadata); + + 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 nparts; + gpt_entry *gpt_pte = NULL; + struct fwu_metadata *metadata; + struct fwu_image_entry *img_entry; + struct fwu_image_bank_info *img_bank_info; + efi_guid_t unique_part_guid; + efi_guid_t image_guid = NULL_GUID; + + ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, + desc->blksz); + + ret = gpt_get_valid_metadata(&metadata); + if (ret < 0) { + log_err("Unable to read valid metadata\n"); + goto out; + } + + /* + * The 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, + &metadata->img_entry[i].image_type_uuid)) { + img_entry = &metadata->img_entry[i]; + img_bank_info = &img_entry->img_bank_info[update_bank]; + guidcpy(&image_guid, &img_bank_info->image_uuid); + } + } + + /* + * 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 + */ + ret = get_gpt_hdr_parts(desc, gpt_head, &gpt_pte); + if (ret < 0) { + log_err("Error getting GPT header and partitions\n"); + ret = -EIO; + goto out; + } + + nparts = gpt_head->num_partition_entries; + + for (i = 0; i < nparts; i++) { + unique_part_guid = gpt_pte[i].unique_partition_guid; + if (!guidcmp(&unique_part_guid, &image_guid)) { + /* Found the partition */ + *alt_no = i + 1; + break; + } + } + + if (i == nparts) { + log_err("Partition with the image guid not found\n"); + ret = -EINVAL; + } + +out: + free(metadata); + free(gpt_pte); + return ret; +} + +int fwu_gpt_update_active_index(u32 active_idx) +{ + int ret; + void *buf; + u32 cur_active_index; + struct fwu_metadata *metadata; + + if (active_idx > CONFIG_FWU_NUM_BANKS) { + printf("Active index value to be updated is incorrect\n"); + return -1; + } + + ret = gpt_get_valid_metadata(&metadata); + if (ret < 0) { + log_err("Unable to get valid metadata\n"); + goto out; + } + + /* + * Update the active index and previous_active_index fields + * in the metadata + */ + cur_active_index = metadata->active_index; + metadata->active_index = active_idx; + metadata->previous_active_index = cur_active_index; + + /* + * Calculate the crc32 for the updated metadata + * and put the updated value in the metadata crc32 + * field + */ + buf = &metadata->version; + metadata->crc32 = crc32(0, buf, sizeof(*metadata) - sizeof(u32)); + + /* + * Now write this updated metadata to both the + * metadata partitions + */ + ret = gpt_update_metadata(metadata); + if (ret < 0) { + log_err("Failed to update metadata partitions\n"); + ret = -EIO; + } + +out: + free(metadata); + + return ret; +} + +int fwu_gpt_fill_partition_guid_array(efi_guid_t **part_guid_arr, u32 *nparts) +{ + 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_fill_partition_guid_array(desc, part_guid_arr, nparts); +} + +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_metadata_check(void) +{ + /* + * Check if both the copies of the metadata are valid. + * If one has gone bad, restore it from the other good + * copy. + */ + return gpt_check_metadata_validity(); +} + +int fwu_gpt_get_metadata(struct fwu_metadata **metadata) +{ + return gpt_get_valid_metadata(metadata); +} + +int fwu_gpt_revert_boot_index(u32 *active_idx) +{ + int ret; + void *buf; + u32 cur_active_index; + struct fwu_metadata *metadata; + + ret = gpt_get_valid_metadata(&metadata); + if (ret < 0) { + log_err("Unable to get valid metadata\n"); + goto out; + } + + /* + * Swap the active index and previous_active_index fields + * in the metadata + */ + cur_active_index = metadata->active_index; + metadata->active_index = metadata->previous_active_index; + metadata->previous_active_index = cur_active_index; + *active_idx = metadata->active_index; + + /* + * Calculate the crc32 for the updated metadata + * and put the updated value in the metadata crc32 + * field + */ + buf = &metadata->version; + metadata->crc32 = crc32(0, buf, sizeof(*metadata) - sizeof(u32)); + + /* + * Now write this updated metadata to both the + * metadata partitions + */ + ret = gpt_update_metadata(metadata); + if (ret < 0) { + log_err("Failed to update metadata partitions\n"); + ret = -EIO; + } + +out: + free(metadata); + + 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_metadata *metadata; + struct fwu_image_entry *img_entry; + struct fwu_image_bank_info *img_bank_info; + + ret = gpt_get_valid_metadata(&metadata); + if (ret < 0) { + log_err("Unable to get valid metadata\n"); + goto out; + } + + if (action == IMAGE_ACCEPT_SET) + bank = metadata->active_index; + + nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK; + img_entry = &metadata->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 = &metadata->version; + metadata->crc32 = crc32(0, buf, sizeof(*metadata) - + sizeof(u32)); + + ret = gpt_update_metadata(metadata); + goto out; + } + } + + /* Image not found */ + ret = -EINVAL; + +out: + free(metadata); + + 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_metadata_ops fwu_gpt_blk_ops = { + .get_active_index = fwu_gpt_get_active_index, + .update_active_index = fwu_gpt_update_active_index, + .fill_partition_guid_array = fwu_gpt_fill_partition_guid_array, + .get_image_alt_num = fwu_gpt_get_image_alt_num, + .metadata_check = fwu_gpt_metadata_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_metadata = fwu_gpt_get_metadata, +};