diff options
-rw-r--r-- | env/mmc.c | 95 |
1 files changed, 77 insertions, 18 deletions
diff --git a/env/mmc.c b/env/mmc.c index 0338aa6c56a..e2f8e7ece28 100644 --- a/env/mmc.c +++ b/env/mmc.c @@ -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, ©); } + 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; |