* [U-Boot] [PATCH] Add support for CONFIG_EFI_PARTITION (GUID Partition Table)
@ 2008-09-23 21:39 richardretanubun
2008-09-23 22:09 ` Wolfgang Denk
0 siblings, 1 reply; 9+ messages in thread
From: richardretanubun @ 2008-09-23 21:39 UTC (permalink / raw)
To: u-boot
Signed-off-by: Richard Retanubun <RichardRetanubun@RugggedCom.com>
---
disk/Makefile | 1 +
disk/part.c | 33 ++++-
disk/part_efi.c | 428 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
disk/part_efi.h | 138 ++++++++++++++++++
include/part.h | 8 +
5 files changed, 605 insertions(+), 3 deletions(-)
create mode 100644 disk/part_efi.c
create mode 100644 disk/part_efi.h
diff --git a/disk/Makefile b/disk/Makefile
index f19d18d..c479145 100644
--- a/disk/Makefile
+++ b/disk/Makefile
@@ -32,6 +32,7 @@ COBJS-y += part_mac.o
COBJS-y += part_dos.o
COBJS-y += part_iso.o
COBJS-y += part_amiga.o
+COBJS-y += part_efi.o
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
diff --git a/disk/part.c b/disk/part.c
index 5c4bf6b..9db6a78 100644
--- a/disk/part.c
+++ b/disk/part.c
@@ -198,7 +198,8 @@ void dev_print (block_dev_desc_t *dev_desc)
#if defined(CONFIG_MAC_PARTITION) || \
defined(CONFIG_DOS_PARTITION) || \
defined(CONFIG_ISO_PARTITION) || \
- defined(CONFIG_AMIGA_PARTITION)
+ defined(CONFIG_AMIGA_PARTITION) || \
+ defined(CONFIG_EFI_PARTITION)
void init_part (block_dev_desc_t * dev_desc)
{
@@ -216,6 +217,14 @@ void init_part (block_dev_desc_t * dev_desc)
}
#endif
+/* must be placed before DOS partition detection */
+#ifdef CONFIG_EFI_PARTITION
+ if (test_part_efi(dev_desc) == 0) {
+ dev_desc->part_type = PART_TYPE_EFI;
+ return;
+ }
+#endif
+
#ifdef CONFIG_DOS_PARTITION
if (test_part_dos(dev_desc) == 0) {
dev_desc->part_type = PART_TYPE_DOS;
@@ -272,6 +281,15 @@ int get_partition_info (block_dev_desc_t *dev_desc, int part
}
break;
#endif
+
+#ifdef CONFIG_EFI_PARTITION
+ case PART_TYPE_EFI:
+ if (get_partition_info_efi(dev_desc,part,info) == 0) {
+ PRINTF ("## Valid EFI partition found ##\n");
+ return (0);
+ }
+ break;
+#endif
default:
break;
}
@@ -342,14 +360,23 @@ void print_part (block_dev_desc_t * dev_desc)
print_part_amiga (dev_desc);
return;
#endif
+
+#ifdef CONFIG_EFI_PARTITION
+ case PART_TYPE_EFI:
+ PRINTF ("## Testing for valid EFI partition ##\n");
+ print_part_header ("EFI", dev_desc);
+ print_part_efi (dev_desc);
+ return;
+#endif
}
puts ("## Unknown partition table\n");
}
-#else /* neither MAC nor DOS nor ISO partition configured */
+#else /* neither MAC nor DOS nor ISO nor AMIGA nor EFI partition configured */
# error neither CONFIG_MAC_PARTITION nor CONFIG_DOS_PARTITION
-# error nor CONFIG_ISO_PARTITION configured!
+# error nor CONFIG_ISO_PARTITION nor CONFIG_AMIGA_PARTITION
+# error nor CONFIG_EFI_PARTITION configured!
#endif
#endif
diff --git a/disk/part_efi.c b/disk/part_efi.c
new file mode 100644
index 0000000..7f89a2c
--- /dev/null
+++ b/disk/part_efi.c
@@ -0,0 +1,428 @@
+/*
+ * Copyright (C) 2008 RuggedCom, Inc.
+ * Richard Retanubun <RichardRetanubun@RuggedCom.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Problems with CFG_64BIT_LBA:
+ *
+ * struct disk_partition.start in include/part.h is sized as ulong.
+ * When CFG_64BIT_LBA is activated, lbaint_t changes from ulong to uint64_t.
+ * For now, it is cast back to ulong at assignment.
+ *
+ * This limits the maximum size of disk addressable to < 2 Terra Bytes
+ */
+#include <common.h>
+#include <command.h>
+#include <ide.h>
+#include <malloc.h>
+#include "part_efi.h"
+
+#if (defined(CONFIG_CMD_IDE) || \
+ defined(CONFIG_CMD_SATA) || \
+ defined(CONFIG_CMD_SCSI) || \
+ defined(CONFIG_CMD_USB) || \
+ defined(CONFIG_MMC) || \
+ defined(CONFIG_SYSTEMACE) ) && defined(CONFIG_EFI_PARTITION)
+
+/* Convert char[2] in little endian format to the host format integer
+ */
+static inline unsigned short le16_to_int(unsigned char *le16)
+{
+ return ((le16[1] << 8) +
+ le16[0]);
+}
+
+/* Convert char[4] in little endian format to the host format integer
+ */
+static inline unsigned long le32_to_int(unsigned char *le32)
+{
+ return ((le32[3] << 24) +
+ (le32[2] << 16) +
+ (le32[1] << 8) +
+ le32[0]);
+}
+
+/* Convert char[8] in little endian format to the host format integer
+ */
+static inline unsigned long long le64_to_int(unsigned char *le64)
+{
+ return (((unsigned long long)le64[7] << 56) +
+ ((unsigned long long)le64[6] << 48) +
+ ((unsigned long long)le64[5] << 40) +
+ ((unsigned long long)le64[4] << 32) +
+ ((unsigned long long)le64[3] << 24) +
+ ((unsigned long long)le64[2] << 16) +
+ ((unsigned long long)le64[1] << 8) +
+ (unsigned long long)le64[0]);
+}
+
+/**
+ * efi_crc32() - EFI version of crc32 function
+ * @buf: buffer to calculate crc32 of
+ * @len - length of buf
+ *
+ * Description: Returns EFI-style CRC32 value for @buf
+ */
+static inline unsigned long efi_crc32(const void *buf, unsigned long len)
+{
+ return crc32(0, buf, len);
+}
+
+
+/*
+ * Private function prototypes
+ */
+
+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, unsigned long long 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 int is_pte_valid(gpt_entry *pte);
+
+/*
+ * Public Functions (include/part.h)
+ */
+
+void print_part_efi (block_dev_desc_t *dev_desc)
+{
+ gpt_header gpt_head;
+ gpt_entry **pgpt_pte = NULL;
+ int i = 0;
+
+ if (!dev_desc) {
+ printf("%s: Invalid Argument(s)\n", __FUNCTION__);
+ 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), pgpt_pte) != 1) {
+ printf("%s: *** ERROR: Invalid GPT ***\n", __FUNCTION__);
+ return;
+ }
+
+ debug("%s: gpt-entry at 0x%08X\n", __FUNCTION__, (unsigned int)*pgpt_pte);
+
+ printf("Part Start LBA End LBA\n");
+ for (i = 0; i < le32_to_int(gpt_head.num_partition_entries); i++) {
+
+ if (is_pte_valid(&(*pgpt_pte)[i])) {
+ printf("%s%d 0x%llX 0x%llX\n", GPT_ENTRY_NAME, (i+1),
+ le64_to_int((*pgpt_pte)[i].starting_lba),
+ le64_to_int((*pgpt_pte)[i].ending_lba));
+ } else {
+ break; /* Stop at the first non valid PTE */
+ }
+ }
+
+ /* Remember to free pte */
+ if(*pgpt_pte != NULL) {
+ debug("%s: Freeing pgpt_pte\n", __FUNCTION__);
+ free(*pgpt_pte);
+ }
+ return;
+}
+
+int get_partition_info_efi (block_dev_desc_t *dev_desc, int part,
+ disk_partition_t * info)
+{
+ gpt_header gpt_head;
+ gpt_entry **pgpt_pte = NULL;
+
+ /* "part" argument must be@least 1 */
+ if (!dev_desc || !info || part < 1) {
+ printf("%s: Invalid Argument(s)\n", __FUNCTION__);
+ return -1;
+ }
+
+ /* This function validates AND fills in the GPT header and PTE */
+ if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
+ &(gpt_head), pgpt_pte) != 1) {
+ printf("%s: *** ERROR: Invalid GPT ***\n", __FUNCTION__);
+ return -1;
+ }
+
+ /* The ulong casting limits the maximum disk size to 2 TB */
+ info->start = (ulong)le64_to_int((*pgpt_pte)[part-1].starting_lba);
+ info->size = (ulong)le64_to_int((*pgpt_pte)[part-1].ending_lba) - info->start;
+ info->blksz = GPT_BLOCK_SIZE;
+
+ sprintf ((char *)info->name, "%s%d\n", GPT_ENTRY_NAME, part);
+ sprintf ((char *)info->type, "U-Boot");
+
+ debug("%s: start 0x%lX, size 0x%lX, name %s", __FUNCTION__,
+ info->start, info->size, info->name);
+
+ /* Remember to free pte */
+ if(*pgpt_pte != NULL) {
+ debug("%s: Freeing pgpt_pte\n", __FUNCTION__);
+ free(*pgpt_pte);
+ }
+ return 0;
+}
+
+int test_part_efi (block_dev_desc_t *dev_desc)
+{
+ legacy_mbr legacymbr;
+
+ /* Read legacy MBR from block 0 and validate it */
+ if ((dev_desc->block_read(dev_desc->dev, 0, 1, (ulong *) &legacymbr) != 1)
+ || (is_pmbr_valid(&legacymbr) != 1)) {
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Private functions
+ */
+/*
+ * pmbr_part_valid(): Check for EFI partition signature
+ *
+ * Returns: 1 if EFI GPT partition type is found.
+ */
+static int pmbr_part_valid(struct partition *part)
+{
+ if (part->sys_ind == EFI_PMBR_OSTYPE_EFI_GPT &&
+ le32_to_int(part->start_sect) == 1UL) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * is_pmbr_valid(): test Protective MBR for validity
+ *
+ * Returns: 1 if PMBR is valid, 0 otherwise.
+ * Validity depends on two things:
+ * 1) MSDOS signature is in the last two bytes of the MBR
+ * 2) One partition of type 0xEE is found, checked by pmbr_part_valid()
+ */
+static int is_pmbr_valid(legacy_mbr *mbr)
+{
+ int i = 0;
+
+ if (!mbr || le16_to_int(mbr->signature) != MSDOS_MBR_SIGNATURE) {
+ return 0;
+ }
+
+ for (i = 0; i < 4; i++) {
+ if (pmbr_part_valid(&mbr->partition_record[i])) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/**
+ * is_gpt_valid() - tests one GPT header and PTEs for validity
+ *
+ * lba is the logical block address of the GPT header to test
+ * gpt is a GPT header ptr, filled on return.
+ * ptes is a PTEs ptr, filled on return.
+ *
+ * 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, unsigned long long lba,
+ gpt_header *pgpt_head, gpt_entry **pgpt_pte)
+{
+ unsigned char crc32_backup[4] = {0};
+ unsigned long calc_crc32;
+ unsigned long long lastlba;
+
+ if (!dev_desc || !pgpt_head) {
+ printf("%s: Invalid Argument(s)\n", __FUNCTION__);
+ return 0;
+ }
+
+ /* Read GPT Header from device */
+ if (dev_desc->block_read(dev_desc->dev, lba, 1, pgpt_head) != 1) {
+ printf("*** ERROR: Can't read GPT header ***\n");
+ return 0;
+ }
+
+ /* Check the GPT header signature */
+ if (le64_to_int(pgpt_head->signature) != GPT_HEADER_SIGNATURE) {
+ printf("GUID Partition Table Header signature is wrong:"
+ "0x%llX != 0x%llX\n",
+ (unsigned long long)le64_to_int(pgpt_head->signature),
+ (unsigned long long)GPT_HEADER_SIGNATURE);
+ return 0;
+ }
+
+ /* Check the GUID Partition Table CRC */
+ memcpy(crc32_backup, pgpt_head->header_crc32, sizeof(crc32_backup));
+ memset(pgpt_head->header_crc32, 0, sizeof(pgpt_head->header_crc32));
+
+ calc_crc32 = efi_crc32((const unsigned char *) pgpt_head,
+ le32_to_int(pgpt_head->header_size));
+
+ memcpy(pgpt_head->header_crc32, crc32_backup, sizeof(crc32_backup));
+
+ if (calc_crc32 != le32_to_int(crc32_backup)) {
+ printf("GUID Partition Table Header CRC is wrong:"
+ "0x%08lX != 0x%08lX\n",
+ le32_to_int(crc32_backup), calc_crc32);
+ return 0;
+ }
+
+ /* Check that the my_lba entry points to the LBA that contains the GPT */
+ if (le64_to_int(pgpt_head->my_lba) != lba) {
+ printf("GPT: my_lba incorrect: %llX != %llX\n",
+ (unsigned long long)le64_to_int(pgpt_head->my_lba),
+ (unsigned long long)lba);
+ return 0;
+ }
+
+ /* Check the first_usable_lba and last_usable_lba are within the disk. */
+ lastlba = (unsigned long long)dev_desc->lba;
+ if (le64_to_int(pgpt_head->first_usable_lba) > lastlba) {
+ printf("GPT: first_usable_lba incorrect: %llX > %llX\n",
+ le64_to_int(pgpt_head->first_usable_lba), lastlba);
+ return 0;
+ }
+ if (le64_to_int(pgpt_head->last_usable_lba) > lastlba) {
+ printf("GPT: last_usable_lba incorrect: %llX > %llX\n",
+ le64_to_int(pgpt_head->last_usable_lba), lastlba);
+ return 0;
+ }
+
+ debug("GPT: first_usable_lba: %llX last_usable_lba %llX last lba %llX\n",
+ le64_to_int(pgpt_head->first_usable_lba),
+ le64_to_int(pgpt_head->last_usable_lba),
+ lastlba);
+
+ /* Read and allocate Partition Table Entries */
+ *pgpt_pte = alloc_read_gpt_entries(dev_desc, pgpt_head);
+ if (*pgpt_pte == NULL) {
+ printf("GPT: Failed to allocate memory for PTE\n");
+ return 0;
+ }
+
+ /* Check the GUID Partition Table Entry Array CRC */
+ calc_crc32 = efi_crc32((const unsigned char *) *pgpt_pte,
+ le32_to_int(pgpt_head->num_partition_entries) *
+ le32_to_int(pgpt_head->sizeof_partition_entry));
+
+ if (calc_crc32 != le32_to_int(pgpt_head->partition_entry_array_crc32)) {
+ printf("GUID Partition Table Entry Array CRC is wrong:"
+ "0x%08lX != 0x%08lX\n",
+ le32_to_int(pgpt_head->partition_entry_array_crc32),
+ calc_crc32);
+
+ if (*pgpt_pte != NULL) {
+ free(*pgpt_pte);
+ }
+ return 0;
+ }
+
+ /* We're done, all's well */
+ return 1;
+}
+
+/**
+ * alloc_read_gpt_entries(): reads partition entries from disk
+ * @dev_desc
+ * @gpt - GPT header
+ *
+ * Description: Returns ptes on success, NULL on error.
+ * 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)
+{
+ size_t count = 0;
+ gpt_entry *pte = NULL;
+
+ if (!dev_desc || !pgpt_head) {
+ printf("%s: Invalid Argument(s)\n", __FUNCTION__);
+ return NULL;
+ }
+
+ count = le32_to_int(pgpt_head->num_partition_entries) *
+ le32_to_int(pgpt_head->sizeof_partition_entry);
+
+ debug("%s: count = %lu * %lu = %u\n", __FUNCTION__,
+ le32_to_int(pgpt_head->num_partition_entries),
+ le32_to_int(pgpt_head->sizeof_partition_entry), count);
+
+ /* Allocate memory for PTE, remember to FREE */
+ if (count != 0) {
+ pte = malloc(count);
+ }
+
+ if (count == 0 || pte == NULL) {
+ printf("%s: ERROR: Can't allocate 0x%X bytes for GPT Entries\n",
+ __FUNCTION__, count);
+ return NULL;
+ }
+
+ /* Read GPT Entries from device */
+ if (dev_desc->block_read
+ (dev_desc->dev,
+ (unsigned long)le64_to_int(pgpt_head->partition_entry_lba),
+ (lbaint_t)(count/GPT_BLOCK_SIZE), pte)
+ != (count/GPT_BLOCK_SIZE)) {
+ printf("*** ERROR: Can't read GPT Entries ***\n");
+ free(pte);
+ return NULL;
+ }
+ return pte;
+}
+
+/**
+ * is_pte_valid(): validates a single Partition Table Entry
+ * @gpt_entry - Pointer to a single Partition Table Entry
+ *
+ * Description: returns 1 if valid, 0 on error.
+ */
+static int is_pte_valid(gpt_entry *pte)
+{
+ efi_guid_t unused_guid;
+
+ if (!pte) {
+ printf("%s: Invalid Argument(s)\n", __FUNCTION__);
+ return 0;
+ }
+
+ /* Only one validation for now:
+ * The GUID Partition Type != Unused Entry (ALL-ZERO)
+ */
+ memset(unused_guid.b, 0, sizeof(unused_guid.b));
+
+ if (memcmp(pte->partition_type_guid.b, unused_guid.b,
+ sizeof(unused_guid.b)) == 0) {
+ debug("%s: Found an unused PTE GUID at 0x%08X\n", __FUNCTION__,
+ (unsigned int)pte);
+ return 0;
+ } else {
+ return 1;
+ }
+}
+#endif
diff --git a/disk/part_efi.h b/disk/part_efi.h
new file mode 100644
index 0000000..988a98b
--- /dev/null
+++ b/disk/part_efi.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2008 RuggedCom, Inc.
+ * Richard Retanubun <RichardRetanubun@RuggedCom.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * See also linux/fs/partitions.efi.h
+ *
+ * EFI GUID Partition Table
+ * Per Intel EFI Specification v1.02
+ * http://developer.intel.com/technology/efi/efi.htm
+*/
+
+#ifndef _DISK_PART_EFI_H
+#define _DISK_PART_EFI_H
+
+#define MSDOS_MBR_SIGNATURE 0xAA55
+#define EFI_PMBR_OSTYPE_EFI 0xEF
+#define EFI_PMBR_OSTYPE_EFI_GPT 0xEE
+
+#define GPT_BLOCK_SIZE 512
+#define GPT_HEADER_SIGNATURE 0x5452415020494645ULL
+#define GPT_HEADER_REVISION_V1 0x00010000
+#define GPT_PRIMARY_PARTITION_TABLE_LBA 1ULL
+#define GPT_ENTRY_NAME "gpt"
+
+#define EFI_GUID(a,b,c,d0,d1,d2,d3,d4,d5,d6,d7) \
+((efi_guid_t) \
+{{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \
+ (b) & 0xff, ((b) >> 8) & 0xff, \
+ (c) & 0xff, ((c) >> 8) & 0xff, \
+ (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }})
+
+#define PARTITION_SYSTEM_GUID \
+ EFI_GUID( 0xC12A7328, 0xF81F, 0x11d2, \
+ 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B)
+#define LEGACY_MBR_PARTITION_GUID \
+ EFI_GUID( 0x024DEE41, 0x33E7, 0x11d3, \
+ 0x9D, 0x69, 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F)
+#define PARTITION_MSFT_RESERVED_GUID \
+ EFI_GUID( 0xE3C9E316, 0x0B5C, 0x4DB8, \
+ 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE)
+#define PARTITION_BASIC_DATA_GUID \
+ EFI_GUID( 0xEBD0A0A2, 0xB9E5, 0x4433, \
+ 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7)
+#define PARTITION_LINUX_RAID_GUID \
+ EFI_GUID( 0xa19d880f, 0x05fc, 0x4d3b, \
+ 0xa0, 0x06, 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e)
+#define PARTITION_LINUX_SWAP_GUID \
+ EFI_GUID( 0x0657fd6d, 0xa4ab, 0x43c4, \
+ 0x84, 0xe5, 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f)
+#define PARTITION_LINUX_LVM_GUID \
+ EFI_GUID( 0xe6d6d379, 0xf507, 0x44c2, \
+ 0xa2, 0x3c, 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28)
+
+#define UNUSED_GUID 0x00000000000000000000000000000000
+/* linux/include/efi.h */
+typedef unsigned short efi_char16_t; /* UNICODE character */
+
+typedef struct {
+ unsigned char b[16];
+} efi_guid_t;
+
+/* based on linux/include/genhd.h */
+struct partition {
+ unsigned char boot_ind; /* 0x80 - active */
+ unsigned char head; /* starting head */
+ unsigned char sector; /* starting sector */
+ unsigned char cyl; /* starting cylinder */
+ unsigned char sys_ind; /* What partition type */
+ unsigned char end_head; /* end head */
+ unsigned char end_sector; /* end sector */
+ unsigned char end_cyl; /* end cylinder */
+ unsigned char start_sect[4]; /* starting sector counting from 0 */
+ unsigned char nr_sects[4]; /* nr of sectors in partition */
+} __attribute__((packed));
+
+/* based on linux/fs/partitions.efi.h */
+typedef struct _gpt_header {
+ unsigned char signature[8];
+ unsigned char revision[4];
+ unsigned char header_size[4];
+ unsigned char header_crc32[4];
+ unsigned char reserved1[4];
+ unsigned char my_lba[8];
+ unsigned char alternate_lba[8];
+ unsigned char first_usable_lba[8];
+ unsigned char last_usable_lba[8];
+ efi_guid_t disk_guid;
+ unsigned char partition_entry_lba[8];
+ unsigned char num_partition_entries[4];
+ unsigned char sizeof_partition_entry[4];
+ unsigned char partition_entry_array_crc32[4];
+ unsigned char reserved2[GPT_BLOCK_SIZE - 92];
+} __attribute__ ((packed)) gpt_header;
+
+typedef struct _gpt_entry_attributes {
+ unsigned long long required_to_function:1;
+ unsigned long long reserved:47;
+ unsigned long long type_guid_specific:16;
+} __attribute__ ((packed)) gpt_entry_attributes;
+
+typedef struct _gpt_entry {
+ efi_guid_t partition_type_guid;
+ efi_guid_t unique_partition_guid;
+ unsigned char starting_lba[8];
+ unsigned char ending_lba[8];
+ gpt_entry_attributes attributes;
+ efi_char16_t partition_name[72 / sizeof (efi_char16_t)];
+} __attribute__ ((packed)) gpt_entry;
+
+typedef struct _legacy_mbr {
+ unsigned char boot_code[440];
+ unsigned char unique_mbr_signature[4];
+ unsigned char unknown[2];
+ struct partition partition_record[4];
+ unsigned char signature[2];
+} __attribute__ ((packed)) legacy_mbr;
+
+#endif /* _DISK_PART_EFI_H */
diff --git a/include/part.h b/include/part.h
index b22a637..980fd04 100644
--- a/include/part.h
+++ b/include/part.h
@@ -69,6 +69,7 @@ typedef struct block_dev_desc {
#define PART_TYPE_DOS 0x02
#define PART_TYPE_ISO 0x03
#define PART_TYPE_AMIGA 0x04
+#define PART_TYPE_EFI 0x05
/*
* Type string for U-Boot bootable partitions
@@ -135,4 +136,11 @@ void print_part_amiga (block_dev_desc_t *dev_desc);
int test_part_amiga (block_dev_desc_t *dev_desc);
#endif
+#ifdef CONFIG_EFI_PARTITION
+/* disk/part_efi.c */
+int get_partition_info_efi (block_dev_desc_t * dev_desc, int part, disk_partition_t *info);
+void print_part_efi (block_dev_desc_t *dev_desc);
+int test_part_efi (block_dev_desc_t *dev_desc);
+#endif
+
#endif /* _PART_H */
--
1.5.5.GIT
^ permalink raw reply [flat|nested] 9+ messages in thread
* [U-Boot] [PATCH] Add support for CONFIG_EFI_PARTITION (GUID Partition Table)
2008-09-23 21:39 [U-Boot] [PATCH] Add support for CONFIG_EFI_PARTITION (GUID Partition Table) richardretanubun
@ 2008-09-23 22:09 ` Wolfgang Denk
2008-09-23 22:19 ` Andrew Dyer
0 siblings, 1 reply; 9+ messages in thread
From: Wolfgang Denk @ 2008-09-23 22:09 UTC (permalink / raw)
To: u-boot
Dear richardretanubun,
In message <48D96215.3020706@ruggedcom.com> you wrote:
> Signed-off-by: Richard Retanubun <RichardRetanubun@RugggedCom.com>
> ---
>
> disk/Makefile | 1 +
>
> disk/part.c | 33 ++++-
>
> disk/part_efi.c | 428 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>
> disk/part_efi.h | 138 ++++++++++++++++++
>
> include/part.h | 8 +
>
> 5 files changed, 605 insertions(+), 3 deletions(-)
>
> create mode 100644 disk/part_efi.c
>
> create mode 100644 disk/part_efi.h
>
>
> diff --git a/disk/Makefile b/disk/Makefile
>
> index f19d18d..c479145 100644
>
> --- a/disk/Makefile
>
> +++ b/disk/Makefile
>
> @@ -32,6 +32,7 @@ COBJS-y += part_mac.o
>
> COBJS-y += part_dos.o
>
> COBJS-y += part_iso.o
>
> COBJS-y += part_amiga.o
>
> +COBJS-y += part_efi.o
Your patch is corrupted because your mailer inserts an empty line
after each line of text. Please fix your mailer setup and repost.
Also, please enlighten me: what is "EFI", and what is a "GUID"
partition table, and which systems do use that?
Best regards,
Wolfgang Denk
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
The only way to learn a new programming language is by writing pro-
grams in it. - Brian Kernighan
^ permalink raw reply [flat|nested] 9+ messages in thread
* [U-Boot] [PATCH] Add support for CONFIG_EFI_PARTITION (GUID Partition Table)
2008-09-23 22:09 ` Wolfgang Denk
@ 2008-09-23 22:19 ` Andrew Dyer
2008-09-24 13:49 ` richardretanubun
0 siblings, 1 reply; 9+ messages in thread
From: Andrew Dyer @ 2008-09-23 22:19 UTC (permalink / raw)
To: u-boot
> Also, please enlighten me: what is "EFI", and what is a "GUID"
> partition table, and which systems do use that?
EFI is the PC BIOS replacement that Intel came up with, most notably
used on Apple's Intel based computers. A blurb about EFI is here -
http://en.wikipedia.org/wiki/Extensible_Firmware_Interface
^ permalink raw reply [flat|nested] 9+ messages in thread
* [U-Boot] [PATCH] Add support for CONFIG_EFI_PARTITION (GUID Partition Table)
2008-09-23 22:19 ` Andrew Dyer
@ 2008-09-24 13:49 ` richardretanubun
2008-09-24 15:27 ` richardretanubun
0 siblings, 1 reply; 9+ messages in thread
From: richardretanubun @ 2008-09-24 13:49 UTC (permalink / raw)
To: u-boot
Dear Wolfgang,
Andrew Dyer wrote:
>> Also, please enlighten me: what is "EFI", and what is a "GUID"
>> partition table, and which systems do use that?
>
> EFI is the PC BIOS replacement that Intel came up with, most notably
> used on Apple's Intel based computers. A blurb about EFI is here -
> http://en.wikipedia.org/wiki/Extensible_Firmware_Interface
The GUID (Globally Unique Identifier) Partition Table (GPT) is a part of EFI.
http://en.wikipedia.org/wiki/GUID_Partition_Table
Sorry about the mangled patch, I hope this works better:
Tested the patch on a MPC8349EMITX Eval board
- Richard Retanubun
<re-posted-patch>
From ebfdb1f5d8f5889a6525566474b9c99f2b4d92dd Mon Sep 17 00:00:00 2001
From: Richard Retanubun <RichardRetanubun@RugggedCom.com>
Date: Tue, 23 Sep 2008 17:20:06 -0400
Subject: [PATCH] Add support for CONFIG_EFI_PARTITION (GUID Partition Table)
Signed-off-by: Richard Retanubun <RichardRetanubun@RugggedCom.com>
---
README | 2 +-
disk/Makefile | 1 +
disk/part.c | 33 ++++-
disk/part_efi.c | 425 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
disk/part_efi.h | 138 ++++++++++++++++++
include/part.h | 8 +
6 files changed, 603 insertions(+), 4 deletions(-)
create mode 100644 disk/part_efi.c
create mode 100644 disk/part_efi.h
diff --git a/README b/README
index f9ea255..4f05907 100644
--- a/README
+++ b/README
@@ -687,7 +687,7 @@ The following options need to be configured:
- Partition Support:
CONFIG_MAC_PARTITION and/or CONFIG_DOS_PARTITION
- and/or CONFIG_ISO_PARTITION
+ and/or CONFIG_ISO_PARTITION and/or CONFIG_EFI_PARTITION
If IDE or SCSI support is enabled (CONFIG_CMD_IDE or
CONFIG_CMD_SCSI) you must configure support for at
diff --git a/disk/Makefile b/disk/Makefile
index f19d18d..c479145 100644
--- a/disk/Makefile
+++ b/disk/Makefile
@@ -32,6 +32,7 @@ COBJS-y += part_mac.o
COBJS-y += part_dos.o
COBJS-y += part_iso.o
COBJS-y += part_amiga.o
+COBJS-y += part_efi.o
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
diff --git a/disk/part.c b/disk/part.c
index 5c4bf6b..9db6a78 100644
--- a/disk/part.c
+++ b/disk/part.c
@@ -198,7 +198,8 @@ void dev_print (block_dev_desc_t *dev_desc)
#if defined(CONFIG_MAC_PARTITION) || \
defined(CONFIG_DOS_PARTITION) || \
defined(CONFIG_ISO_PARTITION) || \
- defined(CONFIG_AMIGA_PARTITION)
+ defined(CONFIG_AMIGA_PARTITION) || \
+ defined(CONFIG_EFI_PARTITION)
void init_part (block_dev_desc_t * dev_desc)
{
@@ -216,6 +217,14 @@ void init_part (block_dev_desc_t * dev_desc)
}
#endif
+/* must be placed before DOS partition detection */
+#ifdef CONFIG_EFI_PARTITION
+ if (test_part_efi(dev_desc) == 0) {
+ dev_desc->part_type = PART_TYPE_EFI;
+ return;
+ }
+#endif
+
#ifdef CONFIG_DOS_PARTITION
if (test_part_dos(dev_desc) == 0) {
dev_desc->part_type = PART_TYPE_DOS;
@@ -272,6 +281,15 @@ int get_partition_info (block_dev_desc_t *dev_desc, int part
}
break;
#endif
+
+#ifdef CONFIG_EFI_PARTITION
+ case PART_TYPE_EFI:
+ if (get_partition_info_efi(dev_desc,part,info) == 0) {
+ PRINTF ("## Valid EFI partition found ##\n");
+ return (0);
+ }
+ break;
+#endif
default:
break;
}
@@ -342,14 +360,23 @@ void print_part (block_dev_desc_t * dev_desc)
print_part_amiga (dev_desc);
return;
#endif
+
+#ifdef CONFIG_EFI_PARTITION
+ case PART_TYPE_EFI:
+ PRINTF ("## Testing for valid EFI partition ##\n");
+ print_part_header ("EFI", dev_desc);
+ print_part_efi (dev_desc);
+ return;
+#endif
}
puts ("## Unknown partition table\n");
}
-#else /* neither MAC nor DOS nor ISO partition configured */
+#else /* neither MAC nor DOS nor ISO nor AMIGA nor EFI partition configured */
# error neither CONFIG_MAC_PARTITION nor CONFIG_DOS_PARTITION
-# error nor CONFIG_ISO_PARTITION configured!
+# error nor CONFIG_ISO_PARTITION nor CONFIG_AMIGA_PARTITION
+# error nor CONFIG_EFI_PARTITION configured!
#endif
#endif
diff --git a/disk/part_efi.c b/disk/part_efi.c
new file mode 100644
index 0000000..4f96f8e
--- /dev/null
+++ b/disk/part_efi.c
@@ -0,0 +1,425 @@
+/*
+ * Copyright (C) 2008 RuggedCom, Inc.
+ * Richard Retanubun <RichardRetanubun@RuggedCom.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Problems with CFG_64BIT_LBA:
+ *
+ * struct disk_partition.start in include/part.h is sized as ulong.
+ * When CFG_64BIT_LBA is activated, lbaint_t changes from ulong to uint64_t.
+ * For now, it is cast back to ulong at assignment.
+ *
+ * This limits the maximum size of disk addressable to < 2 Terra Bytes
+ */
+#include <common.h>
+#include <command.h>
+#include <ide.h>
+#include <malloc.h>
+#include "part_efi.h"
+
+#if (defined(CONFIG_CMD_IDE) || \
+ defined(CONFIG_CMD_SATA) || \
+ defined(CONFIG_CMD_SCSI) || \
+ defined(CONFIG_CMD_USB) || \
+ defined(CONFIG_MMC) || \
+ defined(CONFIG_SYSTEMACE) ) && defined(CONFIG_EFI_PARTITION)
+
+/* Convert char[2] in little endian format to the host format integer
+ */
+static inline unsigned short le16_to_int(unsigned char *le16)
+{
+ return ((le16[1] << 8) + le16[0]);
+}
+
+/* Convert char[4] in little endian format to the host format integer
+ */
+static inline unsigned long le32_to_int(unsigned char *le32)
+{
+ return ((le32[3] << 24) + (le32[2] << 16) + (le32[1] << 8) + le32[0]);
+}
+
+/* Convert char[8] in little endian format to the host format integer
+ */
+static inline unsigned long long le64_to_int(unsigned char *le64)
+{
+ return (((unsigned long long)le64[7] << 56) +
+ ((unsigned long long)le64[6] << 48) +
+ ((unsigned long long)le64[5] << 40) +
+ ((unsigned long long)le64[4] << 32) +
+ ((unsigned long long)le64[3] << 24) +
+ ((unsigned long long)le64[2] << 16) +
+ ((unsigned long long)le64[1] << 8) +
+ (unsigned long long)le64[0]);
+}
+
+/**
+ * efi_crc32() - EFI version of crc32 function
+ * @buf: buffer to calculate crc32 of
+ * @len - length of buf
+ *
+ * Description: Returns EFI-style CRC32 value for @buf
+ */
+static inline unsigned long efi_crc32(const void *buf, unsigned long len)
+{
+ return crc32(0, buf, len);
+}
+
+/*
+ * Private function prototypes
+ */
+
+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, unsigned long long 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 int is_pte_valid(gpt_entry * pte);
+
+/*
+ * Public Functions (include/part.h)
+ */
+
+void print_part_efi(block_dev_desc_t * dev_desc)
+{
+ gpt_header gpt_head;
+ gpt_entry **pgpt_pte = NULL;
+ int i = 0;
+
+ if (!dev_desc) {
+ printf("%s: Invalid Argument(s)\n", __FUNCTION__);
+ 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), pgpt_pte) != 1) {
+ printf("%s: *** ERROR: Invalid GPT ***\n", __FUNCTION__);
+ return;
+ }
+
+ debug("%s: gpt-entry at 0x%08X\n", __FUNCTION__, (unsigned int)*pgpt_pte);
+
+ printf("Part Start LBA End LBA\n");
+ for (i = 0; i < le32_to_int(gpt_head.num_partition_entries); i++) {
+
+ if (is_pte_valid(&(*pgpt_pte)[i])) {
+ printf("%s%d 0x%llX 0x%llX\n", GPT_ENTRY_NAME,
+ (i + 1),
+ le64_to_int((*pgpt_pte)[i].starting_lba),
+ le64_to_int((*pgpt_pte)[i].ending_lba));
+ } else {
+ break; /* Stop at the first non valid PTE */
+ }
+ }
+
+ /* Remember to free pte */
+ if (*pgpt_pte != NULL) {
+ debug("%s: Freeing pgpt_pte\n", __FUNCTION__);
+ free(*pgpt_pte);
+ }
+ return;
+}
+
+int get_partition_info_efi(block_dev_desc_t * dev_desc, int part,
+ disk_partition_t * info)
+{
+ gpt_header gpt_head;
+ gpt_entry **pgpt_pte = NULL;
+
+ /* "part" argument must be@least 1 */
+ if (!dev_desc || !info || part < 1) {
+ printf("%s: Invalid Argument(s)\n", __FUNCTION__);
+ return -1;
+ }
+
+ /* This function validates AND fills in the GPT header and PTE */
+ if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
+ &(gpt_head), pgpt_pte) != 1) {
+ printf("%s: *** ERROR: Invalid GPT ***\n", __FUNCTION__);
+ return -1;
+ }
+
+ /* The ulong casting limits the maximum disk size to 2 TB */
+ info->start = (ulong) le64_to_int((*pgpt_pte)[part - 1].starting_lba);
+ info->size = (ulong) le64_to_int((*pgpt_pte)[part - 1].ending_lba) - info->start;
+ info->blksz = GPT_BLOCK_SIZE;
+
+ sprintf((char *)info->name, "%s%d\n", GPT_ENTRY_NAME, part);
+ sprintf((char *)info->type, "U-Boot");
+
+ debug("%s: start 0x%lX, size 0x%lX, name %s", __FUNCTION__,
+ info->start, info->size, info->name);
+
+ /* Remember to free pte */
+ if (*pgpt_pte != NULL) {
+ debug("%s: Freeing pgpt_pte\n", __FUNCTION__);
+ free(*pgpt_pte);
+ }
+ return 0;
+}
+
+int test_part_efi(block_dev_desc_t * dev_desc)
+{
+ legacy_mbr legacymbr;
+
+ /* Read legacy MBR from block 0 and validate it */
+ if ((dev_desc->block_read(dev_desc->dev, 0, 1, (ulong *) & legacymbr) != 1)
+ || (is_pmbr_valid(&legacymbr) != 1)) {
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Private functions
+ */
+/*
+ * pmbr_part_valid(): Check for EFI partition signature
+ *
+ * Returns: 1 if EFI GPT partition type is found.
+ */
+static int pmbr_part_valid(struct partition *part)
+{
+ if (part->sys_ind == EFI_PMBR_OSTYPE_EFI_GPT &&
+ le32_to_int(part->start_sect) == 1UL) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * is_pmbr_valid(): test Protective MBR for validity
+ *
+ * Returns: 1 if PMBR is valid, 0 otherwise.
+ * Validity depends on two things:
+ * 1) MSDOS signature is in the last two bytes of the MBR
+ * 2) One partition of type 0xEE is found, checked by pmbr_part_valid()
+ */
+static int is_pmbr_valid(legacy_mbr * mbr)
+{
+ int i = 0;
+
+ if (!mbr || le16_to_int(mbr->signature) != MSDOS_MBR_SIGNATURE) {
+ return 0;
+ }
+
+ for (i = 0; i < 4; i++) {
+ if (pmbr_part_valid(&mbr->partition_record[i])) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/**
+ * is_gpt_valid() - tests one GPT header and PTEs for validity
+ *
+ * lba is the logical block address of the GPT header to test
+ * gpt is a GPT header ptr, filled on return.
+ * ptes is a PTEs ptr, filled on return.
+ *
+ * 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, unsigned long long lba,
+ gpt_header * pgpt_head, gpt_entry ** pgpt_pte)
+{
+ unsigned char crc32_backup[4] = { 0 };
+ unsigned long calc_crc32;
+ unsigned long long lastlba;
+
+ if (!dev_desc || !pgpt_head) {
+ printf("%s: Invalid Argument(s)\n", __FUNCTION__);
+ return 0;
+ }
+
+ /* Read GPT Header from device */
+ if (dev_desc->block_read(dev_desc->dev, lba, 1, pgpt_head) != 1) {
+ printf("*** ERROR: Can't read GPT header ***\n");
+ return 0;
+ }
+
+ /* Check the GPT header signature */
+ if (le64_to_int(pgpt_head->signature) != GPT_HEADER_SIGNATURE) {
+ printf("GUID Partition Table Header signature is wrong:"
+ "0x%llX != 0x%llX\n",
+ (unsigned long long)le64_to_int(pgpt_head->signature),
+ (unsigned long long)GPT_HEADER_SIGNATURE);
+ return 0;
+ }
+
+ /* Check the GUID Partition Table CRC */
+ memcpy(crc32_backup, pgpt_head->header_crc32, sizeof(crc32_backup));
+ memset(pgpt_head->header_crc32, 0, sizeof(pgpt_head->header_crc32));
+
+ calc_crc32 = efi_crc32((const unsigned char *)pgpt_head,
+ le32_to_int(pgpt_head->header_size));
+
+ memcpy(pgpt_head->header_crc32, crc32_backup, sizeof(crc32_backup));
+
+ if (calc_crc32 != le32_to_int(crc32_backup)) {
+ printf("GUID Partition Table Header CRC is wrong:"
+ "0x%08lX != 0x%08lX\n",
+ le32_to_int(crc32_backup), calc_crc32);
+ return 0;
+ }
+
+ /* Check that the my_lba entry points to the LBA that contains the GPT */
+ if (le64_to_int(pgpt_head->my_lba) != lba) {
+ printf("GPT: my_lba incorrect: %llX != %llX\n",
+ (unsigned long long)le64_to_int(pgpt_head->my_lba),
+ (unsigned long long)lba);
+ return 0;
+ }
+
+ /* Check the first_usable_lba and last_usable_lba are within the disk. */
+ lastlba = (unsigned long long)dev_desc->lba;
+ if (le64_to_int(pgpt_head->first_usable_lba) > lastlba) {
+ printf("GPT: first_usable_lba incorrect: %llX > %llX\n",
+ le64_to_int(pgpt_head->first_usable_lba), lastlba);
+ return 0;
+ }
+ if (le64_to_int(pgpt_head->last_usable_lba) > lastlba) {
+ printf("GPT: last_usable_lba incorrect: %llX > %llX\n",
+ le64_to_int(pgpt_head->last_usable_lba), lastlba);
+ return 0;
+ }
+
+ debug("GPT: first_usable_lba: %llX last_usable_lba %llX last lba %llX\n",
+ le64_to_int(pgpt_head->first_usable_lba),
+ le64_to_int(pgpt_head->last_usable_lba), lastlba);
+
+ /* Read and allocate Partition Table Entries */
+ *pgpt_pte = alloc_read_gpt_entries(dev_desc, pgpt_head);
+ if (*pgpt_pte == NULL) {
+ printf("GPT: Failed to allocate memory for PTE\n");
+ return 0;
+ }
+
+ /* Check the GUID Partition Table Entry Array CRC */
+ calc_crc32 = efi_crc32((const unsigned char *)*pgpt_pte,
+ le32_to_int(pgpt_head->num_partition_entries) *
+ le32_to_int(pgpt_head->sizeof_partition_entry));
+
+ if (calc_crc32 != le32_to_int(pgpt_head->partition_entry_array_crc32)) {
+ printf("GUID Partition Table Entry Array CRC is wrong:"
+ "0x%08lX != 0x%08lX\n",
+ le32_to_int(pgpt_head->partition_entry_array_crc32),
+ calc_crc32);
+
+ if (*pgpt_pte != NULL) {
+ free(*pgpt_pte);
+ }
+ return 0;
+ }
+
+ /* We're done, all's well */
+ return 1;
+}
+
+/**
+ * alloc_read_gpt_entries(): reads partition entries from disk
+ * @dev_desc
+ * @gpt - GPT header
+ *
+ * Description: Returns ptes on success, NULL on error.
+ * 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)
+{
+ size_t count = 0;
+ gpt_entry *pte = NULL;
+
+ if (!dev_desc || !pgpt_head) {
+ printf("%s: Invalid Argument(s)\n", __FUNCTION__);
+ return NULL;
+ }
+
+ count = le32_to_int(pgpt_head->num_partition_entries) *
+ le32_to_int(pgpt_head->sizeof_partition_entry);
+
+ debug("%s: count = %lu * %lu = %u\n", __FUNCTION__,
+ le32_to_int(pgpt_head->num_partition_entries),
+ le32_to_int(pgpt_head->sizeof_partition_entry), count);
+
+ /* Allocate memory for PTE, remember to FREE */
+ if (count != 0) {
+ pte = malloc(count);
+ }
+
+ if (count == 0 || pte == NULL) {
+ printf("%s: ERROR: Can't allocate 0x%X bytes for GPT Entries\n",
+ __FUNCTION__, count);
+ return NULL;
+ }
+
+ /* Read GPT Entries from device */
+ if (dev_desc->block_read (dev_desc->dev,
+ (unsigned long)le64_to_int(pgpt_head->partition_entry_lba),
+ (lbaint_t) (count / GPT_BLOCK_SIZE), pte)
+ != (count / GPT_BLOCK_SIZE)) {
+
+ printf("*** ERROR: Can't read GPT Entries ***\n");
+ free(pte);
+ return NULL;
+ }
+ return pte;
+}
+
+/**
+ * is_pte_valid(): validates a single Partition Table Entry
+ * @gpt_entry - Pointer to a single Partition Table Entry
+ *
+ * Description: returns 1 if valid, 0 on error.
+ */
+static int is_pte_valid(gpt_entry * pte)
+{
+ efi_guid_t unused_guid;
+
+ if (!pte) {
+ printf("%s: Invalid Argument(s)\n", __FUNCTION__);
+ return 0;
+ }
+
+ /* Only one validation for now:
+ * The GUID Partition Type != Unused Entry (ALL-ZERO)
+ */
+ memset(unused_guid.b, 0, sizeof(unused_guid.b));
+
+ if (memcmp(pte->partition_type_guid.b, unused_guid.b,
+ sizeof(unused_guid.b)) == 0) {
+
+ debug("%s: Found an unused PTE GUID at 0x%08X\n", __FUNCTION__,
+ (unsigned int)pte);
+
+ return 0;
+ } else {
+ return 1;
+ }
+}
+#endif
diff --git a/disk/part_efi.h b/disk/part_efi.h
new file mode 100644
index 0000000..75cd6e6
--- /dev/null
+++ b/disk/part_efi.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2008 RuggedCom, Inc.
+ * Richard Retanubun <RichardRetanubun@RuggedCom.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * See also linux/fs/partitions.efi.h
+ *
+ * EFI GUID Partition Table
+ * Per Intel EFI Specification v1.02
+ * http://developer.intel.com/technology/efi/efi.htm
+*/
+
+#ifndef _DISK_PART_EFI_H
+#define _DISK_PART_EFI_H
+
+#define MSDOS_MBR_SIGNATURE 0xAA55
+#define EFI_PMBR_OSTYPE_EFI 0xEF
+#define EFI_PMBR_OSTYPE_EFI_GPT 0xEE
+
+#define GPT_BLOCK_SIZE 512
+#define GPT_HEADER_SIGNATURE 0x5452415020494645ULL
+#define GPT_HEADER_REVISION_V1 0x00010000
+#define GPT_PRIMARY_PARTITION_TABLE_LBA 1ULL
+#define GPT_ENTRY_NAME "gpt"
+
+#define EFI_GUID(a,b,c,d0,d1,d2,d3,d4,d5,d6,d7) \
+((efi_guid_t) \
+{{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \
+ (b) & 0xff, ((b) >> 8) & 0xff, \
+ (c) & 0xff, ((c) >> 8) & 0xff, \
+ (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }})
+
+#define PARTITION_SYSTEM_GUID \
+ EFI_GUID( 0xC12A7328, 0xF81F, 0x11d2, \
+ 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B)
+#define LEGACY_MBR_PARTITION_GUID \
+ EFI_GUID( 0x024DEE41, 0x33E7, 0x11d3, \
+ 0x9D, 0x69, 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F)
+#define PARTITION_MSFT_RESERVED_GUID \
+ EFI_GUID( 0xE3C9E316, 0x0B5C, 0x4DB8, \
+ 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE)
+#define PARTITION_BASIC_DATA_GUID \
+ EFI_GUID( 0xEBD0A0A2, 0xB9E5, 0x4433, \
+ 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7)
+#define PARTITION_LINUX_RAID_GUID \
+ EFI_GUID( 0xa19d880f, 0x05fc, 0x4d3b, \
+ 0xa0, 0x06, 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e)
+#define PARTITION_LINUX_SWAP_GUID \
+ EFI_GUID( 0x0657fd6d, 0xa4ab, 0x43c4, \
+ 0x84, 0xe5, 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f)
+#define PARTITION_LINUX_LVM_GUID \
+ EFI_GUID( 0xe6d6d379, 0xf507, 0x44c2, \
+ 0xa2, 0x3c, 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28)
+
+/* linux/include/efi.h */
+typedef unsigned short efi_char16_t; /* UNICODE character */
+
+typedef struct {
+ unsigned char b[16];
+} efi_guid_t;
+
+/* based on linux/include/genhd.h */
+struct partition {
+ unsigned char boot_ind; /* 0x80 - active */
+ unsigned char head; /* starting head */
+ unsigned char sector; /* starting sector */
+ unsigned char cyl; /* starting cylinder */
+ unsigned char sys_ind; /* What partition type */
+ unsigned char end_head; /* end head */
+ unsigned char end_sector; /* end sector */
+ unsigned char end_cyl; /* end cylinder */
+ unsigned char start_sect[4]; /* starting sector counting from 0 */
+ unsigned char nr_sects[4]; /* nr of sectors in partition */
+} __attribute__ ((packed));
+
+/* based on linux/fs/partitions.efi.h */
+typedef struct _gpt_header {
+ unsigned char signature[8];
+ unsigned char revision[4];
+ unsigned char header_size[4];
+ unsigned char header_crc32[4];
+ unsigned char reserved1[4];
+ unsigned char my_lba[8];
+ unsigned char alternate_lba[8];
+ unsigned char first_usable_lba[8];
+ unsigned char last_usable_lba[8];
+ efi_guid_t disk_guid;
+ unsigned char partition_entry_lba[8];
+ unsigned char num_partition_entries[4];
+ unsigned char sizeof_partition_entry[4];
+ unsigned char partition_entry_array_crc32[4];
+ unsigned char reserved2[GPT_BLOCK_SIZE - 92];
+} __attribute__ ((packed)) gpt_header;
+
+typedef struct _gpt_entry_attributes {
+ unsigned long long required_to_function:1;
+ unsigned long long reserved:47;
+ unsigned long long type_guid_specific:16;
+} __attribute__ ((packed)) gpt_entry_attributes;
+
+typedef struct _gpt_entry {
+ efi_guid_t partition_type_guid;
+ efi_guid_t unique_partition_guid;
+ unsigned char starting_lba[8];
+ unsigned char ending_lba[8];
+ gpt_entry_attributes attributes;
+ efi_char16_t partition_name[72 / sizeof(efi_char16_t)];
+}
+__attribute__ ((packed)) gpt_entry;
+
+typedef struct _legacy_mbr {
+ unsigned char boot_code[440];
+ unsigned char unique_mbr_signature[4];
+ unsigned char unknown[2];
+ struct partition partition_record[4];
+ unsigned char signature[2];
+} __attribute__ ((packed)) legacy_mbr;
+
+#endif /* _DISK_PART_EFI_H */
diff --git a/include/part.h b/include/part.h
index b22a637..980fd04 100644
--- a/include/part.h
+++ b/include/part.h
@@ -69,6 +69,7 @@ typedef struct block_dev_desc {
#define PART_TYPE_DOS 0x02
#define PART_TYPE_ISO 0x03
#define PART_TYPE_AMIGA 0x04
+#define PART_TYPE_EFI 0x05
/*
* Type string for U-Boot bootable partitions
@@ -135,4 +136,11 @@ void print_part_amiga (block_dev_desc_t *dev_desc);
int test_part_amiga (block_dev_desc_t *dev_desc);
#endif
+#ifdef CONFIG_EFI_PARTITION
+/* disk/part_efi.c */
+int get_partition_info_efi (block_dev_desc_t * dev_desc, int part, disk_partition_t *info);
+void print_part_efi (block_dev_desc_t *dev_desc);
+int test_part_efi (block_dev_desc_t *dev_desc);
+#endif
+
#endif /* _PART_H */
--
1.5.5.GIT
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [U-Boot] [PATCH] Add support for CONFIG_EFI_PARTITION (GUID Partition Table)
2008-09-24 13:49 ` richardretanubun
@ 2008-09-24 15:27 ` richardretanubun
2008-09-26 15:13 ` richardretanubun
0 siblings, 1 reply; 9+ messages in thread
From: richardretanubun @ 2008-09-24 15:27 UTC (permalink / raw)
To: u-boot
Hi Wolfgang
Andrew Dyer wrote:
>> Also, please enlighten me: what is "EFI", and what is a "GUID"
>> partition table, and which systems do use that?
>
> EFI is the PC BIOS replacement that Intel came up with, most notably
> used on Apple's Intel based computers. A blurb about EFI is here -
> http://en.wikipedia.org/wiki/Extensible_Firmware_Interface
The GUID (Globally Unique Identifier) Partition Table (GPT) is a part of EFI.
http://en.wikipedia.org/wiki/GUID_Partition_Table
Sorry about the mangled patch, I hope this works better:
Tested the patch on a MPC8349EMITX Eval board
Sorry for the mishap, please use this patch. I test-sent it to myself and it applies.
Somehow the previous one chops of the " <nl>" to "<nl>", breaking diff.
- Richard Retanubun
^ permalink raw reply [flat|nested] 9+ messages in thread
* [U-Boot] [PATCH] Add support for CONFIG_EFI_PARTITION (GUID Partition Table)
2008-09-24 15:27 ` richardretanubun
@ 2008-09-26 15:13 ` richardretanubun
2008-10-06 20:10 ` [U-Boot] [PATCH] CONFIG_EFI_PARTITION: Added support for EFI partition in cmd_ext2fs.c richardretanubun
2008-10-14 13:15 ` [U-Boot] [PATCH] Add support for CONFIG_EFI_PARTITION (GUID Partition Table) Wolfgang Denk
0 siblings, 2 replies; 9+ messages in thread
From: richardretanubun @ 2008-09-26 15:13 UTC (permalink / raw)
To: u-boot
Add support for CONFIG_EFI_PARTITION (GUID Partition Table)
Based on linux/fs/partitions/efi.[ch]
Signed-off-by: Richard Retanubun <RichardRetanubun@RugggedCom.com>
---
Hi Wolfgang,
Boy, do I suck at submitting patches.
This is the same patch as before,
with some minor comment cleanup and proper formatting of patch.
Richard
README | 2 +-
disk/Makefile | 1 +
disk/part.c | 33 ++++-
disk/part_efi.c | 425 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
disk/part_efi.h | 138 ++++++++++++++++++
include/part.h | 8 +
6 files changed, 603 insertions(+), 4 deletions(-)
create mode 100644 disk/part_efi.c
create mode 100644 disk/part_efi.h
diff --git a/README b/README
index ccd839c..409883e 100644
--- a/README
+++ b/README
@@ -687,7 +687,7 @@ The following options need to be configured:
- Partition Support:
CONFIG_MAC_PARTITION and/or CONFIG_DOS_PARTITION
- and/or CONFIG_ISO_PARTITION
+ and/or CONFIG_ISO_PARTITION and/or CONFIG_EFI_PARTITION
If IDE or SCSI support is enabled (CONFIG_CMD_IDE or
CONFIG_CMD_SCSI) you must configure support for at
diff --git a/disk/Makefile b/disk/Makefile
index f19d18d..c479145 100644
--- a/disk/Makefile
+++ b/disk/Makefile
@@ -32,6 +32,7 @@ COBJS-y += part_mac.o
COBJS-y += part_dos.o
COBJS-y += part_iso.o
COBJS-y += part_amiga.o
+COBJS-y += part_efi.o
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
diff --git a/disk/part.c b/disk/part.c
index 80532a7..e2bf4ab 100644
--- a/disk/part.c
+++ b/disk/part.c
@@ -212,7 +212,8 @@ void dev_print (block_dev_desc_t *dev_desc)
#if defined(CONFIG_MAC_PARTITION) || \
defined(CONFIG_DOS_PARTITION) || \
defined(CONFIG_ISO_PARTITION) || \
- defined(CONFIG_AMIGA_PARTITION)
+ defined(CONFIG_AMIGA_PARTITION) || \
+ defined(CONFIG_EFI_PARTITION)
void init_part (block_dev_desc_t * dev_desc)
{
@@ -230,6 +231,14 @@ void init_part (block_dev_desc_t * dev_desc)
}
#endif
+/* must be placed before DOS partition detection */
+#ifdef CONFIG_EFI_PARTITION
+ if (test_part_efi(dev_desc) == 0) {
+ dev_desc->part_type = PART_TYPE_EFI;
+ return;
+ }
+#endif
+
#ifdef CONFIG_DOS_PARTITION
if (test_part_dos(dev_desc) == 0) {
dev_desc->part_type = PART_TYPE_DOS;
@@ -286,6 +295,15 @@ int get_partition_info (block_dev_desc_t *dev_desc, int part
}
break;
#endif
+
+#ifdef CONFIG_EFI_PARTITION
+ case PART_TYPE_EFI:
+ if (get_partition_info_efi(dev_desc,part,info) == 0) {
+ PRINTF ("## Valid EFI partition found ##\n");
+ return (0);
+ }
+ break;
+#endif
default:
break;
}
@@ -356,14 +374,23 @@ void print_part (block_dev_desc_t * dev_desc)
print_part_amiga (dev_desc);
return;
#endif
+
+#ifdef CONFIG_EFI_PARTITION
+ case PART_TYPE_EFI:
+ PRINTF ("## Testing for valid EFI partition ##\n");
+ print_part_header ("EFI", dev_desc);
+ print_part_efi (dev_desc);
+ return;
+#endif
}
puts ("## Unknown partition table\n");
}
-#else /* neither MAC nor DOS nor ISO partition configured */
+#else /* neither MAC nor DOS nor ISO nor AMIGA nor EFI partition configured */
# error neither CONFIG_MAC_PARTITION nor CONFIG_DOS_PARTITION
-# error nor CONFIG_ISO_PARTITION configured!
+# error nor CONFIG_ISO_PARTITION nor CONFIG_AMIGA_PARTITION
+# error nor CONFIG_EFI_PARTITION configured!
#endif
#endif
diff --git a/disk/part_efi.c b/disk/part_efi.c
new file mode 100644
index 0000000..979019a
--- /dev/null
+++ b/disk/part_efi.c
@@ -0,0 +1,425 @@
+/*
+ * Copyright (C) 2008 RuggedCom, Inc.
+ * Richard Retanubun <RichardRetanubun@RuggedCom.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Problems with CFG_64BIT_LBA:
+ *
+ * struct disk_partition.start in include/part.h is sized as ulong.
+ * When CFG_64BIT_LBA is activated, lbaint_t changes from ulong to uint64_t.
+ * For now, it is cast back to ulong at assignment.
+ *
+ * This limits the maximum size of addressable storage to < 2 Terra Bytes
+ */
+#include <common.h>
+#include <command.h>
+#include <ide.h>
+#include <malloc.h>
+#include "part_efi.h"
+
+#if (defined(CONFIG_CMD_IDE) || \
+ defined(CONFIG_CMD_SATA) || \
+ defined(CONFIG_CMD_SCSI) || \
+ defined(CONFIG_CMD_USB) || \
+ defined(CONFIG_MMC) || \
+ defined(CONFIG_SYSTEMACE) ) && defined(CONFIG_EFI_PARTITION)
+
+/* Convert char[2] in little endian format to the host format integer
+ */
+static inline unsigned short le16_to_int(unsigned char *le16)
+{
+ return ((le16[1] << 8) + le16[0]);
+}
+
+/* Convert char[4] in little endian format to the host format integer
+ */
+static inline unsigned long le32_to_int(unsigned char *le32)
+{
+ return ((le32[3] << 24) + (le32[2] << 16) + (le32[1] << 8) + le32[0]);
+}
+
+/* Convert char[8] in little endian format to the host format integer
+ */
+static inline unsigned long long le64_to_int(unsigned char *le64)
+{
+ return (((unsigned long long)le64[7] << 56) +
+ ((unsigned long long)le64[6] << 48) +
+ ((unsigned long long)le64[5] << 40) +
+ ((unsigned long long)le64[4] << 32) +
+ ((unsigned long long)le64[3] << 24) +
+ ((unsigned long long)le64[2] << 16) +
+ ((unsigned long long)le64[1] << 8) +
+ (unsigned long long)le64[0]);
+}
+
+/**
+ * efi_crc32() - EFI version of crc32 function
+ * @buf: buffer to calculate crc32 of
+ * @len - length of buf
+ *
+ * Description: Returns EFI-style CRC32 value for @buf
+ */
+static inline unsigned long efi_crc32(const void *buf, unsigned long len)
+{
+ return crc32(0, buf, len);
+}
+
+/*
+ * Private function prototypes
+ */
+
+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, unsigned long long 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 int is_pte_valid(gpt_entry * pte);
+
+/*
+ * Public Functions (include/part.h)
+ */
+
+void print_part_efi(block_dev_desc_t * dev_desc)
+{
+ gpt_header gpt_head;
+ gpt_entry **pgpt_pte = NULL;
+ int i = 0;
+
+ if (!dev_desc) {
+ printf("%s: Invalid Argument(s)\n", __FUNCTION__);
+ 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), pgpt_pte) != 1) {
+ printf("%s: *** ERROR: Invalid GPT ***\n", __FUNCTION__);
+ return;
+ }
+
+ debug("%s: gpt-entry at 0x%08X\n", __FUNCTION__, (unsigned int)*pgpt_pte);
+
+ printf("Part Start LBA End LBA\n");
+ for (i = 0; i < le32_to_int(gpt_head.num_partition_entries); i++) {
+
+ if (is_pte_valid(&(*pgpt_pte)[i])) {
+ printf("%s%d 0x%llX 0x%llX\n", GPT_ENTRY_NAME,
+ (i + 1),
+ le64_to_int((*pgpt_pte)[i].starting_lba),
+ le64_to_int((*pgpt_pte)[i].ending_lba));
+ } else {
+ break; /* Stop at the first non valid PTE */
+ }
+ }
+
+ /* Remember to free pte */
+ if (*pgpt_pte != NULL) {
+ debug("%s: Freeing pgpt_pte\n", __FUNCTION__);
+ free(*pgpt_pte);
+ }
+ return;
+}
+
+int get_partition_info_efi(block_dev_desc_t * dev_desc, int part,
+ disk_partition_t * info)
+{
+ gpt_header gpt_head;
+ gpt_entry **pgpt_pte = NULL;
+
+ /* "part" argument must be@least 1 */
+ if (!dev_desc || !info || part < 1) {
+ printf("%s: Invalid Argument(s)\n", __FUNCTION__);
+ return -1;
+ }
+
+ /* This function validates AND fills in the GPT header and PTE */
+ if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
+ &(gpt_head), pgpt_pte) != 1) {
+ printf("%s: *** ERROR: Invalid GPT ***\n", __FUNCTION__);
+ return -1;
+ }
+
+ /* The ulong casting limits the maximum disk size to 2 TB */
+ info->start = (ulong) le64_to_int((*pgpt_pte)[part - 1].starting_lba);
+ info->size = (ulong) le64_to_int((*pgpt_pte)[part - 1].ending_lba) - info->start;
+ info->blksz = GPT_BLOCK_SIZE;
+
+ sprintf((char *)info->name, "%s%d\n", GPT_ENTRY_NAME, part);
+ sprintf((char *)info->type, "U-Boot");
+
+ debug("%s: start 0x%lX, size 0x%lX, name %s", __FUNCTION__,
+ info->start, info->size, info->name);
+
+ /* Remember to free pte */
+ if (*pgpt_pte != NULL) {
+ debug("%s: Freeing pgpt_pte\n", __FUNCTION__);
+ free(*pgpt_pte);
+ }
+ return 0;
+}
+
+int test_part_efi(block_dev_desc_t * dev_desc)
+{
+ legacy_mbr legacymbr;
+
+ /* Read legacy MBR from block 0 and validate it */
+ if ((dev_desc->block_read(dev_desc->dev, 0, 1, (ulong *) & legacymbr) != 1)
+ || (is_pmbr_valid(&legacymbr) != 1)) {
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Private functions
+ */
+/*
+ * pmbr_part_valid(): Check for EFI partition signature
+ *
+ * Returns: 1 if EFI GPT partition type is found.
+ */
+static int pmbr_part_valid(struct partition *part)
+{
+ if (part->sys_ind == EFI_PMBR_OSTYPE_EFI_GPT &&
+ le32_to_int(part->start_sect) == 1UL) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * is_pmbr_valid(): test Protective MBR for validity
+ *
+ * Returns: 1 if PMBR is valid, 0 otherwise.
+ * Validity depends on two things:
+ * 1) MSDOS signature is in the last two bytes of the MBR
+ * 2) One partition of type 0xEE is found, checked by pmbr_part_valid()
+ */
+static int is_pmbr_valid(legacy_mbr * mbr)
+{
+ int i = 0;
+
+ if (!mbr || le16_to_int(mbr->signature) != MSDOS_MBR_SIGNATURE) {
+ return 0;
+ }
+
+ for (i = 0; i < 4; i++) {
+ if (pmbr_part_valid(&mbr->partition_record[i])) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/**
+ * is_gpt_valid() - tests one GPT header and PTEs for validity
+ *
+ * lba is the logical block address of the GPT header to test
+ * gpt is a GPT header ptr, filled on return.
+ * ptes is a PTEs ptr, filled on return.
+ *
+ * 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, unsigned long long lba,
+ gpt_header * pgpt_head, gpt_entry ** pgpt_pte)
+{
+ unsigned char crc32_backup[4] = { 0 };
+ unsigned long calc_crc32;
+ unsigned long long lastlba;
+
+ if (!dev_desc || !pgpt_head) {
+ printf("%s: Invalid Argument(s)\n", __FUNCTION__);
+ return 0;
+ }
+
+ /* Read GPT Header from device */
+ if (dev_desc->block_read(dev_desc->dev, lba, 1, pgpt_head) != 1) {
+ printf("*** ERROR: Can't read GPT header ***\n");
+ return 0;
+ }
+
+ /* Check the GPT header signature */
+ if (le64_to_int(pgpt_head->signature) != GPT_HEADER_SIGNATURE) {
+ printf("GUID Partition Table Header signature is wrong:"
+ "0x%llX != 0x%llX\n",
+ (unsigned long long)le64_to_int(pgpt_head->signature),
+ (unsigned long long)GPT_HEADER_SIGNATURE);
+ return 0;
+ }
+
+ /* Check the GUID Partition Table CRC */
+ memcpy(crc32_backup, pgpt_head->header_crc32, sizeof(crc32_backup));
+ memset(pgpt_head->header_crc32, 0, sizeof(pgpt_head->header_crc32));
+
+ calc_crc32 = efi_crc32((const unsigned char *)pgpt_head,
+ le32_to_int(pgpt_head->header_size));
+
+ memcpy(pgpt_head->header_crc32, crc32_backup, sizeof(crc32_backup));
+
+ if (calc_crc32 != le32_to_int(crc32_backup)) {
+ printf("GUID Partition Table Header CRC is wrong:"
+ "0x%08lX != 0x%08lX\n",
+ le32_to_int(crc32_backup), calc_crc32);
+ return 0;
+ }
+
+ /* Check that the my_lba entry points to the LBA that contains the GPT */
+ if (le64_to_int(pgpt_head->my_lba) != lba) {
+ printf("GPT: my_lba incorrect: %llX != %llX\n",
+ (unsigned long long)le64_to_int(pgpt_head->my_lba),
+ (unsigned long long)lba);
+ return 0;
+ }
+
+ /* Check the first_usable_lba and last_usable_lba are within the disk. */
+ lastlba = (unsigned long long)dev_desc->lba;
+ if (le64_to_int(pgpt_head->first_usable_lba) > lastlba) {
+ printf("GPT: first_usable_lba incorrect: %llX > %llX\n",
+ le64_to_int(pgpt_head->first_usable_lba), lastlba);
+ return 0;
+ }
+ if (le64_to_int(pgpt_head->last_usable_lba) > lastlba) {
+ printf("GPT: last_usable_lba incorrect: %llX > %llX\n",
+ le64_to_int(pgpt_head->last_usable_lba), lastlba);
+ return 0;
+ }
+
+ debug("GPT: first_usable_lba: %llX last_usable_lba %llX last lba %llX\n",
+ le64_to_int(pgpt_head->first_usable_lba),
+ le64_to_int(pgpt_head->last_usable_lba), lastlba);
+
+ /* Read and allocate Partition Table Entries */
+ *pgpt_pte = alloc_read_gpt_entries(dev_desc, pgpt_head);
+ if (*pgpt_pte == NULL) {
+ printf("GPT: Failed to allocate memory for PTE\n");
+ return 0;
+ }
+
+ /* Check the GUID Partition Table Entry Array CRC */
+ calc_crc32 = efi_crc32((const unsigned char *)*pgpt_pte,
+ le32_to_int(pgpt_head->num_partition_entries) *
+ le32_to_int(pgpt_head->sizeof_partition_entry));
+
+ if (calc_crc32 != le32_to_int(pgpt_head->partition_entry_array_crc32)) {
+ printf("GUID Partition Table Entry Array CRC is wrong:"
+ "0x%08lX != 0x%08lX\n",
+ le32_to_int(pgpt_head->partition_entry_array_crc32),
+ calc_crc32);
+
+ if (*pgpt_pte != NULL) {
+ free(*pgpt_pte);
+ }
+ return 0;
+ }
+
+ /* We're done, all's well */
+ return 1;
+}
+
+/**
+ * alloc_read_gpt_entries(): reads partition entries from disk
+ * @dev_desc
+ * @gpt - GPT header
+ *
+ * Description: Returns ptes on success, NULL on error.
+ * 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)
+{
+ size_t count = 0;
+ gpt_entry *pte = NULL;
+
+ if (!dev_desc || !pgpt_head) {
+ printf("%s: Invalid Argument(s)\n", __FUNCTION__);
+ return NULL;
+ }
+
+ count = le32_to_int(pgpt_head->num_partition_entries) *
+ le32_to_int(pgpt_head->sizeof_partition_entry);
+
+ debug("%s: count = %lu * %lu = %u\n", __FUNCTION__,
+ le32_to_int(pgpt_head->num_partition_entries),
+ le32_to_int(pgpt_head->sizeof_partition_entry), count);
+
+ /* Allocate memory for PTE, remember to FREE */
+ if (count != 0) {
+ pte = malloc(count);
+ }
+
+ if (count == 0 || pte == NULL) {
+ printf("%s: ERROR: Can't allocate 0x%X bytes for GPT Entries\n",
+ __FUNCTION__, count);
+ return NULL;
+ }
+
+ /* Read GPT Entries from device */
+ if (dev_desc->block_read (dev_desc->dev,
+ (unsigned long)le64_to_int(pgpt_head->partition_entry_lba),
+ (lbaint_t) (count / GPT_BLOCK_SIZE), pte)
+ != (count / GPT_BLOCK_SIZE)) {
+
+ printf("*** ERROR: Can't read GPT Entries ***\n");
+ free(pte);
+ return NULL;
+ }
+ return pte;
+}
+
+/**
+ * is_pte_valid(): validates a single Partition Table Entry
+ * @gpt_entry - Pointer to a single Partition Table Entry
+ *
+ * Description: returns 1 if valid, 0 on error.
+ */
+static int is_pte_valid(gpt_entry * pte)
+{
+ efi_guid_t unused_guid;
+
+ if (!pte) {
+ printf("%s: Invalid Argument(s)\n", __FUNCTION__);
+ return 0;
+ }
+
+ /* Only one validation for now:
+ * The GUID Partition Type != Unused Entry (ALL-ZERO)
+ */
+ memset(unused_guid.b, 0, sizeof(unused_guid.b));
+
+ if (memcmp(pte->partition_type_guid.b, unused_guid.b,
+ sizeof(unused_guid.b)) == 0) {
+
+ debug("%s: Found an unused PTE GUID at 0x%08X\n", __FUNCTION__,
+ (unsigned int)pte);
+
+ return 0;
+ } else {
+ return 1;
+ }
+}
+#endif
diff --git a/disk/part_efi.h b/disk/part_efi.h
new file mode 100644
index 0000000..aad905d
--- /dev/null
+++ b/disk/part_efi.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2008 RuggedCom, Inc.
+ * Richard Retanubun <RichardRetanubun@RuggedCom.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * See also linux/fs/partitions/efi.h
+ *
+ * EFI GUID Partition Table
+ * Per Intel EFI Specification v1.02
+ * http://developer.intel.com/technology/efi/efi.htm
+*/
+
+#ifndef _DISK_PART_EFI_H
+#define _DISK_PART_EFI_H
+
+#define MSDOS_MBR_SIGNATURE 0xAA55
+#define EFI_PMBR_OSTYPE_EFI 0xEF
+#define EFI_PMBR_OSTYPE_EFI_GPT 0xEE
+
+#define GPT_BLOCK_SIZE 512
+#define GPT_HEADER_SIGNATURE 0x5452415020494645ULL
+#define GPT_HEADER_REVISION_V1 0x00010000
+#define GPT_PRIMARY_PARTITION_TABLE_LBA 1ULL
+#define GPT_ENTRY_NAME "gpt"
+
+#define EFI_GUID(a,b,c,d0,d1,d2,d3,d4,d5,d6,d7) \
+((efi_guid_t) \
+{{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \
+ (b) & 0xff, ((b) >> 8) & 0xff, \
+ (c) & 0xff, ((c) >> 8) & 0xff, \
+ (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }})
+
+#define PARTITION_SYSTEM_GUID \
+ EFI_GUID( 0xC12A7328, 0xF81F, 0x11d2, \
+ 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B)
+#define LEGACY_MBR_PARTITION_GUID \
+ EFI_GUID( 0x024DEE41, 0x33E7, 0x11d3, \
+ 0x9D, 0x69, 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F)
+#define PARTITION_MSFT_RESERVED_GUID \
+ EFI_GUID( 0xE3C9E316, 0x0B5C, 0x4DB8, \
+ 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE)
+#define PARTITION_BASIC_DATA_GUID \
+ EFI_GUID( 0xEBD0A0A2, 0xB9E5, 0x4433, \
+ 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7)
+#define PARTITION_LINUX_RAID_GUID \
+ EFI_GUID( 0xa19d880f, 0x05fc, 0x4d3b, \
+ 0xa0, 0x06, 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e)
+#define PARTITION_LINUX_SWAP_GUID \
+ EFI_GUID( 0x0657fd6d, 0xa4ab, 0x43c4, \
+ 0x84, 0xe5, 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f)
+#define PARTITION_LINUX_LVM_GUID \
+ EFI_GUID( 0xe6d6d379, 0xf507, 0x44c2, \
+ 0xa2, 0x3c, 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28)
+
+/* linux/include/efi.h */
+typedef unsigned short efi_char16_t;
+
+typedef struct {
+ unsigned char b[16];
+} efi_guid_t;
+
+/* based on linux/include/genhd.h */
+struct partition {
+ unsigned char boot_ind; /* 0x80 - active */
+ unsigned char head; /* starting head */
+ unsigned char sector; /* starting sector */
+ unsigned char cyl; /* starting cylinder */
+ unsigned char sys_ind; /* What partition type */
+ unsigned char end_head; /* end head */
+ unsigned char end_sector; /* end sector */
+ unsigned char end_cyl; /* end cylinder */
+ unsigned char start_sect[4]; /* starting sector counting from 0 */
+ unsigned char nr_sects[4]; /* nr of sectors in partition */
+} __attribute__ ((packed));
+
+/* based on linux/fs/partitions/efi.h */
+typedef struct _gpt_header {
+ unsigned char signature[8];
+ unsigned char revision[4];
+ unsigned char header_size[4];
+ unsigned char header_crc32[4];
+ unsigned char reserved1[4];
+ unsigned char my_lba[8];
+ unsigned char alternate_lba[8];
+ unsigned char first_usable_lba[8];
+ unsigned char last_usable_lba[8];
+ efi_guid_t disk_guid;
+ unsigned char partition_entry_lba[8];
+ unsigned char num_partition_entries[4];
+ unsigned char sizeof_partition_entry[4];
+ unsigned char partition_entry_array_crc32[4];
+ unsigned char reserved2[GPT_BLOCK_SIZE - 92];
+} __attribute__ ((packed)) gpt_header;
+
+typedef struct _gpt_entry_attributes {
+ unsigned long long required_to_function:1;
+ unsigned long long reserved:47;
+ unsigned long long type_guid_specific:16;
+} __attribute__ ((packed)) gpt_entry_attributes;
+
+typedef struct _gpt_entry {
+ efi_guid_t partition_type_guid;
+ efi_guid_t unique_partition_guid;
+ unsigned char starting_lba[8];
+ unsigned char ending_lba[8];
+ gpt_entry_attributes attributes;
+ efi_char16_t partition_name[72 / sizeof(efi_char16_t)];
+}
+__attribute__ ((packed)) gpt_entry;
+
+typedef struct _legacy_mbr {
+ unsigned char boot_code[440];
+ unsigned char unique_mbr_signature[4];
+ unsigned char unknown[2];
+ struct partition partition_record[4];
+ unsigned char signature[2];
+} __attribute__ ((packed)) legacy_mbr;
+
+#endif /* _DISK_PART_EFI_H */
diff --git a/include/part.h b/include/part.h
index b22a637..980fd04 100644
--- a/include/part.h
+++ b/include/part.h
@@ -69,6 +69,7 @@ typedef struct block_dev_desc {
#define PART_TYPE_DOS 0x02
#define PART_TYPE_ISO 0x03
#define PART_TYPE_AMIGA 0x04
+#define PART_TYPE_EFI 0x05
/*
* Type string for U-Boot bootable partitions
@@ -135,4 +136,11 @@ void print_part_amiga (block_dev_desc_t *dev_desc);
int test_part_amiga (block_dev_desc_t *dev_desc);
#endif
+#ifdef CONFIG_EFI_PARTITION
+/* disk/part_efi.c */
+int get_partition_info_efi (block_dev_desc_t * dev_desc, int part, disk_partition_t *info);
+void print_part_efi (block_dev_desc_t *dev_desc);
+int test_part_efi (block_dev_desc_t *dev_desc);
+#endif
+
#endif /* _PART_H */
--
1.5.5.GIT
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [U-Boot] [PATCH] CONFIG_EFI_PARTITION: Added support for EFI partition in cmd_ext2fs.c
2008-09-26 15:13 ` richardretanubun
@ 2008-10-06 20:10 ` richardretanubun
2008-10-14 13:16 ` Wolfgang Denk
2008-10-14 13:15 ` [U-Boot] [PATCH] Add support for CONFIG_EFI_PARTITION (GUID Partition Table) Wolfgang Denk
1 sibling, 1 reply; 9+ messages in thread
From: richardretanubun @ 2008-10-06 20:10 UTC (permalink / raw)
To: u-boot
Added support for CONFIG_EFI_PARTITION to ext2 commands.
Signed-off-by: Richard Retanubun <RichardRetanubun@RugggedCom.com>
---
Hi Wolfgang,
This patch should be applied on top of the patch that adds EFI partition support.
A workaround without this patch is to #define CONFIG_DOS_PARTITION
and #define CONFIG_EFI_PARTITION when using #define CONFIG_CMD_EXT2
in the include/config/<board-name.h>
Regards,
Richard
common/cmd_ext2.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/common/cmd_ext2.c b/common/cmd_ext2.c
index f569406..cfd4f64 100644
--- a/common/cmd_ext2.c
+++ b/common/cmd_ext2.c
@@ -44,8 +44,8 @@
#include <usb.h>
#endif
-#ifndef CONFIG_DOS_PARTITION
-#error DOS partition support must be selected
+#if !defined(CONFIG_DOS_PARTITION) && !defined(CONFIG_EFI_PARTITION)
+#error DOS or EFI partition support must be selected
#endif
/* #define EXT2_DEBUG */
--
1.5.5.GIT
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [U-Boot] [PATCH] Add support for CONFIG_EFI_PARTITION (GUID Partition Table)
2008-09-26 15:13 ` richardretanubun
2008-10-06 20:10 ` [U-Boot] [PATCH] CONFIG_EFI_PARTITION: Added support for EFI partition in cmd_ext2fs.c richardretanubun
@ 2008-10-14 13:15 ` Wolfgang Denk
1 sibling, 0 replies; 9+ messages in thread
From: Wolfgang Denk @ 2008-10-14 13:15 UTC (permalink / raw)
To: u-boot
Dear richardretanubun,
In message <48DCFC12.20909@ruggedcom.com> you wrote:
> Add support for CONFIG_EFI_PARTITION (GUID Partition Table)
> Based on linux/fs/partitions/efi.[ch]
>
> Signed-off-by: Richard Retanubun <RichardRetanubun@RugggedCom.com>
> ---
> Hi Wolfgang,
>
> Boy, do I suck at submitting patches.
> This is the same patch as before,
> with some minor comment cleanup and proper formatting of patch.
>
> Richard
>
> README | 2 +-
> disk/Makefile | 1 +
> disk/part.c | 33 ++++-
> disk/part_efi.c | 425 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
> disk/part_efi.h | 138 ++++++++++++++++++
> include/part.h | 8 +
> 6 files changed, 603 insertions(+), 4 deletions(-)
> create mode 100644 disk/part_efi.c
> create mode 100644 disk/part_efi.h
Applied to "next" branch, thanks.
Best regards,
Wolfgang Denk
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
Es gibt immer genug fuer die Beduerfnisse aller, aber niemals genug
fuer die Gier einzelner. -- Ghandi
^ permalink raw reply [flat|nested] 9+ messages in thread
* [U-Boot] [PATCH] CONFIG_EFI_PARTITION: Added support for EFI partition in cmd_ext2fs.c
2008-10-06 20:10 ` [U-Boot] [PATCH] CONFIG_EFI_PARTITION: Added support for EFI partition in cmd_ext2fs.c richardretanubun
@ 2008-10-14 13:16 ` Wolfgang Denk
0 siblings, 0 replies; 9+ messages in thread
From: Wolfgang Denk @ 2008-10-14 13:16 UTC (permalink / raw)
To: u-boot
Dear richardretanubun,
In message <48EA70CD.4090304@ruggedcom.com> you wrote:
> Added support for CONFIG_EFI_PARTITION to ext2 commands.
> Signed-off-by: Richard Retanubun <RichardRetanubun@RugggedCom.com>
> ---
> Hi Wolfgang,
>
> This patch should be applied on top of the patch that adds EFI partition support.
>
> A workaround without this patch is to #define CONFIG_DOS_PARTITION
> and #define CONFIG_EFI_PARTITION when using #define CONFIG_CMD_EXT2
> in the include/config/<board-name.h>
>
> Regards,
>
> Richard
>
> common/cmd_ext2.c | 4 ++--
> 1 files changed, 2 insertions(+), 2 deletions(-)
Applied to "next" branch. Thanks.
Best regards,
Wolfgang Denk
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
In an infinite universe all things are possible, including the possi-
bility that the universe does not exist.
- Terry Pratchett, _The Dark Side of the Sun_
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2008-10-14 13:16 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-09-23 21:39 [U-Boot] [PATCH] Add support for CONFIG_EFI_PARTITION (GUID Partition Table) richardretanubun
2008-09-23 22:09 ` Wolfgang Denk
2008-09-23 22:19 ` Andrew Dyer
2008-09-24 13:49 ` richardretanubun
2008-09-24 15:27 ` richardretanubun
2008-09-26 15:13 ` richardretanubun
2008-10-06 20:10 ` [U-Boot] [PATCH] CONFIG_EFI_PARTITION: Added support for EFI partition in cmd_ext2fs.c richardretanubun
2008-10-14 13:16 ` Wolfgang Denk
2008-10-14 13:15 ` [U-Boot] [PATCH] Add support for CONFIG_EFI_PARTITION (GUID Partition Table) Wolfgang Denk
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.