/** * find_valid_gpt() - Search disk for valid GPT headers and PTEs * @state * @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 newly allocated GPT header and PTEs. * Validity depends on PMBR being valid (or being overridden by the * 'gpt' kernel command line option) and finding either the Primary * GPT header and PTEs valid, or the Alternate GPT header and PTEs * valid. If the Primary GPT header is not valid, the Alternate GPT header * is not checked unless the 'gpt' kernel command line option is passed. * This protects against devices which misreport their size, and forces * the user to decide to use the Alternate GPT. */ static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt, gpt_entry **ptes) { int good_pgpt = 0, good_agpt = 0, good_pmbr = 0; gpt_header *pgpt = NULL, *agpt = NULL; gpt_entry *pptes = NULL, *aptes = NULL; legacy_mbr *legacymbr; u64 lastlba; if (!ptes) return 0; lastlba = last_lba(state->bdev); if (!force_gpt) { /* This will be added to the EFI Spec. per Intel after v1.02. */ legacymbr = kzalloc(sizeof (*legacymbr), GFP_KERNEL); if (legacymbr) { read_lba(state, 0, (u8 *) legacymbr, sizeof (*legacymbr)); good_pmbr = is_pmbr_valid(legacymbr); // panic before kfree to check the buffer content if (!good_pmbr && !memcmp(state->pp_buf, " mmcblk0", 8)) BUG_ON(1); kfree(legacymbr); } if (!good_pmbr) goto fail; } good_pgpt = is_gpt_valid(state, GPT_PRIMARY_PARTITION_TABLE_LBA, &pgpt, &pptes); if (good_pgpt) good_agpt = is_gpt_valid(state, le64_to_cpu(pgpt->alternate_lba), &agpt, &aptes); if (!good_agpt && force_gpt) good_agpt = is_gpt_valid(state, lastlba, &agpt, &aptes); /* The obviously unsuccessful case */ if (!good_pgpt && !good_agpt) goto fail; compare_gpts(pgpt, agpt, lastlba); /* The good cases */ if (good_pgpt) { *gpt = pgpt; *ptes = pptes; kfree(agpt); kfree(aptes); if (!good_agpt) { printk(KERN_WARNING "Alternate GPT is invalid, " "using primary GPT.\n"); } return 1; } else if (good_agpt) { *gpt = agpt; *ptes = aptes; kfree(pgpt); kfree(pptes); printk(KERN_WARNING "Primary GPT is invalid, using alternate GPT.\n"); return 1; } fail: // panic before kfree to check the buffer content if (!memcmp(state->pp_buf, " mmcblk0", 8)) BUG_ON(1); kfree(pgpt); kfree(agpt); kfree(pptes); kfree(aptes); *gpt = NULL; *ptes = NULL; return 0; }
/** * find_valid_gpt() - Search disk for valid GPT headers and PTEs * @bdev * @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 newly allocated GPT header and PTEs. * Validity depends on PMBR being valid (or being overridden by the * 'gpt' kernel command line option) and finding either the Primary * GPT header and PTEs valid, or the Alternate GPT header and PTEs * valid. If the Primary GPT header is not valid, the Alternate GPT header * is not checked unless the 'gpt' kernel command line option is passed. * This protects against devices which misreport their size, and forces * the user to decide to use the Alternate GPT. */ static int find_valid_gpt(struct block_device *bdev, gpt_header **gpt, gpt_entry **ptes) { int good_pgpt = 0, good_agpt = 0, good_pmbr = 0; gpt_header *pgpt = NULL, *agpt = NULL; gpt_entry *pptes = NULL, *aptes = NULL; legacy_mbr *legacymbr; u64 lastlba; if (!bdev || !gpt || !ptes) return 0; lastlba = last_lba(bdev); if (!force_gpt) { /* This will be added to the EFI Spec. per Intel after v1.02. */ legacymbr = kzalloc(sizeof (*legacymbr), GFP_KERNEL); if (legacymbr) { read_lba(bdev, 0, (u8 *) legacymbr, sizeof (*legacymbr)); good_pmbr = is_pmbr_valid(legacymbr); kfree(legacymbr); } if (!good_pmbr) goto fail; } good_pgpt = is_gpt_valid(bdev, GPT_PRIMARY_PARTITION_TABLE_LBA, &pgpt, &pptes); if (good_pgpt) good_agpt = is_gpt_valid(bdev, le64_to_cpu(pgpt->alternate_lba), &agpt, &aptes); if (!good_agpt && force_gpt) good_agpt = is_gpt_valid(bdev, lastlba, &agpt, &aptes); /* The obviously unsuccessful case */ if (!good_pgpt && !good_agpt) goto fail; compare_gpts(pgpt, agpt, lastlba); /* The good cases */ if (good_pgpt) { *gpt = pgpt; *ptes = pptes; kfree(agpt); kfree(aptes); if (!good_agpt) { printk(KERN_WARNING "Alternate GPT is invalid, " "using primary GPT.\n"); } return 1; } else if (good_agpt) { *gpt = agpt; *ptes = aptes; kfree(pgpt); kfree(pptes); printk(KERN_WARNING "Primary GPT is invalid, using alternate GPT.\n"); return 1; } fail: kfree(pgpt); kfree(agpt); kfree(pptes); kfree(aptes); *gpt = NULL; *ptes = NULL; return 0; }
/** * find_valid_gpt() - Search disk for valid GPT headers and PTEs * @fd is an open file descriptor to the whole disk * @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 newly allocated GPT header and PTEs. * Validity depends on finding either the Primary GPT header and PTEs valid, * or the Alternate GPT header and PTEs valid, and the PMBR valid. */ static int find_valid_gpt(int fd, gpt_header ** gpt, gpt_entry ** ptes) { extern int force_gpt; int good_pgpt = 0, good_agpt = 0, good_pmbr = 0; gpt_header *pgpt = NULL, *agpt = NULL; gpt_entry *pptes = NULL, *aptes = NULL; legacy_mbr *legacymbr = NULL; uint64_t lastlba; if (!gpt || !ptes) return 0; lastlba = last_lba(fd); good_pgpt = is_gpt_valid(fd, GPT_PRIMARY_PARTITION_TABLE_LBA, &pgpt, &pptes); if (good_pgpt) { good_agpt = is_gpt_valid(fd, __le64_to_cpu(pgpt->alternate_lba), &agpt, &aptes); if (!good_agpt) { good_agpt = is_gpt_valid(fd, lastlba, &agpt, &aptes); } } else { good_agpt = is_gpt_valid(fd, lastlba, &agpt, &aptes); } /* The obviously unsuccessful case */ if (!good_pgpt && !good_agpt) { goto fail; } /* This will be added to the EFI Spec. per Intel after v1.02. */ legacymbr = malloc(sizeof (*legacymbr)); if (legacymbr) { memset(legacymbr, 0, sizeof (*legacymbr)); read_lba(fd, 0, (uint8_t *) legacymbr, sizeof (*legacymbr)); good_pmbr = is_pmbr_valid(legacymbr); free(legacymbr); legacymbr=NULL; } /* Failure due to bad PMBR */ if ((good_pgpt || good_agpt) && !good_pmbr && !force_gpt) { fprintf(stderr, " Warning: Disk has a valid GPT signature " "but invalid PMBR.\n" " Assuming this disk is *not* a GPT disk anymore.\n" " Use gpt kernel option to override. " "Use GNU Parted to correct disk.\n"); goto fail; } /* Would fail due to bad PMBR, but force GPT anyhow */ if ((good_pgpt || good_agpt) && !good_pmbr && force_gpt) { fprintf(stderr, " Warning: Disk has a valid GPT signature but " "invalid PMBR.\n" " Use GNU Parted to correct disk.\n" " gpt option taken, disk treated as GPT.\n"); } compare_gpts(pgpt, agpt, lastlba); /* The good cases */ if (good_pgpt && (good_pmbr || force_gpt)) { *gpt = pgpt; *ptes = pptes; if (agpt) { free(agpt); agpt = NULL; } if (aptes) { free(aptes); aptes = NULL; } if (!good_agpt) { fprintf(stderr, "Alternate GPT is invalid, " "using primary GPT.\n"); } return 1; } else if (good_agpt && (good_pmbr || force_gpt)) { *gpt = agpt; *ptes = aptes; if (pgpt) { free(pgpt); pgpt = NULL; } if (pptes) { free(pptes); pptes = NULL; } fprintf(stderr, "Primary GPT is invalid, using alternate GPT.\n"); return 1; } fail: if (pgpt) { free(pgpt); pgpt=NULL; } if (agpt) { free(agpt); agpt=NULL; } if (pptes) { free(pptes); pptes=NULL; } if (aptes) { free(aptes); aptes=NULL; } *gpt = NULL; *ptes = NULL; return 0; }
/** * find_valid_gpt() - Search disk for valid GPT headers and PTEs * @state * @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 newly allocated GPT header and PTEs. * Validity depends on PMBR being valid (or being overridden by the * 'gpt' kernel command line option) and finding either the Primary * GPT header and PTEs valid, or the Alternate GPT header and PTEs * valid. If the Primary GPT header is not valid, the Alternate GPT header * is not checked unless the 'gpt' kernel command line option is passed. * This protects against devices which misreport their size, and forces * the user to decide to use the Alternate GPT. */ static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt, gpt_entry **ptes) { int good_pgpt = 0, good_agpt = 0, good_pmbr = 0; gpt_header *pgpt = NULL, *agpt = NULL; gpt_entry *pptes = NULL, *aptes = NULL; legacy_mbr *legacymbr; u64 lastlba; if (!ptes) return 0; lastlba = last_lba(state->bdev); #if 0 // merged from msm8960-gb by ZTE_BOOT_JIA_20120105 jia.jia if (!force_gpt) { #else if (force_gpt) { #endif /* This will be added to the EFI Spec. per Intel after v1.02. */ legacymbr = kzalloc(sizeof (*legacymbr), GFP_KERNEL); if (legacymbr) { read_lba(state, 0, (u8 *) legacymbr, sizeof (*legacymbr)); good_pmbr = is_pmbr_valid(legacymbr); kfree(legacymbr); } if (!good_pmbr) goto fail; } good_pgpt = is_gpt_valid(state, GPT_PRIMARY_PARTITION_TABLE_LBA, &pgpt, &pptes); if (good_pgpt) good_agpt = is_gpt_valid(state, le64_to_cpu(pgpt->alternate_lba), &agpt, &aptes); if (!good_agpt && force_gpt) good_agpt = is_gpt_valid(state, lastlba, &agpt, &aptes); /* The obviously unsuccessful case */ if (!good_pgpt && !good_agpt) goto fail; compare_gpts(pgpt, agpt, lastlba); /* The good cases */ if (good_pgpt) { *gpt = pgpt; *ptes = pptes; kfree(agpt); kfree(aptes); if (!good_agpt) { printk(KERN_WARNING "Alternate GPT is invalid, " "using primary GPT.\n"); } return 1; } else if (good_agpt) { *gpt = agpt; *ptes = aptes; kfree(pgpt); kfree(pptes); printk(KERN_WARNING "Primary GPT is invalid, using alternate GPT.\n"); return 1; } fail: kfree(pgpt); kfree(agpt); kfree(pptes); kfree(aptes); *gpt = NULL; *ptes = NULL; return 0; } /** * efi_partition(struct parsed_partitions *state) * @state * * Description: called from check.c, if the disk contains GPT * partitions, sets up partition entries in the kernel. * * If the first block on the disk is a legacy MBR, * it will get handled by msdos_partition(). * If it's a Protective MBR, we'll handle it here. * * We do not create a Linux partition for GPT, but * only for the actual data partitions. * Returns: * -1 if unable to read the partition table * 0 if this isn't our partition table * 1 if successful * */ int efi_partition(struct parsed_partitions *state) { gpt_header *gpt = NULL; gpt_entry *ptes = NULL; u32 i; unsigned ssz = bdev_logical_block_size(state->bdev) / 512; u8 unparsed_guid[37]; if (!find_valid_gpt(state, &gpt, &ptes) || !gpt || !ptes) { kfree(gpt); kfree(ptes); return 0; } pr_debug("GUID Partition Table is valid! Yea!\n"); for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < state->limit-1; i++) { struct partition_meta_info *info; unsigned label_count = 0; unsigned label_max; u64 start = le64_to_cpu(ptes[i].starting_lba); u64 size = le64_to_cpu(ptes[i].ending_lba) - le64_to_cpu(ptes[i].starting_lba) + 1ULL; if (!is_pte_valid(&ptes[i], last_lba(state->bdev))) continue; put_partition(state, i+1, start * ssz, size * ssz); /* If this is a RAID volume, tell md */ if (!efi_guidcmp(ptes[i].partition_type_guid, PARTITION_LINUX_RAID_GUID)) state->parts[i + 1].flags = ADDPART_FLAG_RAID; info = &state->parts[i + 1].info; /* Instead of doing a manual swap to big endian, reuse the * common ASCII hex format as the interim. */ efi_guid_unparse(&ptes[i].unique_partition_guid, unparsed_guid); part_pack_uuid(unparsed_guid, info->uuid); /* Naively convert UTF16-LE to 7 bits. */ label_max = min(sizeof(info->volname) - 1, sizeof(ptes[i].partition_name)); info->volname[label_max] = 0; while (label_count < label_max) { u8 c = ptes[i].partition_name[label_count] & 0xff; if (c && !isprint(c)) c = '!'; info->volname[label_count] = c; label_count++; } state->parts[i + 1].has_info = true; } kfree(ptes); kfree(gpt); strlcat(state->pp_buf, "\n", PAGE_SIZE); return 1; }
/** * find_valid_gpt() - Search disk for valid GPT headers and PTEs * @state * @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 newly allocated GPT header and PTEs. * Validity depends on PMBR being valid (or being overridden by the * 'gpt' kernel command line option) and finding either the Primary * GPT header and PTEs valid, or the Alternate GPT header and PTEs * valid. If the Primary GPT header is not valid, the Alternate GPT header * is not checked unless the 'gpt' kernel command line option is passed. * This protects against devices which misreport their size, and forces * the user to decide to use the Alternate GPT. */ static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt, gpt_entry **ptes) { int good_pgpt = 0, good_agpt = 0, good_pmbr = 0; gpt_header *pgpt = NULL, *agpt = NULL; gpt_entry *pptes = NULL, *aptes = NULL; legacy_mbr *legacymbr; u64 lastlba; char *blk_name = NULL; blk_name = ((state->bdev)->bd_disk)->disk_name; printk(KERN_NOTICE "%s: %s", __func__, blk_name); if (!ptes) return 0; lastlba = last_lba(state->bdev); if ((!force_gpt) || (!strcmp(blk_name, "mmcblk1"))) { /* This will be added to the EFI Spec. per Intel after v1.02. */ legacymbr = kzalloc(sizeof (*legacymbr), GFP_KERNEL); if (legacymbr) { read_lba(state, 0, (u8 *) legacymbr, sizeof (*legacymbr)); good_pmbr = is_pmbr_valid(legacymbr); kfree(legacymbr); } if (!good_pmbr) goto fail; } good_pgpt = is_gpt_valid(state, GPT_PRIMARY_PARTITION_TABLE_LBA, &pgpt, &pptes); if (good_pgpt) good_agpt = is_gpt_valid(state, le64_to_cpu(pgpt->alternate_lba), &agpt, &aptes); if (!good_agpt && force_gpt) good_agpt = is_gpt_valid(state, lastlba, &agpt, &aptes); /* The obviously unsuccessful case */ if (!good_pgpt && !good_agpt) goto fail; compare_gpts(pgpt, agpt, lastlba); /* The good cases */ if (good_pgpt) { *gpt = pgpt; *ptes = pptes; kfree(agpt); kfree(aptes); if (!good_agpt) { printk(KERN_WARNING "Alternate GPT is invalid, " "using primary GPT.\n"); } return 1; } else if (good_agpt) { *gpt = agpt; *ptes = aptes; kfree(pgpt); kfree(pptes); printk(KERN_WARNING "Primary GPT is invalid, using alternate GPT.\n"); return 1; } fail: kfree(pgpt); kfree(agpt); kfree(pptes); kfree(aptes); *gpt = NULL; *ptes = NULL; return 0; }
/** * find_valid_gpt() - Search disk for valid GPT headers and PTEs * @fd is an open file descriptor to the whole disk * @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 newly allocated GPT header and PTEs. * Validity depends on finding either the Primary GPT header and PTEs valid, * or the Alternate GPT header and PTEs valid, and the PMBR valid. */ static int find_valid_gpt(int fd, gpt_header ** gpt, gpt_entry ** ptes, int ignore_pmbr_err) { int good_pgpt = 0, good_agpt = 0, good_pmbr = 0; gpt_header *pgpt = NULL, *agpt = NULL; gpt_entry *pptes = NULL, *aptes = NULL; legacy_mbr *legacymbr = NULL; uint64_t lastlba; int ret = -1; errno = EINVAL; if (!gpt || !ptes) return -1; lastlba = last_lba(fd); good_pgpt = is_gpt_valid(fd, GPT_PRIMARY_PARTITION_TABLE_LBA, &pgpt, &pptes); if (good_pgpt) { good_agpt = is_gpt_valid(fd, __le64_to_cpu(pgpt->alternate_lba), &agpt, &aptes); if (!good_agpt) { good_agpt = is_gpt_valid(fd, lastlba, &agpt, &aptes); } } else { good_agpt = is_gpt_valid(fd, lastlba, &agpt, &aptes); } /* The obviously unsuccessful case */ if (!good_pgpt && !good_agpt) { goto fail; } /* This will be added to the EFI Spec. per Intel after v1.02. */ legacymbr = malloc(sizeof (*legacymbr)); if (legacymbr) { memset(legacymbr, 0, sizeof (*legacymbr)); read_lba(fd, 0, (uint8_t *) legacymbr, sizeof (*legacymbr)); good_pmbr = is_pmbr_valid(legacymbr); free(legacymbr); legacymbr=NULL; } /* Failure due to bad PMBR */ if ((good_pgpt || good_agpt) && !good_pmbr && !ignore_pmbr_err) { if (report_errors) fprintf(stderr, "Primary GPT is invalid, using alternate GPT.\n"); goto fail; } /* Would fail due to bad PMBR, but force GPT anyhow */ if ((good_pgpt || good_agpt) && !good_pmbr && ignore_pmbr_err && report_errors) { fprintf(stderr, " Warning: Disk has a valid GPT signature but invalid PMBR.\n" " Use GNU Parted to correct disk.\n" " gpt option taken, disk treated as GPT.\n"); } compare_gpts(pgpt, agpt, lastlba); /* The good cases */ if (good_pgpt && (good_pmbr || ignore_pmbr_err)) { *gpt = pgpt; *ptes = pptes; } else if (good_agpt && (good_pmbr || ignore_pmbr_err)) { *gpt = agpt; *ptes = aptes; } ret = 0; errno = 0; fail: if (pgpt && (pgpt != *gpt || ret < 0)) { free(pgpt); pgpt=NULL; } if (pptes && (pptes != *ptes || ret < 0)) { free(pptes); pptes=NULL; } if (agpt && (agpt != *gpt || ret < 0)) { free(agpt); agpt=NULL; } if (aptes && (aptes != *ptes || ret < 0)) { free(aptes); aptes=NULL; } if (ret < 0) { *gpt = NULL; *ptes = NULL; } return ret; }