X-Git-Url: https://git.kernelconcepts.de/?a=blobdiff_plain;f=disk%2Fpart_efi.c;h=5856f9321118da1be38015d4bce89e8e498f1683;hb=e443fec05c595cf180c2365cbe30548e3682d8e4;hp=216a2920c27da5f893f3f94b6288fd720ab19d1a;hpb=519fdde9e6a6ebce7dc743b4f5621503d25b7a45;p=karo-tx-uboot.git diff --git a/disk/part_efi.c b/disk/part_efi.c index 216a2920c2..5856f93211 100644 --- a/disk/part_efi.c +++ b/disk/part_efi.c @@ -6,18 +6,15 @@ */ /* - * Problems with CONFIG_SYS_64BIT_LBA: - * - * struct disk_partition.start in include/part.h is sized as ulong. - * When CONFIG_SYS_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 + * NOTE: + * when CONFIG_SYS_64BIT_LBA is not defined, lbaint_t is 32 bits; this + * limits the maximum size of addressable storage to < 2 Terra Bytes */ #include #include #include #include +#include #include #include #include @@ -43,8 +40,8 @@ static inline u32 efi_crc32(const void *buf, u32 len) 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 int is_gpt_valid(block_dev_desc_t *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 int is_pte_valid(gpt_entry * pte); @@ -72,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) @@ -93,7 +191,15 @@ void print_part_efi(block_dev_desc_t * dev_desc) if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA, gpt_head, &gpt_pte) != 1) { printf("%s: *** ERROR: Invalid GPT ***\n", __func__); - return; + if (is_gpt_valid(dev_desc, (dev_desc->lba - 1), + gpt_head, &gpt_pte) != 1) { + printf("%s: *** ERROR: Invalid Backup GPT ***\n", + __func__); + return; + } else { + printf("%s: *** Using Backup GPT ***\n", + __func__); + } } debug("%s: gpt-entry at %p\n", __func__, gpt_pte); @@ -142,7 +248,15 @@ int get_partition_info_efi(block_dev_desc_t * dev_desc, int part, 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; + } else { + printf("%s: *** Using Backup GPT ***\n", + __func__); + } } if (part > le32_to_cpu(gpt_head->num_partition_entries) || @@ -153,10 +267,10 @@ int get_partition_info_efi(block_dev_desc_t * dev_desc, int part, return -1; } - /* The ulong casting limits the maximum disk size to 2 TB */ - info->start = (u64)le64_to_cpu(gpt_pte[part - 1].starting_lba); + /* The 'lbaint_t' casting may limit the maximum disk size to 2 TB */ + info->start = (lbaint_t)le64_to_cpu(gpt_pte[part - 1].starting_lba); /* The ending LBA is inclusive, to calculate size, add 1 to it */ - info->size = ((u64)le64_to_cpu(gpt_pte[part - 1].ending_lba) + 1) + info->size = (lbaint_t)le64_to_cpu(gpt_pte[part - 1].ending_lba) + 1 - info->start; info->blksz = dev_desc->blksz; @@ -169,7 +283,7 @@ int get_partition_info_efi(block_dev_desc_t * dev_desc, int part, UUID_STR_FORMAT_GUID); #endif - debug("%s: start 0x" LBAF ", size 0x" LBAF ", name %s", __func__, + debug("%s: start 0x" LBAF ", size 0x" LBAF ", name %s\n", __func__, info->start, info->size, info->name); /* Remember to free pte */ @@ -177,6 +291,25 @@ int get_partition_info_efi(block_dev_desc_t * dev_desc, int part, 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) { ALLOC_CACHE_ALIGN_BUFFER_PAD(legacy_mbr, legacymbr, 1, dev_desc->blksz); @@ -209,7 +342,7 @@ static int set_protective_mbr(block_dev_desc_t *dev_desc) p_mbr->signature = MSDOS_MBR_SIGNATURE; p_mbr->partition_record[0].sys_ind = EFI_PMBR_OSTYPE_EFI_GPT; p_mbr->partition_record[0].start_sect = 1; - p_mbr->partition_record[0].nr_sects = (u32) dev_desc->lba; + 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) { @@ -227,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 */ @@ -252,23 +384,17 @@ int write_gpt_table(block_dev_desc_t *dev_desc, != pte_blk_cnt) goto err; - /* recalculate the values for the Second 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, - le32_to_cpu(gpt_h->last_usable_lba + 1), + (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, - le32_to_cpu(gpt_h->my_lba), 1, gpt_h) != 1) + (lbaint_t)le64_to_cpu(gpt_h->my_lba), 1, + gpt_h) != 1) goto err; debug("GPT successfully written to block device!\n"); @@ -282,8 +408,10 @@ int write_gpt_table(block_dev_desc_t *dev_desc, int gpt_fill_pte(gpt_header *gpt_h, gpt_entry *gpt_e, disk_partition_t *partitions, int parts) { - u32 offset = (u32)le32_to_cpu(gpt_h->first_usable_lba); - ulong start; + lbaint_t offset = (lbaint_t)le64_to_cpu(gpt_h->first_usable_lba); + lbaint_t start; + lbaint_t last_usable_lba = (lbaint_t) + le64_to_cpu(gpt_h->last_usable_lba); int i, k; size_t efiname_len, dosname_len; #ifdef CONFIG_PARTITION_UUIDS @@ -305,7 +433,7 @@ int gpt_fill_pte(gpt_header *gpt_h, gpt_entry *gpt_e, gpt_e[i].starting_lba = cpu_to_le64(offset); offset += partitions[i].size; } - if (offset >= gpt_h->last_usable_lba) { + if (offset >= last_usable_lba) { printf("Partitions layout exceds disk size\n"); return -1; } @@ -347,7 +475,8 @@ int gpt_fill_pte(gpt_header *gpt_h, gpt_entry *gpt_e, gpt_e[i].partition_name[k] = (efi_char16_t)(partitions[i].name[k]); - debug("%s: name: %s offset[%d]: 0x%x size[%d]: 0x" LBAF "\n", + debug("%s: name: %s offset[%d]: 0x" LBAF + " size[%d]: 0x" LBAF "\n", __func__, partitions[i].name, i, offset, i, partitions[i].size); } @@ -418,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 /* @@ -471,73 +691,23 @@ static int is_pmbr_valid(legacy_mbr * mbr) * 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) +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; - unsigned long long lastlba; - if (!dev_desc || !pgpt_head) { printf("%s: Invalid Argument(s)\n", __func__); return 0; } /* Read GPT Header from device */ - if (dev_desc->block_read(dev_desc->dev, lba, 1, pgpt_head) != 1) { + if (dev_desc->block_read(dev_desc->dev, (lbaint_t)lba, 1, pgpt_head) + != 1) { printf("*** ERROR: Can't read GPT header ***\n"); 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 != %llX\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 = (unsigned long long)dev_desc->lba; - if (le64_to_cpu(pgpt_head->first_usable_lba) > lastlba) { - printf("GPT: first_usable_lba incorrect: %llX > %llX\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 > %llX\n", - (u64) le64_to_cpu(pgpt_head->last_usable_lba), lastlba); - return 0; - } - - debug("GPT: first_usable_lba: %llX last_usable_lba %llX last lba %llX\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); @@ -546,17 +716,7 @@ static int is_gpt_valid(block_dev_desc_t * dev_desc, unsigned long long 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; } @@ -608,7 +768,7 @@ static gpt_entry *alloc_read_gpt_entries(block_dev_desc_t * dev_desc, /* Read GPT Entries from device */ blk_cnt = BLOCK_CNT(count, dev_desc); if (dev_desc->block_read (dev_desc->dev, - le64_to_cpu(pgpt_head->partition_entry_lba), + (lbaint_t)le64_to_cpu(pgpt_head->partition_entry_lba), (lbaint_t) (blk_cnt), pte) != blk_cnt) {