[Intel-xe] [PATCH v2 04/11] drm/xe/gsc: Parse GSC FW header

John Harrison john.c.harrison at intel.com
Thu Nov 16 23:01:36 UTC 2023


On 11/14/2023 16:46, Daniele Ceraolo Spurio wrote:
> The GSC blob starts with a layout header, from which we can move to the
> boot directory, which in turns allows us to find the CPD. The CPD uses
> the same format as the one in the HuC binary, so we can re-use the same
> parsing code to get to the manifest, which contains the release and
> security versions of the FW.
>
> v2: Fix comments in struct definition (John)
>
> Signed-off-by: Daniele Ceraolo Spurio <daniele.ceraolospurio at intel.com>
> Cc: Alan Previn <alan.previn.teres.alexis at intel.com>
> Cc: John Harrison <John.C.Harrison at Intel.com>
> Cc: Lucas De Marchi <lucas.demarchi at intel.com>
Reviewed-by: John Harrison <John.C.Harrison at Intel.com>

> ---
>   drivers/gpu/drm/xe/xe_gsc_types.h |   3 +
>   drivers/gpu/drm/xe/xe_uc_fw.c     |  77 ++++++++++++++++++++
>   drivers/gpu/drm/xe/xe_uc_fw_abi.h | 113 ++++++++++++++++++++++++++++++
>   3 files changed, 193 insertions(+)
>
> diff --git a/drivers/gpu/drm/xe/xe_gsc_types.h b/drivers/gpu/drm/xe/xe_gsc_types.h
> index 135f156e3736..1bc50583fe58 100644
> --- a/drivers/gpu/drm/xe/xe_gsc_types.h
> +++ b/drivers/gpu/drm/xe/xe_gsc_types.h
> @@ -14,6 +14,9 @@
>   struct xe_gsc {
>   	/** @fw: Generic uC firmware management */
>   	struct xe_uc_fw fw;
> +
> +	/** @security_version: SVN found in the fetched blob */
> +	u32 security_version;
>   };
>   
>   #endif
> diff --git a/drivers/gpu/drm/xe/xe_uc_fw.c b/drivers/gpu/drm/xe/xe_uc_fw.c
> index 16217aacdbfb..c354f7b51103 100644
> --- a/drivers/gpu/drm/xe/xe_uc_fw.c
> +++ b/drivers/gpu/drm/xe/xe_uc_fw.c
> @@ -12,6 +12,7 @@
>   #include "xe_bo.h"
>   #include "xe_device_types.h"
>   #include "xe_force_wake.h"
> +#include "xe_gsc.h"
>   #include "xe_gt.h"
>   #include "xe_map.h"
>   #include "xe_mmio.h"
> @@ -488,6 +489,13 @@ static int parse_cpd_header(struct xe_uc_fw *uc_fw, const void *data, size_t siz
>   	release->minor = manifest->fw_version.minor;
>   	release->patch = manifest->fw_version.hotfix;
>   
> +	if (uc_fw->type == XE_UC_FW_TYPE_GSC) {
> +		struct xe_gsc *gsc = container_of(uc_fw, struct xe_gsc, fw);
> +
> +		release->build = manifest->fw_version.build;
> +		gsc->security_version = manifest->security_version;
> +	}
> +
>   	/* then optionally look for the css header */
>   	if (css_entry) {
>   		int ret;
> @@ -517,6 +525,73 @@ static int parse_cpd_header(struct xe_uc_fw *uc_fw, const void *data, size_t siz
>   	return 0;
>   }
>   
> +static int parse_gsc_layout(struct xe_uc_fw *uc_fw, const void *data, size_t size)
> +{
> +	struct xe_gt *gt = uc_fw_to_gt(uc_fw);
> +	const struct gsc_layout_pointers *layout = data;
> +	const struct gsc_bpdt_header *bpdt_header = NULL;
> +	const struct gsc_bpdt_entry *bpdt_entry = NULL;
> +	size_t min_size = sizeof(*layout);
> +	int i;
> +
> +	if (size < min_size) {
> +		xe_gt_err(gt, "GSC FW too small! %zu < %zu\n", size, min_size);
> +		return -ENODATA;
> +	}
> +
> +	min_size = layout->boot1.offset + layout->boot1.size;
> +	if (size < min_size) {
> +		xe_gt_err(gt, "GSC FW too small for boot section! %zu < %zu\n",
> +			  size, min_size);
> +		return -ENODATA;
> +	}
> +
> +	min_size = sizeof(*bpdt_header);
> +	if (layout->boot1.size < min_size) {
> +		xe_gt_err(gt, "GSC FW boot section too small for BPDT header: %u < %zu\n",
> +			  layout->boot1.size, min_size);
> +		return -ENODATA;
> +	}
> +
> +	bpdt_header = data + layout->boot1.offset;
> +	if (bpdt_header->signature != GSC_BPDT_HEADER_SIGNATURE) {
> +		xe_gt_err(gt, "invalid signature for BPDT header: 0x%08x!\n",
> +			  bpdt_header->signature);
> +		return -EINVAL;
> +	}
> +
> +	min_size += sizeof(*bpdt_entry) * bpdt_header->descriptor_count;
> +	if (layout->boot1.size < min_size) {
> +		xe_gt_err(gt, "GSC FW boot section too small for BPDT entries: %u < %zu\n",
> +			  layout->boot1.size, min_size);
> +		return -ENODATA;
> +	}
> +
> +	bpdt_entry = (void *)bpdt_header + sizeof(*bpdt_header);
> +	for (i = 0; i < bpdt_header->descriptor_count; i++, bpdt_entry++) {
> +		if ((bpdt_entry->type & GSC_BPDT_ENTRY_TYPE_MASK) !=
> +		    GSC_BPDT_ENTRY_TYPE_GSC_RBE)
> +			continue;
> +
> +		min_size = bpdt_entry->sub_partition_offset;
> +
> +		/* the CPD header parser will check that the CPD header fits */
> +		if (layout->boot1.size < min_size) {
> +			xe_gt_err(gt, "GSC FW boot section too small for CPD offset: %u < %zu\n",
> +				  layout->boot1.size, min_size);
> +			return -ENODATA;
> +		}
> +
> +		return parse_cpd_header(uc_fw,
> +					(void *)bpdt_header + min_size,
> +					layout->boot1.size - min_size,
> +					"RBEP.man", NULL);
> +	}
> +
> +	xe_gt_err(gt, "couldn't find CPD header in GSC binary!\n");
> +	return -ENODATA;
> +}
> +
>   static int parse_headers(struct xe_uc_fw *uc_fw, const struct firmware *fw)
>   {
>   	int ret;
> @@ -526,6 +601,8 @@ static int parse_headers(struct xe_uc_fw *uc_fw, const struct firmware *fw)
>   	 * releases use GSC CPD headers.
>   	 */
>   	switch (uc_fw->type) {
> +	case XE_UC_FW_TYPE_GSC:
> +		return parse_gsc_layout(uc_fw, fw->data, fw->size);
>   	case XE_UC_FW_TYPE_HUC:
>   		ret = parse_cpd_header(uc_fw, fw->data, fw->size, "HUCP.man", "huc_fw");
>   		if (!ret || ret != -ENOENT)
> diff --git a/drivers/gpu/drm/xe/xe_uc_fw_abi.h b/drivers/gpu/drm/xe/xe_uc_fw_abi.h
> index d6725c963251..87ade41209d0 100644
> --- a/drivers/gpu/drm/xe/xe_uc_fw_abi.h
> +++ b/drivers/gpu/drm/xe/xe_uc_fw_abi.h
> @@ -140,6 +140,58 @@ static_assert(sizeof(struct uc_css_header) == 128);
>    *	|      RSA Key (MTL+ only)                       |
>    *	|      ...                                       |
>    *	+================================================+
> + *
> + * The GSC binary starts instead with a layout header, which contains the
> + * locations of the various partitions of the binary. The one we're interested
> + * in is the boot1 partition, where we can find a BPDT header followed by
> + * entries, one of which points to the RBE sub-section of the partition, which
> + * contains the CPD. The GSC blob does not contain a CSS-based binary, so we
> + * only need to look for the manifest, which is under the "RBEP.man" CPD entry.
> + * Note that we have no need to find where the actual FW code is inside the
> + * image because the GSC ROM will itself parse the headers to find it and load
> + * it.
> + * The GSC firmware header layout looks like this::
> + *
> + *	+================================================+
> + *	|  Layout Pointers                               |
> + *	|      ...                                       |
> + *	|      Boot1 offset  >---------------------------|------o
> + *	|      ...                                       |      |
> + *	+================================================+      |
> + *	                                                        |
> + *	+================================================+      |
> + *	|  BPDT header                                   |<-----o
> + *	+================================================+
> + *	|  BPDT entries[]                                |
> + *	|      entry1                                    |
> + *	|      ...                                       |
> + *	|      entryX                                    |
> + *	|          type == GSC_RBE                       |
> + *	|          offset  >-----------------------------|------o
> + *	|      ...                                       |      |
> + *	+================================================+      |
> + *	                                                        |
> + *	+================================================+      |
> + *	|  CPD Header                                    |<-----o
> + *	+================================================+
> + *	|  CPD entries[]                                 |
> + *	|      entry1                                    |
> + *	|      ...                                       |
> + *	|      entryX                                    |
> + *	|          "RBEP.man"                            |
> + *	|           ...                                  |
> + *	|           offset  >----------------------------|------o
> + *	|      ...                                       |      |
> + *	+================================================+      |
> + *	                                                        |
> + *	+================================================+      |
> + *	| Manifest Header                                |<-----o
> + *	|  ...                                           |
> + *	|  FW version                                    |
> + *	|  ...                                           |
> + *	|  Security version                              |
> + *	|  ...                                           |
> + *	+================================================+
>    */
>   
>   struct gsc_version {
> @@ -149,6 +201,67 @@ struct gsc_version {
>   	u16 build;
>   } __packed;
>   
> +struct gsc_partition {
> +	u32 offset;
> +	u32 size;
> +} __packed;
> +
> +struct gsc_layout_pointers {
> +	u8 rom_bypass_vector[16];
> +
> +	/* size of this header section, not including ROM bypass vector */
> +	u16 size;
> +
> +	/*
> +	 * bit0: Backup copy of layout pointers exists
> +	 * bits1-15: reserved
> +	 */
> +	u8 flags;
> +
> +	u8 reserved;
> +
> +	u32 crc32;
> +
> +	struct gsc_partition datap;
> +	struct gsc_partition boot1;
> +	struct gsc_partition boot2;
> +	struct gsc_partition boot3;
> +	struct gsc_partition boot4;
> +	struct gsc_partition boot5;
> +	struct gsc_partition temp_pages;
> +} __packed;
> +
> +/* Boot partition structures */
> +struct gsc_bpdt_header {
> +	u32 signature;
> +#define GSC_BPDT_HEADER_SIGNATURE 0x000055AA
> +
> +	u16 descriptor_count; /* num of entries after the header */
> +
> +	u8 version;
> +	u8 configuration;
> +
> +	u32 crc32;
> +
> +	u32 build_version;
> +	struct gsc_version tool_version;
> +} __packed;
> +
> +struct gsc_bpdt_entry {
> +	/*
> +	 * Bits 0-15: BPDT entry type
> +	 * Bits 16-17: reserved
> +	 * Bit 18: code sub-partition
> +	 * Bits 19-31: reserved
> +	 */
> +	u32 type;
> +#define GSC_BPDT_ENTRY_TYPE_MASK GENMASK(15, 0)
> +#define GSC_BPDT_ENTRY_TYPE_GSC_RBE 0x1
> +
> +	u32 sub_partition_offset; /* from the base of the BPDT header */
> +	u32 sub_partition_size;
> +} __packed;
> +
>   /* Code partition directory (CPD) structures */
>   struct gsc_cpd_header_v2 {
>   	u32 header_marker;



More information about the Intel-xe mailing list