gpt: repair the gpt table when head or backup gpt table is invalid

There is some gpt table errors when use open source tools to download
gpt table or is destroyed by other procedure.
Such as:
1.Get error storage size.
2.Download the gpt table in the error place.
3.The gpt table is destroyed by other procedure.

So test the gpt table is correct or not firstly. If the gpt table header is
error, update the correct gpt table. If the last partition size error in
the gpt table entry, get the size of current storage by dev_desc and update
the last partition size.

Change-Id: I0ef91a0f8462eca52924d17c5aaefcdae602267d
Signed-off-by: Jason Zhu <jason.zhu@rock-chips.com>
This commit is contained in:
Jason Zhu 2018-11-19 22:12:33 +08:00 committed by Kever Yang
parent f05ce84792
commit f70f0bfd86
1 changed files with 122 additions and 0 deletions

View File

@ -339,6 +339,93 @@ int part_get_info_efi(struct blk_desc *dev_desc, int part,
return 0; return 0;
} }
#ifdef RKIMG_BOOTLOADER
static void gpt_entry_modify(struct blk_desc *dev_desc,
gpt_entry *gpt_pte,
gpt_header *gpt_head)
{
int i;
uint32_t calc_crc32;
for (i = 0; i < gpt_head->num_partition_entries; i++) {
if (!is_pte_valid(&gpt_pte[i]))
break;
}
if (gpt_pte[i - 1].ending_lba <= (dev_desc->lba - 0x22))
return;
gpt_pte[i - 1].ending_lba = dev_desc->lba - 0x22;
calc_crc32 = efi_crc32((const unsigned char *)gpt_pte,
le32_to_cpu(gpt_head->num_partition_entries) *
le32_to_cpu(gpt_head->sizeof_partition_entry));
gpt_head->partition_entry_array_crc32 = calc_crc32;
}
static int part_efi_repair(struct blk_desc *dev_desc, gpt_entry *gpt_pte,
gpt_header *gpt_head, int head_gpt_valid,
int backup_gpt_valid)
{
uint32_t calc_crc32;
size_t count = 0, blk_cnt;
lbaint_t blk;
if (head_gpt_valid == 1 && backup_gpt_valid == 1) {
return 0;
} else if (head_gpt_valid == 0 && backup_gpt_valid == 0) {
return -1;
} else if (head_gpt_valid == 1 && backup_gpt_valid == 0) {
gpt_head->header_crc32 = 0;
gpt_head->my_lba = dev_desc->lba - 1;
gpt_head->alternate_lba = 1;
gpt_head->partition_entry_lba = dev_desc->lba - 0x21;
gpt_entry_entry_modify(dev_desc, gpt_pte, gpt_head);
calc_crc32 = efi_crc32((const unsigned char *)gpt_head,
le32_to_cpu(gpt_head->header_size));
gpt_head->header_crc32 = calc_crc32;
if (blk_dwrite(dev_desc, dev_desc->lba - 1, 1, gpt_head) != 1) {
printf("*** ERROR: Can't write GPT header ***\n");
return -1;
}
count = le32_to_cpu(gpt_head->num_partition_entries) *
le32_to_cpu(gpt_head->sizeof_partition_entry);
blk = le64_to_cpu(gpt_head->partition_entry_lba);
blk_cnt = BLOCK_CNT(count, dev_desc);
if (blk_dwrite(dev_desc, blk, (lbaint_t)blk_cnt, gpt_pte) !=
blk_cnt) {
printf("*** ERROR: Can't write entry partitions ***\n");
return -1;
}
printf("Repair the backup gpt table OK!\n");
} else if (head_gpt_valid == 0 && backup_gpt_valid == 1) {
gpt_head->header_crc32 = 0;
gpt_head->my_lba = 1;
gpt_head->alternate_lba = dev_desc->lba - 1;
gpt_head->partition_entry_lba = 0x22;
gpt_entry_entry_modify(dev_desc, gpt_pte, gpt_head);
calc_crc32 = efi_crc32((const unsigned char *)gpt_head,
le32_to_cpu(gpt_head->header_size));
gpt_head->header_crc32 = calc_crc32;
if (blk_dwrite(dev_desc, 1, 1, gpt_head) != 1) {
printf("*** ERROR: Can't write GPT header ***\n");
return -1;
}
count = le32_to_cpu(gpt_head->num_partition_entries) *
le32_to_cpu(gpt_head->sizeof_partition_entry);
blk = le64_to_cpu(gpt_head->partition_entry_lba);
blk_cnt = BLOCK_CNT(count, dev_desc);
if (blk_dwrite(dev_desc, blk, (lbaint_t)blk_cnt, gpt_pte) !=
blk_cnt) {
printf("*** ERROR: Can't write entry partitions ***\n");
return -1;
}
printf("Repair the Primary gpt table OK!\n");
}
return 0;
}
#endif
static int part_test_efi(struct blk_desc *dev_desc) static int part_test_efi(struct blk_desc *dev_desc)
{ {
ALLOC_CACHE_ALIGN_BUFFER_PAD(legacy_mbr, legacymbr, 1, dev_desc->blksz); ALLOC_CACHE_ALIGN_BUFFER_PAD(legacy_mbr, legacymbr, 1, dev_desc->blksz);
@ -348,6 +435,41 @@ static int part_test_efi(struct blk_desc *dev_desc)
|| (is_pmbr_valid(legacymbr) != 1)) { || (is_pmbr_valid(legacymbr) != 1)) {
return -1; return -1;
} }
#ifdef RKIMG_BOOTLOADER
gpt_entry *h_gpt_pte = NULL;
gpt_header *h_gpt_head = NULL;
gpt_entry *b_gpt_pte = NULL;
gpt_header *b_gpt_head = NULL;
int head_gpt_valid = 0;
int backup_gpt_valid = 0;
if (!h_gpt_head)
h_gpt_head = memalign(ARCH_DMA_MINALIGN, dev_desc->blksz);
if (!b_gpt_head)
b_gpt_head = memalign(ARCH_DMA_MINALIGN, dev_desc->blksz);
head_gpt_valid = is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
h_gpt_head, &h_gpt_pte);
backup_gpt_valid = is_gpt_valid(dev_desc, (dev_desc->lba - 1),
b_gpt_head, &b_gpt_pte);
if (head_gpt_valid == 1 && backup_gpt_valid == 0) {
if (part_efi_repair(dev_desc, h_gpt_pte, h_gpt_head,
head_gpt_valid, backup_gpt_valid))
printf("Backup GPT repair fail!\n");
} else if (head_gpt_valid == 0 && backup_gpt_valid == 1) {
if (part_efi_repair(dev_desc, b_gpt_pte, b_gpt_head,
head_gpt_valid, backup_gpt_valid))
printf("Primary GPT repair fail!\n");
}
free(h_gpt_pte);
h_gpt_pte = NULL;
free(h_gpt_head);
h_gpt_head = NULL;
free(b_gpt_pte);
b_gpt_pte = NULL;
free(b_gpt_head);
b_gpt_head = NULL;
#endif
return 0; return 0;
} }