summaryrefslogtreecommitdiffstats
path: root/disk/part_efi.c
diff options
context:
space:
mode:
Diffstat (limited to 'disk/part_efi.c')
-rw-r--r--disk/part_efi.c268
1 files changed, 195 insertions, 73 deletions
diff --git a/disk/part_efi.c b/disk/part_efi.c
index efed58f81d..338010e148 100644
--- a/disk/part_efi.c
+++ b/disk/part_efi.c
@@ -69,6 +69,107 @@ static inline int is_bootable(gpt_entry *p)
sizeof(efi_guid_t));
}
+static int validate_gpt_header(gpt_header *gpt_h, lbaint_t lba,
+ lbaint_t lastlba)
+{
+ uint32_t crc32_backup = 0;
+ uint32_t calc_crc32;
+
+ /* Check the GPT header signature */
+ if (le64_to_cpu(gpt_h->signature) != GPT_HEADER_SIGNATURE) {
+ printf("%s signature is wrong: 0x%llX != 0x%llX\n",
+ "GUID Partition Table Header",
+ le64_to_cpu(gpt_h->signature),
+ GPT_HEADER_SIGNATURE);
+ return -1;
+ }
+
+ /* Check the GUID Partition Table CRC */
+ memcpy(&crc32_backup, &gpt_h->header_crc32, sizeof(crc32_backup));
+ memset(&gpt_h->header_crc32, 0, sizeof(gpt_h->header_crc32));
+
+ calc_crc32 = efi_crc32((const unsigned char *)gpt_h,
+ le32_to_cpu(gpt_h->header_size));
+
+ memcpy(&gpt_h->header_crc32, &crc32_backup, sizeof(crc32_backup));
+
+ if (calc_crc32 != le32_to_cpu(crc32_backup)) {
+ printf("%s CRC is wrong: 0x%x != 0x%x\n",
+ "GUID Partition Table Header",
+ le32_to_cpu(crc32_backup), calc_crc32);
+ return -1;
+ }
+
+ /*
+ * Check that the my_lba entry points to the LBA that contains the GPT
+ */
+ if (le64_to_cpu(gpt_h->my_lba) != lba) {
+ printf("GPT: my_lba incorrect: %llX != " LBAF "\n",
+ le64_to_cpu(gpt_h->my_lba),
+ lba);
+ return -1;
+ }
+
+ /*
+ * Check that the first_usable_lba and that the last_usable_lba are
+ * within the disk.
+ */
+ if (le64_to_cpu(gpt_h->first_usable_lba) > lastlba) {
+ printf("GPT: first_usable_lba incorrect: %llX > " LBAF "\n",
+ le64_to_cpu(gpt_h->first_usable_lba), lastlba);
+ return -1;
+ }
+ if (le64_to_cpu(gpt_h->last_usable_lba) > lastlba) {
+ printf("GPT: last_usable_lba incorrect: %llX > " LBAF "\n",
+ le64_to_cpu(gpt_h->last_usable_lba), lastlba);
+ return -1;
+ }
+
+ debug("GPT: first_usable_lba: %llX last_usable_lba: %llX last lba: "
+ LBAF "\n", le64_to_cpu(gpt_h->first_usable_lba),
+ le64_to_cpu(gpt_h->last_usable_lba), lastlba);
+
+ return 0;
+}
+
+static int validate_gpt_entries(gpt_header *gpt_h, gpt_entry *gpt_e)
+{
+ uint32_t calc_crc32;
+
+ /* Check the GUID Partition Table Entry Array CRC */
+ calc_crc32 = efi_crc32((const unsigned char *)gpt_e,
+ le32_to_cpu(gpt_h->num_partition_entries) *
+ le32_to_cpu(gpt_h->sizeof_partition_entry));
+
+ if (calc_crc32 != le32_to_cpu(gpt_h->partition_entry_array_crc32)) {
+ printf("%s: 0x%x != 0x%x\n",
+ "GUID Partition Table Entry Array CRC is wrong",
+ le32_to_cpu(gpt_h->partition_entry_array_crc32),
+ calc_crc32);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void prepare_backup_gpt_header(gpt_header *gpt_h)
+{
+ uint32_t calc_crc32;
+ uint64_t val;
+
+ /* recalculate the values for the Backup GPT Header */
+ val = le64_to_cpu(gpt_h->my_lba);
+ gpt_h->my_lba = gpt_h->alternate_lba;
+ gpt_h->alternate_lba = cpu_to_le64(val);
+ gpt_h->partition_entry_lba =
+ cpu_to_le64(le64_to_cpu(gpt_h->last_usable_lba) + 1);
+ gpt_h->header_crc32 = 0;
+
+ calc_crc32 = efi_crc32((const unsigned char *)gpt_h,
+ le32_to_cpu(gpt_h->header_size));
+ gpt_h->header_crc32 = cpu_to_le32(calc_crc32);
+}
+
#ifdef CONFIG_EFI_PARTITION
/*
* Public Functions (include/part.h)
@@ -259,7 +360,6 @@ int write_gpt_table(block_dev_desc_t *dev_desc,
const int pte_blk_cnt = BLOCK_CNT((gpt_h->num_partition_entries
* sizeof(gpt_entry)), dev_desc);
u32 calc_crc32;
- u64 val;
debug("max lba: %x\n", (u32) dev_desc->lba);
/* Setup the Protective MBR */
@@ -284,15 +384,7 @@ int write_gpt_table(block_dev_desc_t *dev_desc,
!= pte_blk_cnt)
goto err;
- /* recalculate the values for the Backup GPT Header */
- val = le64_to_cpu(gpt_h->my_lba);
- gpt_h->my_lba = gpt_h->alternate_lba;
- gpt_h->alternate_lba = cpu_to_le64(val);
- gpt_h->header_crc32 = 0;
-
- calc_crc32 = efi_crc32((const unsigned char *)gpt_h,
- le32_to_cpu(gpt_h->header_size));
- gpt_h->header_crc32 = cpu_to_le32(calc_crc32);
+ prepare_backup_gpt_header(gpt_h);
if (dev_desc->block_write(dev_desc->dev,
(lbaint_t)le64_to_cpu(gpt_h->last_usable_lba)
@@ -455,6 +547,97 @@ err:
free(gpt_h);
return ret;
}
+
+int is_valid_gpt_buf(block_dev_desc_t *dev_desc, void *buf)
+{
+ gpt_header *gpt_h;
+ gpt_entry *gpt_e;
+
+ /* determine start of GPT Header in the buffer */
+ gpt_h = buf + (GPT_PRIMARY_PARTITION_TABLE_LBA *
+ dev_desc->blksz);
+ if (validate_gpt_header(gpt_h, GPT_PRIMARY_PARTITION_TABLE_LBA,
+ dev_desc->lba))
+ return -1;
+
+ /* determine start of GPT Entries in the buffer */
+ gpt_e = buf + (le64_to_cpu(gpt_h->partition_entry_lba) *
+ dev_desc->blksz);
+ if (validate_gpt_entries(gpt_h, gpt_e))
+ return -1;
+
+ return 0;
+}
+
+int write_mbr_and_gpt_partitions(block_dev_desc_t *dev_desc, void *buf)
+{
+ gpt_header *gpt_h;
+ gpt_entry *gpt_e;
+ int gpt_e_blk_cnt;
+ lbaint_t lba;
+ int cnt;
+
+ if (is_valid_gpt_buf(dev_desc, buf))
+ return -1;
+
+ /* determine start of GPT Header in the buffer */
+ gpt_h = buf + (GPT_PRIMARY_PARTITION_TABLE_LBA *
+ dev_desc->blksz);
+
+ /* determine start of GPT Entries in the buffer */
+ gpt_e = buf + (le64_to_cpu(gpt_h->partition_entry_lba) *
+ dev_desc->blksz);
+ gpt_e_blk_cnt = BLOCK_CNT((le32_to_cpu(gpt_h->num_partition_entries) *
+ le32_to_cpu(gpt_h->sizeof_partition_entry)),
+ dev_desc);
+
+ /* 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) {
+ 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) {
+ 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) {
+ printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n",
+ __func__, "Primary GPT Entries", cnt, lba);
+ return 1;
+ }
+
+ prepare_backup_gpt_header(gpt_h);
+
+ /* 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) {
+ 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) {
+ printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n",
+ __func__, "Backup GPT Header", cnt, lba);
+ return 1;
+ }
+
+ return 0;
+}
#endif
/*
@@ -511,10 +694,6 @@ static int is_pmbr_valid(legacy_mbr * mbr)
static int is_gpt_valid(block_dev_desc_t *dev_desc, u64 lba,
gpt_header *pgpt_head, gpt_entry **pgpt_pte)
{
- u32 crc32_backup = 0;
- u32 calc_crc32;
- u64 lastlba;
-
if (!dev_desc || !pgpt_head) {
printf("%s: Invalid Argument(s)\n", __func__);
return 0;
@@ -527,55 +706,8 @@ static int is_gpt_valid(block_dev_desc_t *dev_desc, u64 lba,
return 0;
}
- /* Check the GPT header signature */
- if (le64_to_cpu(pgpt_head->signature) != GPT_HEADER_SIGNATURE) {
- printf("GUID Partition Table Header signature is wrong:"
- "0x%llX != 0x%llX\n",
- le64_to_cpu(pgpt_head->signature),
- 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_cpu(pgpt_head->header_size));
-
- memcpy(&pgpt_head->header_crc32, &crc32_backup, sizeof(crc32_backup));
-
- if (calc_crc32 != le32_to_cpu(crc32_backup)) {
- printf("GUID Partition Table Header CRC is wrong:"
- "0x%x != 0x%x\n",
- le32_to_cpu(crc32_backup), calc_crc32);
- return 0;
- }
-
- /* Check that the my_lba entry points to the LBA that contains the GPT */
- if (le64_to_cpu(pgpt_head->my_lba) != lba) {
- printf("GPT: my_lba incorrect: %llX != %" PRIX64 "\n",
- le64_to_cpu(pgpt_head->my_lba),
- lba);
+ if (validate_gpt_header(pgpt_head, (lbaint_t)lba, dev_desc->lba))
return 0;
- }
-
- /* Check the first_usable_lba and last_usable_lba are within the disk. */
- lastlba = (u64)dev_desc->lba;
- if (le64_to_cpu(pgpt_head->first_usable_lba) > lastlba) {
- printf("GPT: first_usable_lba incorrect: %llX > %" PRIX64 "\n",
- le64_to_cpu(pgpt_head->first_usable_lba), lastlba);
- return 0;
- }
- if (le64_to_cpu(pgpt_head->last_usable_lba) > lastlba) {
- printf("GPT: last_usable_lba incorrect: %llX > %" PRIX64 "\n",
- le64_to_cpu(pgpt_head->last_usable_lba), lastlba);
- return 0;
- }
-
- debug("GPT: first_usable_lba: %llX last_usable_lba %llX last lba %"
- PRIX64 "\n", le64_to_cpu(pgpt_head->first_usable_lba),
- le64_to_cpu(pgpt_head->last_usable_lba), lastlba);
/* Read and allocate Partition Table Entries */
*pgpt_pte = alloc_read_gpt_entries(dev_desc, pgpt_head);
@@ -584,17 +716,7 @@ static int is_gpt_valid(block_dev_desc_t *dev_desc, u64 lba,
return 0;
}
- /* Check the GUID Partition Table Entry Array CRC */
- calc_crc32 = efi_crc32((const unsigned char *)*pgpt_pte,
- le32_to_cpu(pgpt_head->num_partition_entries) *
- le32_to_cpu(pgpt_head->sizeof_partition_entry));
-
- if (calc_crc32 != le32_to_cpu(pgpt_head->partition_entry_array_crc32)) {
- printf("GUID Partition Table Entry Array CRC is wrong:"
- "0x%x != 0x%x\n",
- le32_to_cpu(pgpt_head->partition_entry_array_crc32),
- calc_crc32);
-
+ if (validate_gpt_entries(pgpt_head, *pgpt_pte)) {
free(*pgpt_pte);
return 0;
}
OpenPOWER on IntegriCloud