[PATCH v14 02/15] FWU: Add FWU metadata structure and driver for accessing metadata

Ilias Apalodimas ilias.apalodimas at linaro.org
Thu Oct 20 08:39:40 CEST 2022


Hi Sughosh, Etienne

[...]

> > > +      * Check if the platform has defined its own
> > > +      * function to check the metadata partitions'
> > > +      * validity. If so, that takes precedence.
> > > +      */
> > > +     ret = fwu_mdata_check(dev);
> >
> > Isn't this a bit dangerous?  Let's say a device defines it's own check
> > function but for some reason returns -ENOSYS.  I am wondering if we should
> > just return 0 if the platform defined functions aren't defined.
>
> A driver should return ENOSYS only if a driver method has not been
> defined. That is what I see being used in other drivers as well. So I
> think that the current implementation of returning ENOSYS for a non
> defined method is correct. If a driver is returning ENOSYS for any
> other purpose I feel that should be fixed instead.
>

Fair enough

> >
> > > +     if (!ret || ret != -ENOSYS)
> > > +             return ret;
> > > +
> > > +     /*
> > > +      * Two FWU metadata partitions are expected.
> > > +      * If we don't have two, user needs to create
> > > +      * them first
> > > +      */
> > > +     valid_partitions = 0;
> > > +     ret = fwu_get_mdata_part_num(dev, mdata_parts);
> > > +     if (ret < 0) {
> > > +             log_debug("Error getting the FWU metadata partitions\n");
> > > +             return -ENOENT;
> > > +     }
> > > +
> > > +     ret = fwu_read_mdata_partition(dev, &pri_mdata, mdata_parts[0]);
> > > +     if (!ret) {
> > > +             ret = fwu_verify_mdata(&pri_mdata, 1);
> > > +             if (!ret)
> > > +                     valid_partitions |= PRIMARY_PART;
> > > +     }
> > > +
> > > +     ret = fwu_read_mdata_partition(dev, &secondary_mdata, mdata_parts[1]);
> > > +     if (!ret) {
> > > +             ret = fwu_verify_mdata(&secondary_mdata, 0);
> > > +             if (!ret)
> > > +                     valid_partitions |= SECONDARY_PART;
> > > +     }
> > > +
> > > +     if (valid_partitions == (PRIMARY_PART | SECONDARY_PART)) {
> > > +             /*
> > > +              * Before returning, check that both the
> > > +              * FWU metadata copies are the same. If not,
> > > +              * the FWU metadata copies need to be
> > > +              * re-populated.
> > > +              */
> > > +             if (!memcmp(&pri_mdata, &secondary_mdata,
> > > +                         sizeof(struct fwu_mdata))) {
> > > +                     ret = 0;
> > > +             } else {
> > > +                     log_info("Both FWU metadata copies are valid but do not match. Please check!\n");
> >
> > Check what ? Just remove that part please
>
> Okay. I will restore the secondary partition from the primary
> partition as Etienne has suggested.

Yep, I agree on that.  I vaguely remember discussing the same thing a
few versions ago, but that somehow slipped away.  Good catch!

>
> >
> > > +                     ret = -1;
> > > +             }
> > > +             goto out;
> > > +     }
> > > +
> > > +     if (!(valid_partitions & BOTH_PARTS)) {
> > > +             ret = -1;
> >
> > In general we should try to avoid returning -1 etc.  Is there an errno that
> > would make sense?
>
> Even I am not sure what is relevant here(EINVAL?). I think I can add a
> log_info mentioning the error case?

EBADMSG could also be an option here I guess, but there's not POSIX
errnor I am aware of that means "data corrupted"

>
> >
> > > +             goto out;
> > > +     }
> > > +
> > > +     invalid_partitions = valid_partitions ^ BOTH_PARTS;
> > > +     ret = fwu_write_mdata_partition(dev,
> > > +                                     (invalid_partitions == PRIMARY_PART) ?
> > > +                                     &secondary_mdata : &pri_mdata,
> > > +                                     (invalid_partitions == PRIMARY_PART) ?
> > > +                                     mdata_parts[0] : mdata_parts[1]);
> > > +
> > > +     if (ret < 0)
> > > +             log_info("Restoring %s FWU metadata partition failed\n",
> > > +                       (invalid_partitions == PRIMARY_PART) ?
> > > +                       "primary" : "secondary");
> > > +
> > > +out:
> > > +     return ret;
> > > +}
> > > +
> > > +/**
> > > + * fwu_get_active_index() - Get active_index from the FWU metadata
> > > + * @active_idx: active_index value to be read
> > > + *
> > > + * Read the active_index field from the FWU metadata and place it in
> > > + * the variable pointed to be the function argument.
> > > + *
> > > + * Return: 0 if OK, -ve on error
> > > + *
> > > + */
> > > +int fwu_get_active_index(uint *active_idx)
> > > +{
> > > +     int ret;
> > > +     struct udevice *dev;
> > > +     struct fwu_mdata mdata = { 0 };
> > > +
> > > +     ret = fwu_get_dev_mdata(&dev, &mdata);
> > > +     if (ret)
> > > +             return ret;
> > > +
> > > +     /*
> > > +      * Found the FWU metadata partition, now read the active_index
> > > +      * value
> > > +      */
> > > +     *active_idx = mdata.active_index;
> > > +     if (*active_idx >= CONFIG_FWU_NUM_BANKS) {
> > > +             log_debug("Active index value read is incorrect\n");
> > > +             ret = -EINVAL;
> > > +     }
> > > +
> > > +     return ret;
> > > +}
> > > +
> > > +/**
> > > + * fwu_set_active_index() - Set active_index in the FWU metadata
> > > + * @active_idx: active_index value to be set
> > > + *
> > > + * Update the active_index field in the FWU metadata
> > > + *
> > > + * Return: 0 if OK, -ve on error
> > > + *
> > > + */
> > > +int fwu_set_active_index(uint active_idx)
> > > +{
> > > +     int ret;
> > > +     struct udevice *dev;
> > > +     struct fwu_mdata mdata = { 0 };
> > > +
> > > +     if (active_idx >= CONFIG_FWU_NUM_BANKS) {
> > > +             log_debug("Invalid active index value\n");
> > > +             return -EINVAL;
> > > +     }
> > > +
> > > +     ret = fwu_get_dev_mdata(&dev, &mdata);
> > > +     if (ret)
> > > +             return ret;
> > > +
> > > +     /*
> > > +      * Update the active index and previous_active_index fields
> > > +      * in the FWU metadata
> > > +      */
> > > +     mdata.previous_active_index = mdata.active_index;
> > > +     mdata.active_index = active_idx;
> > > +
> > > +     /*
> > > +      * Now write this updated FWU metadata to both the
> > > +      * FWU metadata partitions
> > > +      */
> > > +     ret = fwu_update_mdata(dev, &mdata);
> > > +     if (ret) {
> > > +             log_debug("Failed to update FWU metadata partitions\n");
> > > +             ret = -EIO;
> > > +     }
> > > +
> > > +     return ret;
> > > +}
> > > +
> > > +/**
> > > + * fwu_get_image_index() - Get the Image Index to be used for capsule update
> > > + * @image_index: The Image Index for the image
> > > + *
> > > + * The FWU multi bank update feature computes the value of image_index at
> > > + * runtime, based on the bank to which the image needs to be written to.
> > > + * Derive the image_index value for the image.
> > > + *
> > > + * Currently, the capsule update driver uses the DFU framework for
> > > + * the updates. This function gets the DFU alt number which is to
> > > + * be used as the Image Index
> > > + *
> > > + * Return: 0 if OK, -ve on error
> > > + *
> > > + */
> > > +int fwu_get_image_index(u8 *image_index)
> > > +{
> > > +     int ret, i;
> > > +     u8 alt_num;
> > > +     uint update_bank;
> > > +     efi_guid_t *image_guid, image_type_id;
> > > +     struct udevice *dev;
> > > +     struct fwu_mdata mdata = { 0 };
> > > +     struct fwu_image_entry *img_entry;
> > > +     struct fwu_image_bank_info *img_bank_info;
> > > +
> > > +     ret = fwu_get_dev_mdata(&dev, &mdata);
> > > +     if (ret)
> > > +             return ret;
> > > +
> > > +     ret = fwu_plat_get_update_index(&update_bank);
> > > +     if (ret) {
> > > +             log_debug("Failed to get the FWU update bank\n");
> > > +             goto out;
> > > +     }
> > > +
> > > +     ret = fwu_get_image_type_id(image_index, &image_type_id);
> > > +     if (ret) {
> > > +             log_debug("Unable to get image_type_id for image_index %u\n",
> > > +                       *image_index);
> > > +             goto out;
> > > +     }
> > > +
> > > +     ret = -EINVAL;
> > > +     /*
> > > +      * The FWU metadata has been read. Now get the image_uuid for the
> > > +      * image with the update_bank.
> > > +      */
> > > +     for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; i++) {
> > > +             if (!guidcmp(&image_type_id,
> > > +                          &mdata.img_entry[i].image_type_uuid)) {
> >
> > can we invert the check with a 'continue' here?  Will save us one level of
> > indentation
>
> Hmm, yeah. I know it's subjective, but I personally find the current
> code flow easier to follow. Moreover, the current code is not breaking
> the 80 column rule. If you don't have a strong opinion about this, I
> will prefer to keep it this way.
>
> >
> > > +                     img_entry = &mdata.img_entry[i];
> > > +                     img_bank_info = &img_entry->img_bank_info[update_bank];

[...]

Thanks
/Ilias


More information about the U-Boot mailing list