image: extend FIT partition parser for use on eMMC/SDcard
Introduce a magic GUID_PARTITION_LINUX_FIT_GUID to designate a GPT partition to be interpreted by the FIT partition parser. In that way, sub-partitions for (external-data) uImage.FIT stored directly in a partition can be split, similar like we do for devices with raw flash storage. Signed-off-by: Daniel Golle <daniel@makrotopia.org>
This commit is contained in:
		| @@ -67,17 +67,20 @@ | |||||||
|  |  | ||||||
| #define FIT_MAX_HASH_LEN	HASH_MAX_DIGEST_SIZE | #define FIT_MAX_HASH_LEN	HASH_MAX_DIGEST_SIZE | ||||||
|  |  | ||||||
| int fit_partition(struct parsed_partitions *state) | #define MIN_FREE_SECT		16 | ||||||
|  | #define REMAIN_VOLNAME		"rootfs_data" | ||||||
|  |  | ||||||
|  | int parse_fit_partitions(struct parsed_partitions *state, u64 fit_start_sector, u64 sectors, int *slot, int add_remain) | ||||||
| { | { | ||||||
| 	struct address_space *mapping = state->bdev->bd_inode->i_mapping; | 	struct address_space *mapping = state->bdev->bd_inode->i_mapping; | ||||||
| 	struct page *page = read_mapping_page(mapping, 0, NULL); | 	struct page *page; | ||||||
| 	void *fit, *init_fit; | 	void *fit, *init_fit; | ||||||
| 	struct partition_meta_info *info; | 	struct partition_meta_info *info; | ||||||
| 	char tmp[sizeof(info->volname)]; | 	char tmp[sizeof(info->volname)]; | ||||||
| 	u64 dsize, dsectors; | 	u64 dsize, dsectors, imgmaxsect = 0; | ||||||
| 	u32 size, image_pos, image_len; | 	u32 size, image_pos, image_len; | ||||||
| 	const u32 *image_offset_be, *image_len_be, *image_pos_be; | 	const u32 *image_offset_be, *image_len_be, *image_pos_be; | ||||||
| 	int ret = 1, node, images, config, slot; | 	int ret = 1, node, images, config; | ||||||
| 	const char *image_name, *image_type, *image_description, *config_default, | 	const char *image_name, *image_type, *image_description, *config_default, | ||||||
| 		*config_description, *config_loadables; | 		*config_description, *config_loadables; | ||||||
| 	int image_name_len, image_type_len, image_description_len, config_default_len, | 	int image_name_len, image_type_len, image_description_len, config_default_len, | ||||||
| @@ -85,6 +88,10 @@ int fit_partition(struct parsed_partitions *state) | |||||||
| 	sector_t start_sect, nr_sects; | 	sector_t start_sect, nr_sects; | ||||||
| 	size_t label_min; | 	size_t label_min; | ||||||
|  |  | ||||||
|  | 	if (fit_start_sector % (1<<(PAGE_SHIFT - SECTOR_SHIFT))) | ||||||
|  | 		return -ERANGE; | ||||||
|  |  | ||||||
|  | 	page = read_mapping_page(mapping, fit_start_sector >> (PAGE_SHIFT - SECTOR_SHIFT), NULL); | ||||||
| 	if (!page) | 	if (!page) | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
|  |  | ||||||
| @@ -101,6 +108,9 @@ int fit_partition(struct parsed_partitions *state) | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	dsectors = get_capacity(state->bdev->bd_disk); | 	dsectors = get_capacity(state->bdev->bd_disk); | ||||||
|  | 	if (sectors) | ||||||
|  | 		dsectors = (dsectors>sectors)?sectors:dsectors; | ||||||
|  |  | ||||||
| 	dsize = dsectors << SECTOR_SHIFT; | 	dsize = dsectors << SECTOR_SHIFT; | ||||||
| 	printk(KERN_DEBUG "FIT: volume size: %llu sectors (%llu bytes)\n", dsectors, dsize); | 	printk(KERN_DEBUG "FIT: volume size: %llu sectors (%llu bytes)\n", dsectors, dsize); | ||||||
|  |  | ||||||
| @@ -158,7 +168,6 @@ int fit_partition(struct parsed_partitions *state) | |||||||
| 		goto ret_out; | 		goto ret_out; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	slot = 1; |  | ||||||
| 	fdt_for_each_subnode(node, fit, images) { | 	fdt_for_each_subnode(node, fit, images) { | ||||||
| 		image_name = fdt_get_name(fit, node, &image_name_len); | 		image_name = fdt_get_name(fit, node, &image_name_len); | ||||||
| 		image_type = fdt_getprop(fit, node, FIT_TYPE_PROP, &image_type_len); | 		image_type = fdt_getprop(fit, node, FIT_TYPE_PROP, &image_type_len); | ||||||
| @@ -200,15 +209,16 @@ int fit_partition(struct parsed_partitions *state) | |||||||
|  |  | ||||||
| 		start_sect = image_pos >> SECTOR_SHIFT; | 		start_sect = image_pos >> SECTOR_SHIFT; | ||||||
| 		nr_sects = image_len >> SECTOR_SHIFT; | 		nr_sects = image_len >> SECTOR_SHIFT; | ||||||
|  | 		imgmaxsect = (imgmaxsect < (start_sect + nr_sects))?(start_sect + nr_sects):imgmaxsect; | ||||||
|  |  | ||||||
| 		if (start_sect + nr_sects > dsectors) { | 		if (start_sect + nr_sects > dsectors) { | ||||||
| 			state->access_beyond_eod = 1; | 			state->access_beyond_eod = 1; | ||||||
| 			continue; | 			continue; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		put_partition(state, slot, start_sect, nr_sects); | 		put_partition(state, ++(*slot), fit_start_sector + start_sect, nr_sects); | ||||||
| 		state->parts[slot].flags = 0; | 		state->parts[*slot].flags = 0; | ||||||
| 		info = &state->parts[slot].info; | 		info = &state->parts[*slot].info; | ||||||
|  |  | ||||||
| 		label_min = min_t(int, sizeof(info->volname) - 1, image_name_len); | 		label_min = min_t(int, sizeof(info->volname) - 1, image_name_len); | ||||||
| 		strncpy(info->volname, image_name, label_min); | 		strncpy(info->volname, image_name, label_min); | ||||||
| @@ -217,17 +227,28 @@ int fit_partition(struct parsed_partitions *state) | |||||||
| 		snprintf(tmp, sizeof(tmp), "(%s)", info->volname); | 		snprintf(tmp, sizeof(tmp), "(%s)", info->volname); | ||||||
| 		strlcat(state->pp_buf, tmp, PAGE_SIZE); | 		strlcat(state->pp_buf, tmp, PAGE_SIZE); | ||||||
|  |  | ||||||
| 		state->parts[slot].has_info = true; | 		state->parts[*slot].has_info = true; | ||||||
|  |  | ||||||
| 		if (config_loadables && !strcmp(image_name, config_loadables)) { | 		if (config_loadables && !strcmp(image_name, config_loadables)) { | ||||||
| 			printk(KERN_DEBUG "FIT: selecting configured loadable %s to be root filesystem\n", image_name); | 			printk(KERN_DEBUG "FIT: selecting configured loadable %s to be root filesystem\n", image_name); | ||||||
| 			state->parts[slot].flags |= ADDPART_FLAG_ROOTDEV; | 			state->parts[*slot].flags |= ADDPART_FLAG_ROOTDEV; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		++slot; |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	if (add_remain && (imgmaxsect + MIN_FREE_SECT) < dsectors) { | ||||||
|  | 		put_partition(state, ++(*slot), fit_start_sector + imgmaxsect, dsectors - imgmaxsect); | ||||||
|  | 		state->parts[*slot].flags = 0; | ||||||
|  | 		info = &state->parts[*slot].info; | ||||||
|  | 		strcpy(info->volname, REMAIN_VOLNAME); | ||||||
|  | 		snprintf(tmp, sizeof(tmp), "(%s)", REMAIN_VOLNAME); | ||||||
|  | 		strlcat(state->pp_buf, tmp, PAGE_SIZE); | ||||||
|  | 	} | ||||||
| ret_out: | ret_out: | ||||||
| 	kfree(fit); | 	kfree(fit); | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | int fit_partition(struct parsed_partitions *state) { | ||||||
|  | 	int slot = 0; | ||||||
|  | 	return parse_fit_partitions(state, 0, 0, &slot, 0); | ||||||
|  | } | ||||||
|   | |||||||
| @@ -44,18 +44,26 @@ | |||||||
|  int ibm_partition(struct parsed_partitions *); |  int ibm_partition(struct parsed_partitions *); | ||||||
|  int karma_partition(struct parsed_partitions *state); |  int karma_partition(struct parsed_partitions *state); | ||||||
|  int ldm_partition(struct parsed_partitions *state); |  int ldm_partition(struct parsed_partitions *state); | ||||||
|  | @@ -68,3 +69,5 @@ int sgi_partition(struct parsed_partitio | ||||||
|  |  int sun_partition(struct parsed_partitions *state); | ||||||
|  |  int sysv68_partition(struct parsed_partitions *state); | ||||||
|  |  int ultrix_partition(struct parsed_partitions *state); | ||||||
|  | + | ||||||
|  | +int parse_fit_partitions(struct parsed_partitions *state, u64 start_sector, u64 nr_sectors, int *slot, int add_remain); | ||||||
| --- a/block/partitions/core.c | --- a/block/partitions/core.c | ||||||
| +++ b/block/partitions/core.c | +++ b/block/partitions/core.c | ||||||
| @@ -10,6 +10,8 @@ | @@ -10,6 +10,10 @@ | ||||||
|  #include <linux/vmalloc.h> |  #include <linux/vmalloc.h> | ||||||
|  #include <linux/blktrace_api.h> |  #include <linux/blktrace_api.h> | ||||||
|  #include <linux/raid/detect.h> |  #include <linux/raid/detect.h> | ||||||
|  | +#ifdef CONFIG_FIT_PARTITION | ||||||
| +#include <linux/root_dev.h> | +#include <linux/root_dev.h> | ||||||
|  | +#endif | ||||||
| + | + | ||||||
|  #include "check.h" |  #include "check.h" | ||||||
|   |   | ||||||
|  static int (*check_part[])(struct parsed_partitions *) = { |  static int (*check_part[])(struct parsed_partitions *) = { | ||||||
| @@ -46,6 +48,9 @@ static int (*check_part[])(struct parsed | @@ -46,6 +50,9 @@ static int (*check_part[])(struct parsed | ||||||
|  #ifdef CONFIG_EFI_PARTITION |  #ifdef CONFIG_EFI_PARTITION | ||||||
|  	efi_partition,		/* this must come before msdos */ |  	efi_partition,		/* this must come before msdos */ | ||||||
|  #endif |  #endif | ||||||
| @@ -65,12 +73,49 @@ | |||||||
|  #ifdef CONFIG_SGI_PARTITION |  #ifdef CONFIG_SGI_PARTITION | ||||||
|  	sgi_partition, |  	sgi_partition, | ||||||
|  #endif |  #endif | ||||||
| @@ -694,6 +699,9 @@ static bool blk_add_partition(struct gen | @@ -215,6 +222,18 @@ static ssize_t part_discard_alignment_sh | ||||||
|  |  				p->start_sect)); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +static ssize_t part_name_show(struct device *dev, | ||||||
|  | +			      struct device_attribute *attr, char *buf) | ||||||
|  | +{ | ||||||
|  | +	struct hd_struct *p = dev_to_part(dev); | ||||||
|  | + | ||||||
|  | +	if (p->info && p->info->volname) | ||||||
|  | +		return sprintf(buf, "%s\n", p->info->volname); | ||||||
|  | + | ||||||
|  | +	buf[0] = '\0'; | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  |  static DEVICE_ATTR(partition, 0444, part_partition_show, NULL); | ||||||
|  |  static DEVICE_ATTR(start, 0444, part_start_show, NULL); | ||||||
|  |  static DEVICE_ATTR(size, 0444, part_size_show, NULL); | ||||||
|  | @@ -223,6 +242,7 @@ static DEVICE_ATTR(alignment_offset, 044 | ||||||
|  |  static DEVICE_ATTR(discard_alignment, 0444, part_discard_alignment_show, NULL); | ||||||
|  |  static DEVICE_ATTR(stat, 0444, part_stat_show, NULL); | ||||||
|  |  static DEVICE_ATTR(inflight, 0444, part_inflight_show, NULL); | ||||||
|  | +static DEVICE_ATTR(name, 0444, part_name_show, NULL); | ||||||
|  |  #ifdef CONFIG_FAIL_MAKE_REQUEST | ||||||
|  |  static struct device_attribute dev_attr_fail = | ||||||
|  |  	__ATTR(make-it-fail, 0644, part_fail_show, part_fail_store); | ||||||
|  | @@ -237,6 +257,7 @@ static struct attribute *part_attrs[] = | ||||||
|  |  	&dev_attr_discard_alignment.attr, | ||||||
|  |  	&dev_attr_stat.attr, | ||||||
|  |  	&dev_attr_inflight.attr, | ||||||
|  | +	&dev_attr_name.attr, | ||||||
|  |  #ifdef CONFIG_FAIL_MAKE_REQUEST | ||||||
|  |  	&dev_attr_fail.attr, | ||||||
|  |  #endif | ||||||
|  | @@ -694,6 +715,11 @@ static bool blk_add_partition(struct gen | ||||||
|  	    (state->parts[p].flags & ADDPART_FLAG_RAID)) |  	    (state->parts[p].flags & ADDPART_FLAG_RAID)) | ||||||
|  		md_autodetect_dev(part_to_dev(part)->devt); |  		md_autodetect_dev(part_to_dev(part)->devt); | ||||||
|   |   | ||||||
|  | +#ifdef CONFIG_FIT_PARTITION | ||||||
| +	if ((state->parts[p].flags & ADDPART_FLAG_ROOTDEV) && ROOT_DEV == 0) | +	if ((state->parts[p].flags & ADDPART_FLAG_ROOTDEV) && ROOT_DEV == 0) | ||||||
| +		ROOT_DEV = part_to_dev(part)->devt; | +		ROOT_DEV = part_to_dev(part)->devt; | ||||||
|  | +#endif | ||||||
| + | + | ||||||
|  	return true; |  	return true; | ||||||
|  } |  } | ||||||
| @@ -94,3 +139,62 @@ | |||||||
|  	sprintf(gd->disk_name, "ubiblock%d_%d", dev->ubi_num, dev->vol_id); |  	sprintf(gd->disk_name, "ubiblock%d_%d", dev->ubi_num, dev->vol_id); | ||||||
|  	set_capacity(gd, disk_capacity); |  	set_capacity(gd, disk_capacity); | ||||||
|  	dev->gd = gd; |  	dev->gd = gd; | ||||||
|  | --- a/block/partitions/efi.c | ||||||
|  | +++ b/block/partitions/efi.c | ||||||
|  | @@ -704,7 +704,7 @@ int efi_partition(struct parsed_partitio | ||||||
|  |  { | ||||||
|  |  	gpt_header *gpt = NULL; | ||||||
|  |  	gpt_entry *ptes = NULL; | ||||||
|  | -	u32 i; | ||||||
|  | +	u32 i, slot = 0; | ||||||
|  |  	unsigned ssz = bdev_logical_block_size(state->bdev) / 512; | ||||||
|  |   | ||||||
|  |  	if (!find_valid_gpt(state, &gpt, &ptes) || !gpt || !ptes) { | ||||||
|  | @@ -722,23 +722,30 @@ int efi_partition(struct parsed_partitio | ||||||
|  |  		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))) | ||||||
|  | +		if (!is_pte_valid(&ptes[i], last_lba(state->bdev))) { | ||||||
|  | +			++slot; | ||||||
|  |  			continue; | ||||||
|  | +		} | ||||||
|  |   | ||||||
|  | -		put_partition(state, i+1, start * ssz, size * ssz); | ||||||
|  | +		put_partition(state, ++slot, 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; | ||||||
|  | +			state->parts[slot].flags = ADDPART_FLAG_RAID; | ||||||
|  |   | ||||||
|  | -		info = &state->parts[i + 1].info; | ||||||
|  | +		info = &state->parts[slot].info; | ||||||
|  |  		efi_guid_to_str(&ptes[i].unique_partition_guid, info->uuid); | ||||||
|  |   | ||||||
|  |  		/* Naively convert UTF16-LE to 7 bits. */ | ||||||
|  |  		label_max = min(ARRAY_SIZE(info->volname) - 1, | ||||||
|  |  				ARRAY_SIZE(ptes[i].partition_name)); | ||||||
|  |  		utf16_le_to_7bit(ptes[i].partition_name, label_max, info->volname); | ||||||
|  | -		state->parts[i + 1].has_info = true; | ||||||
|  | +		state->parts[slot].has_info = true; | ||||||
|  | +#ifdef CONFIG_FIT_PARTITION | ||||||
|  | +		/* If this is a U-Boot FIT volume it may have subpartitions */ | ||||||
|  | +		if (!efi_guidcmp(ptes[i].partition_type_guid, PARTITION_LINUX_FIT_GUID)) | ||||||
|  | +			(void) parse_fit_partitions(state, start * ssz, size * ssz, &slot, 1); | ||||||
|  | +#endif | ||||||
|  |  	} | ||||||
|  |  	kfree(ptes); | ||||||
|  |  	kfree(gpt); | ||||||
|  | --- a/block/partitions/efi.h | ||||||
|  | +++ b/block/partitions/efi.h | ||||||
|  | @@ -52,6 +52,9 @@ | ||||||
|  |  #define PARTITION_LINUX_LVM_GUID \ | ||||||
|  |      EFI_GUID( 0xe6d6d379, 0xf507, 0x44c2, \ | ||||||
|  |                0xa2, 0x3c, 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28) | ||||||
|  | +#define PARTITION_LINUX_FIT_GUID \ | ||||||
|  | +    EFI_GUID( 0xcae9be83, 0xb15f, 0x49cc, \ | ||||||
|  | +              0x86, 0x3f, 0x08, 0x1b, 0x74, 0x4a, 0x2d, 0x93) | ||||||
|  |   | ||||||
|  |  typedef struct _gpt_header { | ||||||
|  |  	__le64 signature; | ||||||
|   | |||||||
| @@ -45,20 +45,60 @@ | |||||||
|  	dev->gd = gd; |  	dev->gd = gd; | ||||||
| --- a/block/partition-generic.c | --- a/block/partition-generic.c | ||||||
| +++ b/block/partition-generic.c | +++ b/block/partition-generic.c | ||||||
| @@ -18,6 +18,7 @@ | @@ -18,6 +18,10 @@ | ||||||
|  #include <linux/ctype.h> |  #include <linux/ctype.h> | ||||||
|  #include <linux/genhd.h> |  #include <linux/genhd.h> | ||||||
|  #include <linux/blktrace_api.h> |  #include <linux/blktrace_api.h> | ||||||
|  | +#ifdef CONFIG_FIT_PARTITION | ||||||
| +#include <linux/root_dev.h> | +#include <linux/root_dev.h> | ||||||
|  | +#endif | ||||||
|  | + | ||||||
|   |   | ||||||
|  #include "partitions/check.h" |  #include "partitions/check.h" | ||||||
|   |   | ||||||
| @@ -634,6 +635,8 @@ rescan: | @@ -180,6 +184,18 @@ ssize_t part_fail_store(struct device *d | ||||||
|  |  } | ||||||
|  |  #endif | ||||||
|  |   | ||||||
|  | +static ssize_t part_name_show(struct device *dev, | ||||||
|  | +			      struct device_attribute *attr, char *buf) | ||||||
|  | +{ | ||||||
|  | +	struct hd_struct *p = dev_to_part(dev); | ||||||
|  | + | ||||||
|  | +	if (p->info && p->info->volname) | ||||||
|  | +		return sprintf(buf, "%s\n", p->info->volname); | ||||||
|  | + | ||||||
|  | +	buf[0] = '\0'; | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  |  static DEVICE_ATTR(partition, 0444, part_partition_show, NULL); | ||||||
|  |  static DEVICE_ATTR(start, 0444, part_start_show, NULL); | ||||||
|  |  static DEVICE_ATTR(size, 0444, part_size_show, NULL); | ||||||
|  | @@ -188,6 +204,7 @@ static DEVICE_ATTR(alignment_offset, 044 | ||||||
|  |  static DEVICE_ATTR(discard_alignment, 0444, part_discard_alignment_show, NULL); | ||||||
|  |  static DEVICE_ATTR(stat, 0444, part_stat_show, NULL); | ||||||
|  |  static DEVICE_ATTR(inflight, 0444, part_inflight_show, NULL); | ||||||
|  | +static DEVICE_ATTR(name, 0444, part_name_show, NULL); | ||||||
|  |  #ifdef CONFIG_FAIL_MAKE_REQUEST | ||||||
|  |  static struct device_attribute dev_attr_fail = | ||||||
|  |  	__ATTR(make-it-fail, 0644, part_fail_show, part_fail_store); | ||||||
|  | @@ -202,6 +219,7 @@ static struct attribute *part_attrs[] = | ||||||
|  |  	&dev_attr_discard_alignment.attr, | ||||||
|  |  	&dev_attr_stat.attr, | ||||||
|  |  	&dev_attr_inflight.attr, | ||||||
|  | +	&dev_attr_name.attr, | ||||||
|  |  #ifdef CONFIG_FAIL_MAKE_REQUEST | ||||||
|  |  	&dev_attr_fail.attr, | ||||||
|  |  #endif | ||||||
|  | @@ -634,6 +652,10 @@ rescan: | ||||||
|  		if (state->parts[p].flags & ADDPART_FLAG_RAID) |  		if (state->parts[p].flags & ADDPART_FLAG_RAID) | ||||||
|  			md_autodetect_dev(part_to_dev(part)->devt); |  			md_autodetect_dev(part_to_dev(part)->devt); | ||||||
|  #endif |  #endif | ||||||
|  | +#ifdef CONFIG_FIT_PARTITION | ||||||
| +		if ((state->parts[p].flags & ADDPART_FLAG_ROOTDEV) && ROOT_DEV == 0) | +		if ((state->parts[p].flags & ADDPART_FLAG_ROOTDEV) && ROOT_DEV == 0) | ||||||
| +			ROOT_DEV = part_to_dev(part)->devt; | +			ROOT_DEV = part_to_dev(part)->devt; | ||||||
|  | +#endif | ||||||
|  	} |  	} | ||||||
|  	free_partitions(state); |  	free_partitions(state); | ||||||
|  	return 0; |  	return 0; | ||||||
| @@ -94,6 +134,67 @@ | |||||||
|  extern void blk_free_devt(dev_t devt); |  extern void blk_free_devt(dev_t devt); | ||||||
| --- /dev/null | --- /dev/null | ||||||
| +++ b/block/partitions/fit.h | +++ b/block/partitions/fit.h | ||||||
| @@ -0,0 +1,2 @@ | @@ -0,0 +1,3 @@ | ||||||
| +/* SPDX-License-Identifier: GPL-2.0 */ | +/* SPDX-License-Identifier: GPL-2.0-only */ | ||||||
| +int fit_partition(struct parsed_partitions *); | +int fit_partition(struct parsed_partitions *); | ||||||
|  | +int parse_fit_partitions(struct parsed_partitions *state, u64 start_sector, u64 nr_sectors, int *slot, int add_remain); | ||||||
|  | --- a/block/partitions/efi.c | ||||||
|  | +++ b/block/partitions/efi.c | ||||||
|  | @@ -679,7 +679,7 @@ int efi_partition(struct parsed_partitio | ||||||
|  |  { | ||||||
|  |  	gpt_header *gpt = NULL; | ||||||
|  |  	gpt_entry *ptes = NULL; | ||||||
|  | -	u32 i; | ||||||
|  | +	u32 i, slot = 0; | ||||||
|  |  	unsigned ssz = bdev_logical_block_size(state->bdev) / 512; | ||||||
|  |   | ||||||
|  |  	if (!find_valid_gpt(state, &gpt, &ptes) || !gpt || !ptes) { | ||||||
|  | @@ -698,16 +698,18 @@ int efi_partition(struct parsed_partitio | ||||||
|  |  		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))) | ||||||
|  | +		if (!is_pte_valid(&ptes[i], last_lba(state->bdev))) { | ||||||
|  | +			++slot; | ||||||
|  |  			continue; | ||||||
|  | +		} | ||||||
|  |   | ||||||
|  | -		put_partition(state, i+1, start * ssz, size * ssz); | ||||||
|  | +		put_partition(state, ++slot, 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; | ||||||
|  | +			state->parts[slot].flags = ADDPART_FLAG_RAID; | ||||||
|  |   | ||||||
|  | -		info = &state->parts[i + 1].info; | ||||||
|  | +		info = &state->parts[slot].info; | ||||||
|  |  		efi_guid_to_str(&ptes[i].unique_partition_guid, info->uuid); | ||||||
|  |   | ||||||
|  |  		/* Naively convert UTF16-LE to 7 bits. */ | ||||||
|  | @@ -721,7 +723,12 @@ int efi_partition(struct parsed_partitio | ||||||
|  |  			info->volname[label_count] = c; | ||||||
|  |  			label_count++; | ||||||
|  |  		} | ||||||
|  | -		state->parts[i + 1].has_info = true; | ||||||
|  | +		state->parts[slot].has_info = true; | ||||||
|  | +#ifdef CONFIG_FIT_PARTITION | ||||||
|  | +		/* If this is a U-Boot FIT volume it may have subpartitions */ | ||||||
|  | +		if (!efi_guidcmp(ptes[i].partition_type_guid, PARTITION_LINUX_FIT_GUID)) | ||||||
|  | +			(void) parse_fit_partitions(state, start * ssz, size * ssz, &slot, 1); | ||||||
|  | +#endif | ||||||
|  |  	} | ||||||
|  |  	kfree(ptes); | ||||||
|  |  	kfree(gpt); | ||||||
|  | --- a/block/partitions/efi.h | ||||||
|  | +++ b/block/partitions/efi.h | ||||||
|  | @@ -52,6 +52,9 @@ | ||||||
|  |  #define PARTITION_LINUX_LVM_GUID \ | ||||||
|  |      EFI_GUID( 0xe6d6d379, 0xf507, 0x44c2, \ | ||||||
|  |                0xa2, 0x3c, 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28) | ||||||
|  | +#define PARTITION_LINUX_FIT_GUID \ | ||||||
|  | +    EFI_GUID( 0xcae9be83, 0xb15f, 0x49cc, \ | ||||||
|  | +              0x86, 0x3f, 0x08, 0x1b, 0x74, 0x4a, 0x2d, 0x93) | ||||||
|  |   | ||||||
|  |  typedef struct _gpt_header { | ||||||
|  |  	__le64 signature; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Daniel Golle
					Daniel Golle