Re: [PATCH] lib: Export the parsing functions and related data structures of the PLDM library

From: Jacob Keller
Date: Mon Sep 09 2024 - 16:34:41 EST




On 9/8/2024 11:33 PM, Shawn.Shao wrote:
> From: Shawn Shao <shawn.shao@xxxxxxxxxxxxxxx>
> > The PLDM library is used to implement firmware upgrades,
> but the current library functions only support the
> `pldmfw_flash_image` function to complete a fixed
> process of parsing, sending data to the backend,
> and flashing (allowing users to implement custom
> logic using `pldmfw_ops`). However, this poses
> significant challenges for device vendors using
> PLDM for firmware upgrades.


Hi! I would love to see lib/pldmfw expanded to support more use cases.

I initially focused primarily on the use case I had for driving a flash
update via the functions exposed through my device's firmware.

> The following scenarios are not supported:
> 1. Only using the PLDM parsing functions, as the
> current library does not support this operation.


Right. Exposing the parsing would be useful to enable validating the
image without necessarily running the full process.

> 2. The firmware upgrade process differs from this
> fixed flow (the firmware upgrade process may
> vary across different vendors).
> |-> pldmfw_flash_image
> |-> pldm_parse_image
> |-> pldm_parse_header (UUID/revision校验)
> |-> pldm_parse_records
> |-> pldm_parse_components
> -> pldm_verify_header_crc
> |-> pldm_find_matching_record (xxx_match_record)
> |-> pldm_send_package_data (xxx_send_package_data)
> |-> pldm_send_component_tables (xxx_send_package_data)
> |-> pldm_flash_components (xxx_flash_component)
> |-> pldm_finalize_update (xxx_finalize_update)
>
Right. I think there is some room for interpretation in the standard,
which leads to different vendors interpreting some aspects of the flow.

I'm open to extending the library to support other users.

I think the overall change is good, but I might pull out the
device_update_flags into a separate patch.

Reviewed-by: Jacob Keller <jacob.e.keller@xxxxxxxxx>

> Signed-off-by: Shawn Shao <shawn.shao@xxxxxxxxxxxxxxx>
> ---
> include/linux/pldmfw.h | 38 +++++++++++++++++++++++++++++++++++++
> lib/pldmfw/pldmfw.c | 43 +++++-------------------------------------
> 2 files changed, 43 insertions(+), 38 deletions(-)
>
> diff --git a/include/linux/pldmfw.h b/include/linux/pldmfw.h
> index 0fc831338226..5058a07a5ea4 100644
> --- a/include/linux/pldmfw.h
> +++ b/include/linux/pldmfw.h
> @@ -130,6 +130,42 @@ struct pldmfw {
> struct device *dev;
> };
>
> +/* pldmfw_priv structure used to store details about the PLDM image file as it is
> + * being validated and processed.
> + */
> +struct pldmfw_priv {
> + struct pldmfw *context;
> + const struct firmware *fw;
> +
> + /* current offset of firmware image */
> + size_t offset;
> +
> + struct list_head records;
> + struct list_head components;
> +
> + /* PLDM Firmware Package Header */
> + const struct __pldm_header *header;
> + u16 total_header_size;
> +
> + /* length of the component bitmap */
> + u16 component_bitmap_len;
> + u16 bitmap_size;
> +
> + /* Start of the component image information */
> + u16 component_count;
> + const u8 *component_start;
> +
> + /* Start pf the firmware device id records */
> + const u8 *record_start;
> + u8 record_count;
> +
> + /* The CRC at the end of the package header */
> + u32 header_crc;
> +
> + struct pldmfw_record *matching_record;
> +};
> +
> +
> bool pldmfw_op_pci_match_record(struct pldmfw *context, struct pldmfw_record *record);
>
> /* Operations invoked by the generic PLDM firmware update engine. Used to
> @@ -160,6 +196,8 @@ struct pldmfw_ops {
> int (*finalize_update)(struct pldmfw *context);
> };
>
> +int pldm_parse_image(struct pldmfw_priv *data);
> +void pldmfw_free_priv(struct pldmfw_priv *data);
> int pldmfw_flash_image(struct pldmfw *context, const struct firmware *fw);
>
> #endif
> diff --git a/lib/pldmfw/pldmfw.c b/lib/pldmfw/pldmfw.c
> index 54e1809a38fd..cd1698e9c340 100644
> --- a/lib/pldmfw/pldmfw.c
> +++ b/lib/pldmfw/pldmfw.c
> @@ -14,41 +14,6 @@
>
> #include "pldmfw_private.h"
>
> -/* Internal structure used to store details about the PLDM image file as it is
> - * being validated and processed.
> - */
> -struct pldmfw_priv {
> - struct pldmfw *context;
> - const struct firmware *fw;
> -
> - /* current offset of firmware image */
> - size_t offset;
> -
> - struct list_head records;
> - struct list_head components;
> -
> - /* PLDM Firmware Package Header */
> - const struct __pldm_header *header;
> - u16 total_header_size;
> -
> - /* length of the component bitmap */
> - u16 component_bitmap_len;
> - u16 bitmap_size;
> -
> - /* Start of the component image information */
> - u16 component_count;
> - const u8 *component_start;
> -
> - /* Start pf the firmware device id records */
> - const u8 *record_start;
> - u8 record_count;
> -
> - /* The CRC at the end of the package header */
> - u32 header_crc;
> -
> - struct pldmfw_record *matching_record;
> -};
> -
> /**
> * pldm_check_fw_space - Verify that the firmware image has space left
> * @data: pointer to private data
> @@ -341,6 +306,7 @@ pldm_parse_one_record(struct pldmfw_priv *data,
> return err;
>
> record_len = get_unaligned_le16(&__record->record_len);
> + record->device_update_flags = get_unaligned_le32(&__record->device_update_flags);

This feels like a change that belongs in a separate patch? It looks like
its fixing an actual bug in missing data?

> record->package_data_len = get_unaligned_le16(&__record->package_data_len);
> record->version_len = __record->version_len;
> record->version_type = __record->version_type;
> @@ -540,7 +506,7 @@ static int pldm_verify_header_crc(struct pldmfw_priv *data)
> * Loops through and clears all allocated memory associated with each
> * allocated descriptor, record, and component.
> */
> -static void pldmfw_free_priv(struct pldmfw_priv *data)
> +void pldmfw_free_priv(struct pldmfw_priv *data)
> {
> struct pldmfw_component *component, *c_safe;
> struct pldmfw_record *record, *r_safe;
> @@ -566,7 +532,7 @@ static void pldmfw_free_priv(struct pldmfw_priv *data)
> kfree(record);
> }
> }
> -
> +EXPORT_SYMBOL(pldmfw_free_priv);
> /**
> * pldm_parse_image - parse and extract details from PLDM image
> * @data: pointer to private data
> @@ -581,7 +547,7 @@ static void pldmfw_free_priv(struct pldmfw_priv *data)
> *
> * Returns: zero on success, or a negative error code on failure.
> */
> -static int pldm_parse_image(struct pldmfw_priv *data)
> +int pldm_parse_image(struct pldmfw_priv *data)
> {
> int err;
>
> @@ -602,6 +568,7 @@ static int pldm_parse_image(struct pldmfw_priv *data)
>
> return pldm_verify_header_crc(data);
> }
> +EXPORT_SYMBOL(pldm_parse_image);
>
> /* these are u32 so that we can store PCI_ANY_ID */
> struct pldm_pci_record_id {