[PATCH 11/12] partitions: efi: implement partition manipulation support

Ahmad Fatoum a.fatoum at pengutronix.de
Wed Feb 28 09:36:06 PST 2024


Hello Sascha,

On 19.02.24 09:31, Sascha Hauer wrote:
>  		epart = xzalloc(sizeof(*epart));
> +		epart->pte = &ptes[i];
>  		pentry = &epart->part;
>  		pentry->first_sec = le64_to_cpu(ptes[i].starting_lba);
>  		pentry->size = le64_to_cpu(ptes[i].ending_lba) - pentry->first_sec;
> @@ -485,30 +504,262 @@ static struct partition_desc *efi_partition(void *buf, struct block_device *blk)
>  		part_set_efi_name(&ptes[i], pentry->name);
>  		snprintf(pentry->partuuid, sizeof(pentry->partuuid), "%pUl", &ptes[i].unique_partition_guid);
>  		pentry->typeuuid = ptes[i].partition_type_guid;
> -		pentry->num = i;
> +		pentry->num = i + 1;

This breaks my boot scripts. For better or worse, barebox partitions were always
zero-indexed. This switches them to 1-indexed.

Thanks,
Ahmad

>  		list_add_tail(&pentry->list, &epd->pd.partitions);
>  	}
>  out:
> -	kfree(gpt);
> -	kfree(ptes);
>  
>  	return &epd->pd;
>  }
>  
>  static void efi_partition_free(struct partition_desc *pd)
>  {
> +	struct efi_partition_desc *epd = container_of(pd, struct efi_partition_desc, pd);
>  	struct partition *part, *tmp;
>  
> -	list_for_each_entry_safe(part, tmp, &pd->partitions, list)
> -		free(part);
> +	list_for_each_entry_safe(part, tmp, &pd->partitions, list) {
> +		struct efi_partition *epart = container_of(part, struct efi_partition, part);
> +
> +		free(epart);
> +	}
> +
> +	free(epd->ptes);
> +	free(epd->gpt);
> +	free(epd);
> +}
> +
> +static __maybe_unused struct partition_desc *efi_partition_create_table(struct block_device *blk)
> +{
> +	struct efi_partition_desc *epd = xzalloc(sizeof(*epd));
> +	gpt_header *gpt;
> +
> +	partition_desc_init(&epd->pd, blk);
> +
> +	epd->gpt = xzalloc(512);
> +	gpt = epd->gpt;
> +
> +	gpt->signature = cpu_to_le64(GPT_HEADER_SIGNATURE);
> +	gpt->revision = cpu_to_le32(0x100);
> +	gpt->header_size = cpu_to_le32(sizeof(*gpt));
> +	gpt->my_lba = cpu_to_le64(1);
> +	gpt->alternate_lba = cpu_to_le64(last_lba(blk));
> +	gpt->first_usable_lba = cpu_to_le64(34);
> +	gpt->last_usable_lba = cpu_to_le64(last_lba(blk) - 34);;
> +	generate_random_guid((unsigned char *)&gpt->disk_guid);
> +	gpt->partition_entry_lba = cpu_to_le64(2);
> +	gpt->num_partition_entries = cpu_to_le32(128);
> +	gpt->sizeof_partition_entry = cpu_to_le32(sizeof(gpt_entry));
> +
> +	pr_info("Created new disk label with GUID %pU\n", &gpt->disk_guid);
> +
> +	epd->ptes = xzalloc(128 * sizeof(gpt_entry));
> +
> +	return &epd->pd;
> +}
> +
> +static guid_t partition_linux_data_guid = PARTITION_LINUX_DATA_GUID;
> +static guid_t partition_basic_data_guid = PARTITION_BASIC_DATA_GUID;
> +
> +static const guid_t *fs_type_to_guid(const char *fstype)
> +{
> +	if (!strcmp(fstype, "ext2"))
> +		return &partition_linux_data_guid;
> +	if (!strcmp(fstype, "ext3"))
> +		return &partition_linux_data_guid;
> +	if (!strcmp(fstype, "ext4"))
> +		return &partition_linux_data_guid;
> +	if (!strcmp(fstype, "fat16"))
> +		return &partition_basic_data_guid;
> +	if (!strcmp(fstype, "fat32"))
> +		return &partition_basic_data_guid;
> +
> +	return NULL;
> +}
> +
> +static __maybe_unused int efi_partition_mkpart(struct partition_desc *pd,
> +					       const char *name, const char *fs_type,
> +					       uint64_t start_lba, uint64_t end_lba)
> +{
> +	struct efi_partition_desc *epd = container_of(pd, struct efi_partition_desc, pd);
> +	struct efi_partition *epart;
> +	struct partition *part;
> +	gpt_header *gpt = epd->gpt;
> +	int num_parts = le32_to_cpu(gpt->num_partition_entries);
> +	gpt_entry *pte;
> +	int i;
> +	const guid_t *guid;
> +
> +	if (start_lba < 34) {
> +		pr_err("invalid start LBA %lld, minimum is 34\n", start_lba);
> +		return -EINVAL;
> +	}
> +
> +	if (end_lba >= last_lba(pd->blk) - 33) {
> +		pr_err("invalid end LBA %lld, maximum is %lld\n", start_lba,
> +		       last_lba(pd->blk) - 33);
> +		return -EINVAL;
> +	}
> +
> +	for (i = 0; i < num_parts; i++) {
> +		if (!is_pte_valid(&epd->ptes[i], last_lba(pd->blk)))
> +			break;
> +	}
> +
> +	if (i == num_parts) {
> +		pr_err("partition table is full\n");
> +		return -ENOSPC;
> +	}
> +
> +	guid = fs_type_to_guid(fs_type);
> +	if (!guid) {
> +		pr_err("Unknown fs type %s\n", fs_type);
> +		return -EINVAL;
> +	}
> +
> +	pte = &epd->ptes[i];
> +	epart = xzalloc(sizeof(*epart));
> +	part = &epart->part;
> +
> +	part->first_sec = start_lba;
> +	part->size = end_lba - start_lba + 1;
> +	part->typeuuid = *guid;
> +
> +	pte->partition_type_guid = *guid;
> +	generate_random_guid((unsigned char *)&pte->unique_partition_guid);
> +	pte->starting_lba = cpu_to_le64(start_lba);
> +	pte->ending_lba = cpu_to_le64(end_lba);
> +	part_get_efi_name(pte, name);
> +	part_set_efi_name(pte, part->name);
> +	part->num = i;
> +
> +	list_add_tail(&part->list, &pd->partitions);
> +
> +	return 0;
> +}
> +
> +static __maybe_unused int efi_partition_rmpart(struct partition_desc *pd, struct partition *part)
> +{
> +	struct efi_partition *epart = container_of(part, struct efi_partition, part);
> +
> +	memset(epart->pte, 0, sizeof(*epart->pte));
> +
> +	list_del(&part->list);
> +	free(epart);
> +
> +	return 0;
> +}
> +
> +static int efi_protective_mbr(struct block_device *blk)
> +{
> +	struct partition_desc *pdesc;
> +	int ret;
> +
> +	pdesc = partition_table_new(blk, "msdos");
> +	if (IS_ERR(pdesc)) {
> +		printf("Error: Cannot create partition table: %pe\n", pdesc);
> +		return PTR_ERR(pdesc);
> +	}
> +
> +	ret = partition_create(pdesc, "primary", "0xee", 1, last_lba(blk));
> +	if (ret) {
> +		pr_err("Cannot create partition: %pe\n", ERR_PTR(ret));
> +		goto out;
> +	}
> +
> +	ret = partition_table_write(pdesc);
> +	if (ret) {
> +		pr_err("Cannot write partition: %pe\n", ERR_PTR(ret));
> +		goto out;
> +	}
> +out:
> +	partition_table_free(pdesc);
> +
> +	return ret;
> +}
> +
> +static __maybe_unused int efi_partition_write(struct partition_desc *pd)
> +{
> +	struct block_device *blk = pd->blk;
> +	struct efi_partition_desc *epd = container_of(pd, struct efi_partition_desc, pd);
> +	gpt_header *gpt = epd->gpt, *altgpt;
> +	int ret;
> +	uint32_t count;
> +	uint64_t from, size;
> +
> +	if (le32_to_cpu(gpt->num_partition_entries) != 128) {
> +		/*
> +		 * This is not yet properly implemented. At least writing of the
> +		 * alternative GPT is not correctly implemented for this case as
> +		 * we can't assume that the partition entries are written at
> +		 * last_lba() - 32, we would have to calculate that from the number
> +		 * of partition entries.
> +		 */
> +		pr_err("num_partition_entries is != 128. This is not yet supported for writing\n");
> +		return -EINVAL;
> +	}
> +
> +	count = le32_to_cpu(gpt->num_partition_entries) *
> +		le32_to_cpu(gpt->sizeof_partition_entry);
> +
> +	gpt->my_lba = cpu_to_le64(1);
> +	gpt->partition_entry_array_crc32 = cpu_to_le32(efi_crc32(
> +			(const unsigned char *)epd->ptes, count));
> +	gpt->header_crc32 = 0;
> +	gpt->header_crc32 = cpu_to_le32(efi_crc32((const unsigned char *)gpt,
> +						  le32_to_cpu(gpt->header_size)));
> +
> +	ret = efi_protective_mbr(blk);
> +	if (ret)
> +		return ret;
> +
> +	ret = block_write(blk, gpt, 1, 1);
> +	if (ret)
> +		goto err_block_write;
> +
> +	from = le64_to_cpu(gpt->partition_entry_lba);
> +	size = count / GPT_BLOCK_SIZE;
> +
> +	ret = block_write(blk, epd->ptes, from, size);
> +	if (ret)
> +		goto err_block_write;
> +
> +	altgpt = xmemdup(gpt, SECTOR_SIZE);
> +
> +	altgpt->alternate_lba = cpu_to_le64(1);
> +	altgpt->my_lba = cpu_to_le64(last_lba(blk));
> +	altgpt->partition_entry_lba = cpu_to_le64(last_lba(blk) - 32);
> +	altgpt->header_crc32 = 0;
> +	altgpt->header_crc32 = cpu_to_le32(efi_crc32((const unsigned char *)altgpt,
> +						  le32_to_cpu(altgpt->header_size)));
> +	ret = block_write(blk, altgpt, last_lba(blk), 1);
> +
> +	free(altgpt);
> +
> +	if (ret)
> +		goto err_block_write;
> +	ret = block_write(blk, epd->ptes, last_lba(blk) - 32, 32);
> +	if (ret)
> +		goto err_block_write;
> +
> +	return 0;
> +
> +err_block_write:
> +	pr_err("Cannot write to block device: %pe\n", ERR_PTR(ret));
>  
> -	free(pd);
> +	return ret;
>  }
>  
>  static struct partition_parser efi_partition_parser = {
>  	.parse = efi_partition,
>  	.partition_free = efi_partition_free,
> +#ifdef CONFIG_PARTITION_MANIPULATION
> +	.create = efi_partition_create_table,
> +	.mkpart = efi_partition_mkpart,
> +	.rmpart = efi_partition_rmpart,
> +	.write = efi_partition_write,
> +#endif
>  	.type = filetype_gpt,
> +	.name = "gpt",
>  };
>  
>  static int efi_partition_init(void)

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |




More information about the barebox mailing list