Merge patch series "env: mmc: fix use of two separate partitions with proper type GUID"

Rasmus Villemoes <rasmus.villemoes@prevas.dk> says:

I always define a disk layout with two separate partitions for the two
copies of the U-Boot environment and, being the one who introduced the
type GUID for such partitions, of course also set those partitions'
type GUID appropriately.

This has worked just fine, but, it turns out, only because I've never
had CONFIG_PARTITION_TYPE_GUID enabled on any of my boards; I've
always just set the offsets of the two partitions via the config
variables CONFIG_ENV_OFFSET(,_REDUND).

I didn't even know that env/mmc.c had learnt to look for the env
partition based on the type GUID, or that that would overrule the
ENV_OFFSET config variables, until I experienced weird random
corruption while doing bringup for an stm32 board, where
PARTITION_TYPE_GUID is automatically set because it is select'ed by
CMD_STM32PROG.

These patches try to fix the code to fit my scheme, while not changing
anything for existing setups that use the two-copies-one-partition
scheme, other than complaining loudly if the system is misconfigured
and avoiding such random corruption of neighbouring partitions.
This commit is contained in:
Tom Rini 2024-10-01 08:46:01 -06:00
commit 667a671cca

95
env/mmc.c vendored
View file

@ -53,11 +53,74 @@ DECLARE_GLOBAL_DATA_PTR;
#endif
#if CONFIG_IS_ENABLED(OF_CONTROL)
static int mmc_env_partition_by_name(struct blk_desc *desc, const char *str,
struct disk_partition *info)
{
int i, ret;
for (i = 1;; i++) {
ret = part_get_info(desc, i, info);
if (ret < 0)
return ret;
if (!strncmp((const char *)info->name, str, sizeof(info->name)))
return 0;
}
}
/*
* Look for one or two partitions with the U-Boot environment GUID.
*
* If *copy is 0, return the first such partition.
*
* If *copy is 1 on entry and two partitions are found, return the
* second partition and set *copy = 0.
*
* If *copy is 1 on entry and only one partition is found, return that
* partition, leaving *copy unmodified.
*/
static int mmc_env_partition_by_guid(struct blk_desc *desc, struct disk_partition *info,
int *copy)
{
const efi_guid_t env_guid = PARTITION_U_BOOT_ENVIRONMENT;
efi_guid_t type_guid;
int i, ret, found = 0;
struct disk_partition dp;
for (i = 1;; i++) {
ret = part_get_info(desc, i, &dp);
if (ret < 0)
break;
uuid_str_to_bin(disk_partition_type_guid(&dp), type_guid.b, UUID_STR_FORMAT_GUID);
if (!memcmp(&env_guid, &type_guid, sizeof(efi_guid_t))) {
memcpy(info, &dp, sizeof(dp));
/* If *copy is 0, we are only looking for the first partition. */
if (*copy == 0)
return 0;
/* This was the second such partition. */
if (found) {
*copy = 0;
return 0;
}
found = 1;
}
}
/* The loop ended after finding at most one matching partition. */
if (found)
ret = 0;
return ret;
}
static inline int mmc_offset_try_partition(const char *str, int copy, s64 *val)
{
struct disk_partition info;
struct blk_desc *desc;
int len, i, ret;
lbaint_t len;
int ret;
char dev_str[4];
snprintf(dev_str, sizeof(dev_str), "%d", mmc_get_env_dev());
@ -65,28 +128,24 @@ static inline int mmc_offset_try_partition(const char *str, int copy, s64 *val)
if (ret < 0)
return (ret);
for (i = 1;;i++) {
ret = part_get_info(desc, i, &info);
if (ret < 0)
return ret;
if (str && !strncmp((const char *)info.name, str, sizeof(info.name)))
break;
#ifdef CONFIG_PARTITION_TYPE_GUID
if (!str) {
const efi_guid_t env_guid = PARTITION_U_BOOT_ENVIRONMENT;
efi_guid_t type_guid;
uuid_str_to_bin(info.type_guid, type_guid.b, UUID_STR_FORMAT_GUID);
if (!memcmp(&env_guid, &type_guid, sizeof(efi_guid_t)))
break;
}
#endif
if (str) {
ret = mmc_env_partition_by_name(desc, str, &info);
} else if (IS_ENABLED(CONFIG_PARTITION_TYPE_GUID) && !str) {
ret = mmc_env_partition_by_guid(desc, &info, &copy);
}
if (ret < 0)
return ret;
/* round up to info.blksz */
len = DIV_ROUND_UP(CONFIG_ENV_SIZE, info.blksz);
if ((1 + copy) * len > info.size) {
printf("Partition '%s' [0x"LBAF"; 0x"LBAF"] too small for %senvironment, required size 0x"LBAF" blocks\n",
(const char*)info.name, info.start, info.size,
copy ? "two copies of " : "", (1 + copy)*len);
return -ENOSPC;
}
/* use the top of the partion for the environment */
*val = (info.start + info.size - (1 + copy) * len) * info.blksz;