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 |


Reply via email to