[Intel-xe] [PATCH 05/12] drm/xe/gsc: Parse GSC FW header
John Harrison
john.c.harrison at intel.com
Wed Nov 8 00:42:23 UTC 2023
On 11/7/2023 15:57, Daniele Ceraolo Spurio wrote:
> On 11/7/2023 3:45 PM, John Harrison wrote:
>> On 10/27/2023 15:29, 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.
>>>
>>> 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>
>>> ---
>>> 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;
>> There is no official structure to this version number?
>
> no, it's just a linearly increasing integer, there are no
> minor/patch/build versions involved.
>
>>
>>> };
>>> #endif
>>> diff --git a/drivers/gpu/drm/xe/xe_uc_fw.c
>>> b/drivers/gpu/drm/xe/xe_uc_fw.c
>>> index af3e5cba606f..bb38a76eb4a6 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,
>> Could compare this calculation against bpdt_entry->sub_partition_size
>> before bothering to try to decode a partial CPD?
>
> The CPD parser checks for the size. I could add an extra check here
> and bail early, but why add extra case to optimize a scenario that
> should never happen?
Fair enough.
>
>>
>>> + "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..edf2a448f4bb 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 pointers layout not including ROM bypass vector */
>> pointers layout -> layout pointers?
>
> I'll just simplify it to "size of this header section"
>
>>
>>> + u16 size;
>>> +
>>> + /*
>>> + * bit0: Backup copy of layout pointers exist
>> exist -> exists
>
> ack
>
>>
>>> + * bits1-15: reserved
>>> + */
>>> + u8 flags;
>>> +
>>> + u8 reserved;
>>> +
>>> + u32 crc32;
>> Should we be doing anything to test against this crc or the one in
>> the bpdt_header below?
>
> No, the GSC ROM checks those at load time.
Okay.
John.
>
> Daniele
>
>>
>> John.
>>
>>> +
>>> + 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