#include <asm/unaligned.h>
#include <common.h>
#include <command.h>
+#include <fdtdec.h>
#include <ide.h>
#include <inttypes.h>
#include <malloc.h>
+#include <memalign.h>
#include <part_efi.h>
+#include <linux/compiler.h>
#include <linux/ctype.h>
DECLARE_GLOBAL_DATA_PTR;
static int pmbr_part_valid(struct partition *part);
static int is_pmbr_valid(legacy_mbr * mbr);
-static int is_gpt_valid(block_dev_desc_t *dev_desc, u64 lba,
+static int is_gpt_valid(struct blk_desc *dev_desc, u64 lba,
gpt_header *pgpt_head, gpt_entry **pgpt_pte);
-static gpt_entry *alloc_read_gpt_entries(block_dev_desc_t * dev_desc,
- gpt_header * pgpt_head);
+static gpt_entry *alloc_read_gpt_entries(struct blk_desc *dev_desc,
+ gpt_header *pgpt_head);
static int is_pte_valid(gpt_entry * pte);
static char *print_efiname(gpt_entry *pte)
gpt_h->header_crc32 = cpu_to_le32(calc_crc32);
}
-#ifdef CONFIG_EFI_PARTITION
+#if CONFIG_IS_ENABLED(EFI_PARTITION)
/*
* Public Functions (include/part.h)
*/
-void print_part_efi(block_dev_desc_t * dev_desc)
+void part_print_efi(struct blk_desc *dev_desc)
{
ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
gpt_entry *gpt_pte = NULL;
char uuid[37];
unsigned char *uuid_bin;
- if (!dev_desc) {
- printf("%s: Invalid Argument(s)\n", __func__);
- return;
- }
/* This function validates AND fills in the GPT header and PTE */
if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
gpt_head, &gpt_pte) != 1) {
uuid_bin = (unsigned char *)gpt_pte[i].partition_type_guid.b;
uuid_bin_to_str(uuid_bin, uuid, UUID_STR_FORMAT_GUID);
printf("\ttype:\t%s\n", uuid);
+#ifdef CONFIG_PARTITION_TYPE_GUID
+ if (!uuid_guid_get_str(uuid_bin, uuid))
+ printf("\ttype:\t%s\n", uuid);
+#endif
uuid_bin = (unsigned char *)gpt_pte[i].unique_partition_guid.b;
uuid_bin_to_str(uuid_bin, uuid, UUID_STR_FORMAT_GUID);
printf("\tguid:\t%s\n", uuid);
return;
}
-int get_partition_info_efi(block_dev_desc_t * dev_desc, int part,
- disk_partition_t * info)
+int part_get_info_efi(struct blk_desc *dev_desc, int part,
+ disk_partition_t *info)
{
ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
gpt_entry *gpt_pte = NULL;
/* "part" argument must be at least 1 */
- if (!dev_desc || !info || part < 1) {
+ if (part < 1) {
printf("%s: Invalid Argument(s)\n", __func__);
return -1;
}
sprintf((char *)info->name, "%s",
print_efiname(&gpt_pte[part - 1]));
- sprintf((char *)info->type, "U-Boot");
+ strcpy((char *)info->type, "U-Boot");
info->bootable = is_bootable(&gpt_pte[part - 1]);
-#ifdef CONFIG_PARTITION_UUIDS
+#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
uuid_bin_to_str(gpt_pte[part - 1].unique_partition_guid.b, info->uuid,
UUID_STR_FORMAT_GUID);
#endif
+#ifdef CONFIG_PARTITION_TYPE_GUID
+ uuid_bin_to_str(gpt_pte[part - 1].partition_type_guid.b,
+ info->type_guid, UUID_STR_FORMAT_GUID);
+#endif
debug("%s: start 0x" LBAF ", size 0x" LBAF ", name %s\n", __func__,
info->start, info->size, info->name);
return 0;
}
-int get_partition_info_efi_by_name(block_dev_desc_t *dev_desc,
- const char *name, disk_partition_t *info)
-{
- int ret;
- int i;
- for (i = 1; i < GPT_ENTRY_NUMBERS; i++) {
- ret = get_partition_info_efi(dev_desc, i, info);
- if (ret != 0) {
- /* no more entries in table */
- return -1;
- }
- if (strcmp(name, (const char *)info->name) == 0) {
- /* matched */
- return 0;
- }
- }
- return -2;
-}
-
-int test_part_efi(block_dev_desc_t * dev_desc)
+static int part_test_efi(struct blk_desc *dev_desc)
{
ALLOC_CACHE_ALIGN_BUFFER_PAD(legacy_mbr, legacymbr, 1, dev_desc->blksz);
/* Read legacy MBR from block 0 and validate it */
- if ((dev_desc->block_read(dev_desc->dev, 0, 1, (ulong *)legacymbr) != 1)
+ if ((blk_dread(dev_desc, 0, 1, (ulong *)legacymbr) != 1)
|| (is_pmbr_valid(legacymbr) != 1)) {
return -1;
}
*
* @return - zero on success, otherwise error
*/
-static int set_protective_mbr(block_dev_desc_t *dev_desc)
+static int set_protective_mbr(struct blk_desc *dev_desc)
{
/* Setup the Protective MBR */
ALLOC_CACHE_ALIGN_BUFFER(legacy_mbr, p_mbr, 1);
printf("%s: calloc failed!\n", __func__);
return -1;
}
+
+ /* Read MBR to backup boot code if it exists */
+ if (blk_dread(dev_desc, 0, 1, p_mbr) != 1) {
+ error("** Can't read from device %d **\n", dev_desc->devnum);
+ return -1;
+ }
+
/* Append signature */
p_mbr->signature = MSDOS_MBR_SIGNATURE;
p_mbr->partition_record[0].sys_ind = EFI_PMBR_OSTYPE_EFI_GPT;
p_mbr->partition_record[0].nr_sects = (u32) dev_desc->lba - 1;
/* Write MBR sector to the MMC device */
- if (dev_desc->block_write(dev_desc->dev, 0, 1, p_mbr) != 1) {
+ if (blk_dwrite(dev_desc, 0, 1, p_mbr) != 1) {
printf("** Can't write to device %d **\n",
- dev_desc->dev);
+ dev_desc->devnum);
return -1;
}
return 0;
}
-int write_gpt_table(block_dev_desc_t *dev_desc,
+int write_gpt_table(struct blk_desc *dev_desc,
gpt_header *gpt_h, gpt_entry *gpt_e)
{
const int pte_blk_cnt = BLOCK_CNT((gpt_h->num_partition_entries
gpt_h->header_crc32 = cpu_to_le32(calc_crc32);
/* Write the First GPT to the block right after the Legacy MBR */
- if (dev_desc->block_write(dev_desc->dev, 1, 1, gpt_h) != 1)
+ if (blk_dwrite(dev_desc, 1, 1, gpt_h) != 1)
goto err;
- if (dev_desc->block_write(dev_desc->dev, 2, pte_blk_cnt, gpt_e)
- != pte_blk_cnt)
+ if (blk_dwrite(dev_desc, le64_to_cpu(gpt_h->partition_entry_lba),
+ pte_blk_cnt, gpt_e) != pte_blk_cnt)
goto err;
prepare_backup_gpt_header(gpt_h);
- if (dev_desc->block_write(dev_desc->dev,
- (lbaint_t)le64_to_cpu(gpt_h->last_usable_lba)
- + 1,
- pte_blk_cnt, gpt_e) != pte_blk_cnt)
+ if (blk_dwrite(dev_desc, (lbaint_t)le64_to_cpu(gpt_h->last_usable_lba)
+ + 1, pte_blk_cnt, gpt_e) != pte_blk_cnt)
goto err;
- if (dev_desc->block_write(dev_desc->dev,
- (lbaint_t)le64_to_cpu(gpt_h->my_lba), 1,
- gpt_h) != 1)
+ if (blk_dwrite(dev_desc, (lbaint_t)le64_to_cpu(gpt_h->my_lba), 1,
+ gpt_h) != 1)
goto err;
debug("GPT successfully written to block device!\n");
return 0;
err:
- printf("** Can't write to device %d **\n", dev_desc->dev);
+ printf("** Can't write to device %d **\n", dev_desc->devnum);
return -1;
}
le64_to_cpu(gpt_h->last_usable_lba);
int i, k;
size_t efiname_len, dosname_len;
-#ifdef CONFIG_PARTITION_UUIDS
+#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
char *str_uuid;
unsigned char *bin_uuid;
#endif
+#ifdef CONFIG_PARTITION_TYPE_GUID
+ char *str_type_guid;
+ unsigned char *bin_type_guid;
+#endif
for (i = 0; i < parts; i++) {
/* partition starting lba */
gpt_e[i].starting_lba = cpu_to_le64(offset);
offset += partitions[i].size;
}
- if (offset >= last_usable_lba) {
+ if (offset > (last_usable_lba + 1)) {
printf("Partitions layout exceds disk size\n");
return -1;
}
else
gpt_e[i].ending_lba = cpu_to_le64(offset - 1);
+#ifdef CONFIG_PARTITION_TYPE_GUID
+ str_type_guid = partitions[i].type_guid;
+ bin_type_guid = gpt_e[i].partition_type_guid.b;
+ if (strlen(str_type_guid)) {
+ if (uuid_str_to_bin(str_type_guid, bin_type_guid,
+ UUID_STR_FORMAT_GUID)) {
+ printf("Partition no. %d: invalid type guid: %s\n",
+ i, str_type_guid);
+ return -1;
+ }
+ } else {
+ /* default partition type GUID */
+ memcpy(bin_type_guid,
+ &PARTITION_BASIC_DATA_GUID, 16);
+ }
+#else
/* partition type GUID */
memcpy(gpt_e[i].partition_type_guid.b,
&PARTITION_BASIC_DATA_GUID, 16);
+#endif
-#ifdef CONFIG_PARTITION_UUIDS
+#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
str_uuid = partitions[i].uuid;
bin_uuid = gpt_e[i].unique_partition_guid.b;
- if (uuid_str_to_bin(str_uuid, bin_uuid, UUID_STR_FORMAT_STD)) {
+ if (uuid_str_to_bin(str_uuid, bin_uuid, UUID_STR_FORMAT_GUID)) {
printf("Partition no. %d: invalid guid: %s\n",
i, str_uuid);
return -1;
memset(&gpt_e[i].attributes, 0,
sizeof(gpt_entry_attributes));
+ if (partitions[i].bootable)
+ gpt_e[i].attributes.fields.legacy_bios_bootable = 1;
+
/* partition name */
efiname_len = sizeof(gpt_e[i].partition_name)
/ sizeof(efi_char16_t);
return 0;
}
-int gpt_fill_header(block_dev_desc_t *dev_desc, gpt_header *gpt_h,
+static uint32_t partition_entries_offset(struct blk_desc *dev_desc)
+{
+ uint32_t offset_blks = 2;
+ int __maybe_unused config_offset;
+
+#if defined(CONFIG_EFI_PARTITION_ENTRIES_OFF)
+ /*
+ * Some architectures require their SPL loader at a fixed
+ * address within the first 16KB of the disk. To avoid an
+ * overlap with the partition entries of the EFI partition
+ * table, the first safe offset (in bytes, from the start of
+ * the disk) for the entries can be set in
+ * CONFIG_EFI_PARTITION_ENTRIES_OFF.
+ */
+ offset_blks =
+ PAD_TO_BLOCKSIZE(CONFIG_EFI_PARTITION_ENTRIES_OFF, dev_desc);
+#endif
+
+#if defined(CONFIG_OF_CONTROL)
+ /*
+ * Allow the offset of the first partition entires (in bytes
+ * from the start of the device) to be specified as a property
+ * of the device tree '/config' node.
+ */
+ config_offset = fdtdec_get_config_int(gd->fdt_blob,
+ "u-boot,efi-partition-entries-offset",
+ -EINVAL);
+ if (config_offset != -EINVAL)
+ offset_blks = PAD_TO_BLOCKSIZE(config_offset, dev_desc);
+#endif
+
+ debug("efi: partition entries offset (in blocks): %d\n", offset_blks);
+
+ /*
+ * The earliest LBA this can be at is LBA#2 (i.e. right behind
+ * the (protective) MBR and the GPT header.
+ */
+ if (offset_blks < 2)
+ offset_blks = 2;
+
+ return offset_blks;
+}
+
+int gpt_fill_header(struct blk_desc *dev_desc, gpt_header *gpt_h,
char *str_guid, int parts_count)
{
gpt_h->signature = cpu_to_le64(GPT_HEADER_SIGNATURE);
gpt_h->header_size = cpu_to_le32(sizeof(gpt_header));
gpt_h->my_lba = cpu_to_le64(1);
gpt_h->alternate_lba = cpu_to_le64(dev_desc->lba - 1);
- gpt_h->first_usable_lba = cpu_to_le64(34);
gpt_h->last_usable_lba = cpu_to_le64(dev_desc->lba - 34);
- gpt_h->partition_entry_lba = cpu_to_le64(2);
+ gpt_h->partition_entry_lba =
+ cpu_to_le64(partition_entries_offset(dev_desc));
+ gpt_h->first_usable_lba =
+ cpu_to_le64(le64_to_cpu(gpt_h->partition_entry_lba) + 32);
gpt_h->num_partition_entries = cpu_to_le32(GPT_ENTRY_NUMBERS);
gpt_h->sizeof_partition_entry = cpu_to_le32(sizeof(gpt_entry));
gpt_h->header_crc32 = 0;
return 0;
}
-int gpt_restore(block_dev_desc_t *dev_desc, char *str_disk_guid,
+int gpt_restore(struct blk_desc *dev_desc, char *str_disk_guid,
disk_partition_t *partitions, int parts_count)
{
int ret;
return ret;
}
-int is_valid_gpt_buf(block_dev_desc_t *dev_desc, void *buf)
+static void gpt_convert_efi_name_to_char(char *s, efi_char16_t *es, int n)
+{
+ char *ess = (char *)es;
+ int i, j;
+
+ memset(s, '\0', n);
+
+ for (i = 0, j = 0; j < n; i += 2, j++) {
+ s[j] = ess[i];
+ if (!ess[i])
+ return;
+ }
+}
+
+int gpt_verify_headers(struct blk_desc *dev_desc, gpt_header *gpt_head,
+ gpt_entry **gpt_pte)
+{
+ /*
+ * This function validates AND
+ * fills in the GPT header and PTE
+ */
+ if (is_gpt_valid(dev_desc,
+ GPT_PRIMARY_PARTITION_TABLE_LBA,
+ gpt_head, gpt_pte) != 1) {
+ printf("%s: *** ERROR: Invalid GPT ***\n",
+ __func__);
+ return -1;
+ }
+ if (is_gpt_valid(dev_desc, (dev_desc->lba - 1),
+ gpt_head, gpt_pte) != 1) {
+ printf("%s: *** ERROR: Invalid Backup GPT ***\n",
+ __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+int gpt_verify_partitions(struct blk_desc *dev_desc,
+ disk_partition_t *partitions, int parts,
+ gpt_header *gpt_head, gpt_entry **gpt_pte)
+{
+ char efi_str[PARTNAME_SZ + 1];
+ u64 gpt_part_size;
+ gpt_entry *gpt_e;
+ int ret, i;
+
+ ret = gpt_verify_headers(dev_desc, gpt_head, gpt_pte);
+ if (ret)
+ return ret;
+
+ gpt_e = *gpt_pte;
+
+ for (i = 0; i < parts; i++) {
+ if (i == gpt_head->num_partition_entries) {
+ error("More partitions than allowed!\n");
+ return -1;
+ }
+
+ /* Check if GPT and ENV partition names match */
+ gpt_convert_efi_name_to_char(efi_str, gpt_e[i].partition_name,
+ PARTNAME_SZ + 1);
+
+ debug("%s: part: %2d name - GPT: %16s, ENV: %16s ",
+ __func__, i, efi_str, partitions[i].name);
+
+ if (strncmp(efi_str, (char *)partitions[i].name,
+ sizeof(partitions->name))) {
+ error("Partition name: %s does not match %s!\n",
+ efi_str, (char *)partitions[i].name);
+ return -1;
+ }
+
+ /* Check if GPT and ENV sizes match */
+ gpt_part_size = le64_to_cpu(gpt_e[i].ending_lba) -
+ le64_to_cpu(gpt_e[i].starting_lba) + 1;
+ debug("size(LBA) - GPT: %8llu, ENV: %8llu ",
+ (unsigned long long)gpt_part_size,
+ (unsigned long long)partitions[i].size);
+
+ if (le64_to_cpu(gpt_part_size) != partitions[i].size) {
+ /* We do not check the extend partition size */
+ if ((i == parts - 1) && (partitions[i].size == 0))
+ continue;
+
+ error("Partition %s size: %llu does not match %llu!\n",
+ efi_str, (unsigned long long)gpt_part_size,
+ (unsigned long long)partitions[i].size);
+ return -1;
+ }
+
+ /*
+ * Start address is optional - check only if provided
+ * in '$partition' variable
+ */
+ if (!partitions[i].start) {
+ debug("\n");
+ continue;
+ }
+
+ /* Check if GPT and ENV start LBAs match */
+ debug("start LBA - GPT: %8llu, ENV: %8llu\n",
+ le64_to_cpu(gpt_e[i].starting_lba),
+ (unsigned long long)partitions[i].start);
+
+ if (le64_to_cpu(gpt_e[i].starting_lba) != partitions[i].start) {
+ error("Partition %s start: %llu does not match %llu!\n",
+ efi_str, le64_to_cpu(gpt_e[i].starting_lba),
+ (unsigned long long)partitions[i].start);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int is_valid_gpt_buf(struct blk_desc *dev_desc, void *buf)
{
gpt_header *gpt_h;
gpt_entry *gpt_e;
return 0;
}
-int write_mbr_and_gpt_partitions(block_dev_desc_t *dev_desc, void *buf)
+int write_mbr_and_gpt_partitions(struct blk_desc *dev_desc, void *buf)
{
gpt_header *gpt_h;
gpt_entry *gpt_e;
/* write MBR */
lba = 0; /* MBR is always at 0 */
cnt = 1; /* MBR (1 block) */
- if (dev_desc->block_write(dev_desc->dev, lba, cnt, buf) != cnt) {
+ if (blk_dwrite(dev_desc, lba, cnt, buf) != cnt) {
printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n",
__func__, "MBR", cnt, lba);
return 1;
/* write Primary GPT */
lba = GPT_PRIMARY_PARTITION_TABLE_LBA;
cnt = 1; /* GPT Header (1 block) */
- if (dev_desc->block_write(dev_desc->dev, lba, cnt, gpt_h) != cnt) {
+ if (blk_dwrite(dev_desc, lba, cnt, gpt_h) != cnt) {
printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n",
__func__, "Primary GPT Header", cnt, lba);
return 1;
lba = le64_to_cpu(gpt_h->partition_entry_lba);
cnt = gpt_e_blk_cnt;
- if (dev_desc->block_write(dev_desc->dev, lba, cnt, gpt_e) != cnt) {
+ if (blk_dwrite(dev_desc, lba, cnt, gpt_e) != cnt) {
printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n",
__func__, "Primary GPT Entries", cnt, lba);
return 1;
/* write Backup GPT */
lba = le64_to_cpu(gpt_h->partition_entry_lba);
cnt = gpt_e_blk_cnt;
- if (dev_desc->block_write(dev_desc->dev, lba, cnt, gpt_e) != cnt) {
+ if (blk_dwrite(dev_desc, lba, cnt, gpt_e) != cnt) {
printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n",
__func__, "Backup GPT Entries", cnt, lba);
return 1;
lba = le64_to_cpu(gpt_h->my_lba);
cnt = 1; /* GPT Header (1 block) */
- if (dev_desc->block_write(dev_desc->dev, lba, cnt, gpt_h) != cnt) {
+ if (blk_dwrite(dev_desc, lba, cnt, gpt_h) != cnt) {
printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n",
__func__, "Backup GPT Header", cnt, lba);
return 1;
* Description: returns 1 if valid, 0 on error.
* If valid, returns pointers to PTEs.
*/
-static int is_gpt_valid(block_dev_desc_t *dev_desc, u64 lba,
+static int is_gpt_valid(struct blk_desc *dev_desc, u64 lba,
gpt_header *pgpt_head, gpt_entry **pgpt_pte)
{
if (!dev_desc || !pgpt_head) {
}
/* Read GPT Header from device */
- if (dev_desc->block_read(dev_desc->dev, (lbaint_t)lba, 1, pgpt_head)
- != 1) {
+ if (blk_dread(dev_desc, (lbaint_t)lba, 1, pgpt_head) != 1) {
printf("*** ERROR: Can't read GPT header ***\n");
return 0;
}
* Allocates space for PTEs based on information found in @gpt.
* Notes: remember to free pte when you're done!
*/
-static gpt_entry *alloc_read_gpt_entries(block_dev_desc_t * dev_desc,
- gpt_header * pgpt_head)
+static gpt_entry *alloc_read_gpt_entries(struct blk_desc *dev_desc,
+ gpt_header *pgpt_head)
{
size_t count = 0, blk_cnt;
+ lbaint_t blk;
gpt_entry *pte = NULL;
if (!dev_desc || !pgpt_head) {
count = le32_to_cpu(pgpt_head->num_partition_entries) *
le32_to_cpu(pgpt_head->sizeof_partition_entry);
- debug("%s: count = %u * %u = %zu\n", __func__,
+ debug("%s: count = %u * %u = %lu\n", __func__,
(u32) le32_to_cpu(pgpt_head->num_partition_entries),
- (u32) le32_to_cpu(pgpt_head->sizeof_partition_entry), count);
+ (u32) le32_to_cpu(pgpt_head->sizeof_partition_entry),
+ (ulong)count);
/* Allocate memory for PTE, remember to FREE */
if (count != 0) {
}
if (count == 0 || pte == NULL) {
- printf("%s: ERROR: Can't allocate 0x%zX "
- "bytes for GPT Entries\n",
- __func__, count);
+ printf("%s: ERROR: Can't allocate %#lX bytes for GPT Entries\n",
+ __func__, (ulong)count);
return NULL;
}
/* Read GPT Entries from device */
+ blk = le64_to_cpu(pgpt_head->partition_entry_lba);
blk_cnt = BLOCK_CNT(count, dev_desc);
- if (dev_desc->block_read (dev_desc->dev,
- (lbaint_t)le64_to_cpu(pgpt_head->partition_entry_lba),
- (lbaint_t) (blk_cnt), pte)
- != blk_cnt) {
-
+ if (blk_dread(dev_desc, blk, (lbaint_t)blk_cnt, pte) != blk_cnt) {
printf("*** ERROR: Can't read GPT Entries ***\n");
free(pte);
return NULL;
return 1;
}
}
+
+/*
+ * Add an 'a_' prefix so it comes before 'dos' in the linker list. We need to
+ * check EFI first, since a DOS partition is often used as a 'protective MBR'
+ * with EFI.
+ */
+U_BOOT_PART_TYPE(a_efi) = {
+ .name = "EFI",
+ .part_type = PART_TYPE_EFI,
+ .max_entries = GPT_ENTRY_NUMBERS,
+ .get_info = part_get_info_ptr(part_get_info_efi),
+ .print = part_print_ptr(part_print_efi),
+ .test = part_test_efi,
+};
#endif