u-boot/lib/fwu_updates/fwu_mtd.c
Tom Rini 7e52d6ccfb Merge patch series "FWU: Add support for FWU metadata version 2"
Sughosh Ganu <sughosh.ganu@linaro.org> says:

The following patch series adds support for version 2 of the FWU
metadata. The version 2 metadata structure is defined in the latest
revision of the FWU specification [1].

The earlier versions of these patches were migrating to a version 2
only support in U-Boot, similar to TF-A. However, based on feedback
from ST [2], this series has been updated to support both versions. A
platform would still be needed to enable one of the two versions of
metadata through a config symbol.

TF-A has code which reads the FWU metadata and boots the platform from
the active partition. TF-A has decided to migrate the FWU code to a
version 2 only support. These changes have been merged in upstream
TF-A.

These changes have been tested on the ST DK2 board, which uses the GPT
based partitioning scheme. Both V1 and V2 metadata versions have been
tested on the DK2 board.

These changes need to be tested on platforms with MTD partitioned
storage devices.
2024-05-24 13:42:07 -06:00

187 lines
4.2 KiB
C

// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2023, Linaro Limited
*/
#include <dm.h>
#include <dfu.h>
#include <fwu.h>
#include <fwu_mdata.h>
#include <log.h>
#include <malloc.h>
#include <mtd.h>
#include <uuid.h>
#include <stdio.h>
#include <dm/ofnode.h>
static struct fwu_mtd_image_info *mtd_img_by_uuid(const char *uuidbuf)
{
int num_images;
struct fwu_mdata_mtd_priv *mtd_priv = dev_get_priv(fwu_get_dev());
struct fwu_mtd_image_info *image_info = mtd_priv->fwu_mtd_images;
if (!image_info)
return NULL;
num_images = CONFIG_FWU_NUM_BANKS *
CONFIG_FWU_NUM_IMAGES_PER_BANK;
for (int i = 0; i < num_images; i++)
if (!strcmp(uuidbuf, image_info[i].uuidbuf))
return &image_info[i];
return NULL;
}
int fwu_mtd_get_alt_num(efi_guid_t *image_id, u8 *alt_num,
const char *mtd_dev)
{
struct fwu_mtd_image_info *mtd_img_info;
char uuidbuf[UUID_STR_LEN + 1];
fdt_addr_t offset, size = 0;
struct dfu_entity *dfu;
int i, nalt, ret;
mtd_probe_devices();
uuid_bin_to_str(image_id->b, uuidbuf, UUID_STR_FORMAT_STD);
mtd_img_info = mtd_img_by_uuid(uuidbuf);
if (!mtd_img_info) {
log_err("%s: Not found partition for image %s\n", __func__, uuidbuf);
return -ENOENT;
}
offset = mtd_img_info->start;
size = mtd_img_info->size;
ret = dfu_init_env_entities(NULL, NULL);
if (ret)
return -ENOENT;
nalt = 0;
list_for_each_entry(dfu, &dfu_list, list)
nalt++;
if (!nalt) {
log_warning("No entities in dfu_alt_info\n");
dfu_free_entities();
return -ENOENT;
}
ret = -ENOENT;
for (i = 0; i < nalt; i++) {
dfu = dfu_get_entity(i);
/* Only MTD RAW access */
if (!dfu || dfu->dev_type != DFU_DEV_MTD ||
dfu->layout != DFU_RAW_ADDR ||
dfu->data.mtd.start != offset ||
dfu->data.mtd.size != size)
continue;
*alt_num = dfu->alt;
ret = 0;
break;
}
dfu_free_entities();
log_debug("%s: %s -> %d\n", __func__, uuidbuf, *alt_num);
return ret;
}
/**
* fwu_plat_get_alt_num() - Get the DFU Alt Num for the image from the platform
* @dev: FWU device
* @image_id: Image GUID for which DFU alt number needs to be retrieved
* @alt_num: Pointer to the alt_num
*
* Get the DFU alt number from the platform for the image specified by the
* image GUID.
*
* 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_id,
u8 *alt_num)
{
return fwu_mtd_get_alt_num(image_id, alt_num, "nor1");
}
static int gen_image_alt_info(char *buf, size_t len,
struct fwu_image_entry *img, struct mtd_info *mtd)
{
char *p = buf, *end = buf + len;
int i;
p += snprintf(p, end - p, "mtd %s", mtd->name);
if (end < p) {
log_err("%s:%d Run out of buffer\n", __func__, __LINE__);
return -E2BIG;
}
/*
* List the image banks in the FWU mdata and search the corresponding
* partition based on partition's uuid.
*/
for (i = 0; i < CONFIG_FWU_NUM_BANKS; i++) {
struct fwu_mtd_image_info *mtd_img_info;
struct fwu_image_bank_info *bank;
char uuidbuf[UUID_STR_LEN + 1];
u32 offset, size;
/* Query a partition by image UUID */
bank = &img->img_bank_info[i];
uuid_bin_to_str(bank->image_guid.b, uuidbuf, UUID_STR_FORMAT_STD);
mtd_img_info = mtd_img_by_uuid(uuidbuf);
if (!mtd_img_info) {
log_err("%s: Not found partition for image %s\n", __func__, uuidbuf);
break;
}
offset = mtd_img_info->start;
size = mtd_img_info->size;
p += snprintf(p, end - p, "%sbank%d raw %x %x",
i == 0 ? "=" : ";", i, offset, size);
if (end < p) {
log_err("%s:%d Run out of buffer\n", __func__, __LINE__);
return -E2BIG;
}
}
if (i == CONFIG_FWU_NUM_BANKS)
return 0;
return -ENOENT;
}
int fwu_gen_alt_info_from_mtd(char *buf, size_t len, struct mtd_info *mtd)
{
int i, l, ret;
struct fwu_data *data = fwu_get_data();
struct fwu_image_entry *img_entry;
for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; i++) {
img_entry = &data->fwu_images[i];
ret = gen_image_alt_info(buf, len, img_entry, mtd);
if (ret)
break;
l = strlen(buf);
/* Replace the last ';' with '&' if there is another image. */
if (i != CONFIG_FWU_NUM_IMAGES_PER_BANK - 1 && l) {
buf[l] = '&';
buf++;
}
len -= l;
buf += l;
}
return ret;
}