[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