static int unparse_media_hard_drive_path(char *buffer, EFI_DEVICE_PATH *path) { HARDDRIVE_DEVICE_PATH *hd = (HARDDRIVE_DEVICE_PATH *)path; char text_uuid[40], *sig=text_uuid; char a[16], b[16], c[16]; switch (hd->signature_type) { case 0x00: sprintf(sig, "None"); break; case 0x01: sprintf(sig, "%08x", *(uint32_t *)memcpy(a, &hd->signature, sizeof(hd->signature))); break; case 0x02: /* GPT */ efi_guid_unparse((efi_guid_t *)hd->signature, sig); break; default: break; } return sprintf(buffer, "HD(%x,%" PRIx64 ",%" PRIx64 ",%s)", get(a, hd->part_num), get(b, hd->start), get(c, hd->size), sig); }
/** * 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; }
static void fill_bootvar_name(char *dest, size_t len, const char *name) { efi_guid_t guid = EFI_GLOBAL_VARIABLE; char text_uuid[40]; efi_guid_unparse(&guid, text_uuid); snprintf(dest, len, "%s-%s", name, text_uuid); }
static int unparse_vendor_path(char *buffer, VENDOR_DEVICE_PATH *path) { char text_guid[40], *p = buffer; unsigned char *q = (uint8_t *)path + 20; efi_guid_unparse(&path->vendor_guid, text_guid); p += sprintf(p, "Vendor(%s,", text_guid); p += unparse_raw(p, q, path->length - 20); p += sprintf(p, ")"); return p - buffer; }
static ssize_t efivar_guid_read(struct efivar_entry *entry, char *buf) { struct efi_variable *var = &entry->var; char *str = buf; if (!entry || !buf) return 0; efi_guid_unparse(&var->VendorGuid, str); str += strlen(str); str += sprintf(str, "\n"); return str - buf; }
/** * efivar_create_sysfs_entry - create a new entry in sysfs * @new_var: efivar entry to create * * Returns 1 on failure, 0 on success */ static int efivar_create_sysfs_entry(struct efivar_entry *new_var) { int i, short_name_size; char *short_name; unsigned long variable_name_size; efi_char16_t *variable_name; variable_name = new_var->var.VariableName; variable_name_size = ucs2_strlen(variable_name) * sizeof(efi_char16_t); /* * Length of the variable bytes in ASCII, plus the '-' separator, * plus the GUID, plus trailing NUL */ short_name_size = variable_name_size / sizeof(efi_char16_t) + 1 + EFI_VARIABLE_GUID_LEN + 1; short_name = kzalloc(short_name_size, GFP_KERNEL); if (!short_name) return 1; /* Convert Unicode to normal chars (assume top bits are 0), ala UTF-8 */ for (i=0; i < (int)(variable_name_size / sizeof(efi_char16_t)); i++) { short_name[i] = variable_name[i] & 0xFF; } /* This is ugly, but necessary to separate one vendor's private variables from another's. */ *(short_name + strlen(short_name)) = '-'; efi_guid_unparse(&new_var->var.VendorGuid, short_name + strlen(short_name)); new_var->kobj.kset = efivars_kset; i = kobject_init_and_add(&new_var->kobj, &efivar_ktype, NULL, "%s", short_name); kfree(short_name); if (i) return 1; kobject_uevent(&new_var->kobj, KOBJ_ADD); efivar_entry_add(new_var, &efivar_sysfs_list); return 0; }
static int unparse_media_path(char *buffer, EFI_DEVICE_PATH *path) { CDROM_DEVICE_PATH *cdrom = (CDROM_DEVICE_PATH *)path; MEDIA_PROTOCOL_DEVICE_PATH *media = (MEDIA_PROTOCOL_DEVICE_PATH *)path; FILE_PATH_DEVICE_PATH *file = (FILE_PATH_DEVICE_PATH *)path; char text_guid[40], *p = buffer; char file_name[80]; memset(file_name, 0, sizeof(file_name)); char a[16], b[16], c[16]; switch (path->subtype) { case 1: return unparse_media_hard_drive_path(buffer, path); break; case 2: return sprintf(buffer, "CD-ROM(%x,%" PRIx64 ",%" PRIx64 ")", get(a, cdrom->boot_entry), get(b, cdrom->start), get(c, cdrom->size)); break; case 3: return unparse_vendor_path(buffer, (VENDOR_DEVICE_PATH *)path); break; case 4: efichar_to_char(file_name, file->path_name, 80); return sprintf(p, "File(%s)", file_name); break; case 5: efi_guid_unparse(&media->guid, text_guid); return sprintf(buffer, "Media(%s)", text_guid); break; default: break; } 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; }
static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, unsigned long name_size, void *data) { struct super_block *sb = (struct super_block *)data; struct efivar_entry *entry; struct inode *inode = NULL; struct dentry *dentry, *root = sb->s_root; unsigned long size = 0; char *name; int len; int err = -ENOMEM; bool is_removable = false; entry = kmalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return err; memcpy(entry->var.VariableName, name16, name_size); memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t)); len = ucs2_utf8size(entry->var.VariableName); /* name, plus '-', plus GUID, plus NUL*/ name = kmalloc(len + 1 + EFI_VARIABLE_GUID_LEN + 1, GFP_KERNEL); if (!name) goto fail; ucs2_as_utf8(name, entry->var.VariableName, len); if (efivar_variable_is_removable(entry->var.VendorGuid, name, len)) is_removable = true; name[len] = '-'; efi_guid_unparse(&entry->var.VendorGuid, name + len + 1); name[len + EFI_VARIABLE_GUID_LEN+1] = '\0'; inode = efivarfs_get_inode(sb, root->d_inode, S_IFREG | 0644, 0, is_removable); if (!inode) goto fail_name; dentry = efivarfs_alloc_dentry(root, name); if (IS_ERR(dentry)) { err = PTR_ERR(dentry); goto fail_inode; } /* copied by the above to local storage in the dentry. */ kfree(name); efivar_entry_size(entry, &size); efivar_entry_add(entry, &efivarfs_list); mutex_lock(&inode->i_mutex); inode->i_private = entry; i_size_write(inode, size + sizeof(entry->var.Attributes)); mutex_unlock(&inode->i_mutex); d_add(dentry, inode); return 0; fail_inode: iput(inode); fail_name: kfree(name); fail: kfree(entry); return err; }
/** * 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) { char* partition_name = NULL; gpt_header *gpt = NULL; gpt_entry *ptes = NULL; u32 i; unsigned ssz = bdev_logical_block_size(state->bdev) / 512; partition_name = kzalloc(sizeof(ptes->partition_name), GFP_KERNEL); if (!partition_name) return 0; if (!find_valid_gpt(state, &gpt, &ptes) || !gpt || !ptes) { kfree(gpt); kfree(ptes); kfree(partition_name); return 0; } pr_debug("GUID Partition Table is valid! Yea!\n"); proc_create("emmc", 0666, NULL, &emmc_partition_fops); gpt_info.num_of_partitions = le32_to_cpu(gpt->num_partition_entries); gpt_info.erase_size = bdev_erase_size(state->bdev) * ssz; /* * Not certain if there is a chance this function is called again with * a different GPT. In case there is, free previously allocated memory */ kfree(gpt_info.partitions); gpt_info.partitions = kzalloc(gpt_info.num_of_partitions * sizeof(*gpt_info.partitions), GFP_KERNEL); for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < state->limit-1; i++) { int partition_name_len; 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; gpt_info.partitions[i].size = size * ssz; if (!is_pte_valid(&ptes[i], last_lba(state->bdev))) continue; partition_name_len = utf16s_to_utf8s(ptes[i].partition_name, sizeof(ptes[i].partition_name), UTF16_LITTLE_ENDIAN, partition_name, sizeof(ptes[i].partition_name)); #ifdef CONFIG_APANIC_ON_MMC if(strncmp(partition_name,CONFIG_APANIC_PLABEL,partition_name_len) == 0) { apanic_partition_start = start * ssz; apanic_partition_size = size * ssz; pr_debug("apanic partition found starts at %lu \r\n", apanic_partition_start); pr_debug("apanic partition size = %lu\n", apanic_partition_size); } #endif 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; efi_guid_unparse(&ptes[i].unique_partition_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; if (label_count <= partition_name_len) gpt_info.partitions[i].volname[label_count] = c; label_count++; } state->parts[i + 1].has_info = true; #ifdef CONFIG_APANIC_ON_MMC if(strncmp(info->volname,CONFIG_APANIC_PLABEL,label_count) == 0) { apanic_partition_start = start * ssz; pr_debug("apanic partition found starts at %lu \r\n", apanic_partition_start); } #endif } kfree(ptes); kfree(gpt); kfree(partition_name); strlcat(state->pp_buf, "\n", PAGE_SIZE); return 1; }
/** * efi_partition(struct parsed_partitions *state, struct block_device *bdev) * @state * @bdev * * 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, struct block_device *bdev) { gpt_header *gpt = NULL; gpt_entry *ptes = NULL; u32 i; unsigned ssz = bdev_logical_block_size(bdev) / 512; u8 unparsed_guid[37]; if (!find_valid_gpt(bdev, &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(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 = 1; info = &state->parts[i + 1].info; /* The EFI specification diverges from RFC 4122 with respect to * the packed storage of its UUIDs. efi_guid_unparse unpacks to * a common ASCII representation, which allows part_pack_uuid to * pack it in the standard big endian layout for use by the rest * of the kernel. */ 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); printk("\n"); return 1; }