summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--env/mmc.c95
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, &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;