Skip to content

Commit 985d5a4

Browse files
dceraolorodrigovivi
authored andcommitted
drm/xe/gsc: Parse GSC FW header
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@intel.com> Cc: Alan Previn <alan.previn.teres.alexis@intel.com> Cc: John Harrison <John.C.Harrison@Intel.com> Cc: Lucas De Marchi <lucas.demarchi@intel.com> Reviewed-by: John Harrison <John.C.Harrison@Intel.com> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
1 parent 0d1caff commit 985d5a4

File tree

3 files changed

+193
-0
lines changed

3 files changed

+193
-0
lines changed

drivers/gpu/drm/xe/xe_gsc_types.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
struct xe_gsc {
1515
/** @fw: Generic uC firmware management */
1616
struct xe_uc_fw fw;
17+
18+
/** @security_version: SVN found in the fetched blob */
19+
u32 security_version;
1720
};
1821

1922
#endif

drivers/gpu/drm/xe/xe_uc_fw.c

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "xe_bo.h"
1313
#include "xe_device_types.h"
1414
#include "xe_force_wake.h"
15+
#include "xe_gsc.h"
1516
#include "xe_gt.h"
1617
#include "xe_map.h"
1718
#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
488489
release->minor = manifest->fw_version.minor;
489490
release->patch = manifest->fw_version.hotfix;
490491

492+
if (uc_fw->type == XE_UC_FW_TYPE_GSC) {
493+
struct xe_gsc *gsc = container_of(uc_fw, struct xe_gsc, fw);
494+
495+
release->build = manifest->fw_version.build;
496+
gsc->security_version = manifest->security_version;
497+
}
498+
491499
/* then optionally look for the css header */
492500
if (css_entry) {
493501
int ret;
@@ -517,6 +525,73 @@ static int parse_cpd_header(struct xe_uc_fw *uc_fw, const void *data, size_t siz
517525
return 0;
518526
}
519527

528+
static int parse_gsc_layout(struct xe_uc_fw *uc_fw, const void *data, size_t size)
529+
{
530+
struct xe_gt *gt = uc_fw_to_gt(uc_fw);
531+
const struct gsc_layout_pointers *layout = data;
532+
const struct gsc_bpdt_header *bpdt_header = NULL;
533+
const struct gsc_bpdt_entry *bpdt_entry = NULL;
534+
size_t min_size = sizeof(*layout);
535+
int i;
536+
537+
if (size < min_size) {
538+
xe_gt_err(gt, "GSC FW too small! %zu < %zu\n", size, min_size);
539+
return -ENODATA;
540+
}
541+
542+
min_size = layout->boot1.offset + layout->boot1.size;
543+
if (size < min_size) {
544+
xe_gt_err(gt, "GSC FW too small for boot section! %zu < %zu\n",
545+
size, min_size);
546+
return -ENODATA;
547+
}
548+
549+
min_size = sizeof(*bpdt_header);
550+
if (layout->boot1.size < min_size) {
551+
xe_gt_err(gt, "GSC FW boot section too small for BPDT header: %u < %zu\n",
552+
layout->boot1.size, min_size);
553+
return -ENODATA;
554+
}
555+
556+
bpdt_header = data + layout->boot1.offset;
557+
if (bpdt_header->signature != GSC_BPDT_HEADER_SIGNATURE) {
558+
xe_gt_err(gt, "invalid signature for BPDT header: 0x%08x!\n",
559+
bpdt_header->signature);
560+
return -EINVAL;
561+
}
562+
563+
min_size += sizeof(*bpdt_entry) * bpdt_header->descriptor_count;
564+
if (layout->boot1.size < min_size) {
565+
xe_gt_err(gt, "GSC FW boot section too small for BPDT entries: %u < %zu\n",
566+
layout->boot1.size, min_size);
567+
return -ENODATA;
568+
}
569+
570+
bpdt_entry = (void *)bpdt_header + sizeof(*bpdt_header);
571+
for (i = 0; i < bpdt_header->descriptor_count; i++, bpdt_entry++) {
572+
if ((bpdt_entry->type & GSC_BPDT_ENTRY_TYPE_MASK) !=
573+
GSC_BPDT_ENTRY_TYPE_GSC_RBE)
574+
continue;
575+
576+
min_size = bpdt_entry->sub_partition_offset;
577+
578+
/* the CPD header parser will check that the CPD header fits */
579+
if (layout->boot1.size < min_size) {
580+
xe_gt_err(gt, "GSC FW boot section too small for CPD offset: %u < %zu\n",
581+
layout->boot1.size, min_size);
582+
return -ENODATA;
583+
}
584+
585+
return parse_cpd_header(uc_fw,
586+
(void *)bpdt_header + min_size,
587+
layout->boot1.size - min_size,
588+
"RBEP.man", NULL);
589+
}
590+
591+
xe_gt_err(gt, "couldn't find CPD header in GSC binary!\n");
592+
return -ENODATA;
593+
}
594+
520595
static int parse_headers(struct xe_uc_fw *uc_fw, const struct firmware *fw)
521596
{
522597
int ret;
@@ -526,6 +601,8 @@ static int parse_headers(struct xe_uc_fw *uc_fw, const struct firmware *fw)
526601
* releases use GSC CPD headers.
527602
*/
528603
switch (uc_fw->type) {
604+
case XE_UC_FW_TYPE_GSC:
605+
return parse_gsc_layout(uc_fw, fw->data, fw->size);
529606
case XE_UC_FW_TYPE_HUC:
530607
ret = parse_cpd_header(uc_fw, fw->data, fw->size, "HUCP.man", "huc_fw");
531608
if (!ret || ret != -ENOENT)

drivers/gpu/drm/xe/xe_uc_fw_abi.h

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,58 @@ static_assert(sizeof(struct uc_css_header) == 128);
140140
* | RSA Key (MTL+ only) |
141141
* | ... |
142142
* +================================================+
143+
*
144+
* The GSC binary starts instead with a layout header, which contains the
145+
* locations of the various partitions of the binary. The one we're interested
146+
* in is the boot1 partition, where we can find a BPDT header followed by
147+
* entries, one of which points to the RBE sub-section of the partition, which
148+
* contains the CPD. The GSC blob does not contain a CSS-based binary, so we
149+
* only need to look for the manifest, which is under the "RBEP.man" CPD entry.
150+
* Note that we have no need to find where the actual FW code is inside the
151+
* image because the GSC ROM will itself parse the headers to find it and load
152+
* it.
153+
* The GSC firmware header layout looks like this::
154+
*
155+
* +================================================+
156+
* | Layout Pointers |
157+
* | ... |
158+
* | Boot1 offset >---------------------------|------o
159+
* | ... | |
160+
* +================================================+ |
161+
* |
162+
* +================================================+ |
163+
* | BPDT header |<-----o
164+
* +================================================+
165+
* | BPDT entries[] |
166+
* | entry1 |
167+
* | ... |
168+
* | entryX |
169+
* | type == GSC_RBE |
170+
* | offset >-----------------------------|------o
171+
* | ... | |
172+
* +================================================+ |
173+
* |
174+
* +================================================+ |
175+
* | CPD Header |<-----o
176+
* +================================================+
177+
* | CPD entries[] |
178+
* | entry1 |
179+
* | ... |
180+
* | entryX |
181+
* | "RBEP.man" |
182+
* | ... |
183+
* | offset >----------------------------|------o
184+
* | ... | |
185+
* +================================================+ |
186+
* |
187+
* +================================================+ |
188+
* | Manifest Header |<-----o
189+
* | ... |
190+
* | FW version |
191+
* | ... |
192+
* | Security version |
193+
* | ... |
194+
* +================================================+
143195
*/
144196

145197
struct gsc_version {
@@ -149,6 +201,67 @@ struct gsc_version {
149201
u16 build;
150202
} __packed;
151203

204+
struct gsc_partition {
205+
u32 offset;
206+
u32 size;
207+
} __packed;
208+
209+
struct gsc_layout_pointers {
210+
u8 rom_bypass_vector[16];
211+
212+
/* size of this header section, not including ROM bypass vector */
213+
u16 size;
214+
215+
/*
216+
* bit0: Backup copy of layout pointers exists
217+
* bits1-15: reserved
218+
*/
219+
u8 flags;
220+
221+
u8 reserved;
222+
223+
u32 crc32;
224+
225+
struct gsc_partition datap;
226+
struct gsc_partition boot1;
227+
struct gsc_partition boot2;
228+
struct gsc_partition boot3;
229+
struct gsc_partition boot4;
230+
struct gsc_partition boot5;
231+
struct gsc_partition temp_pages;
232+
} __packed;
233+
234+
/* Boot partition structures */
235+
struct gsc_bpdt_header {
236+
u32 signature;
237+
#define GSC_BPDT_HEADER_SIGNATURE 0x000055AA
238+
239+
u16 descriptor_count; /* num of entries after the header */
240+
241+
u8 version;
242+
u8 configuration;
243+
244+
u32 crc32;
245+
246+
u32 build_version;
247+
struct gsc_version tool_version;
248+
} __packed;
249+
250+
struct gsc_bpdt_entry {
251+
/*
252+
* Bits 0-15: BPDT entry type
253+
* Bits 16-17: reserved
254+
* Bit 18: code sub-partition
255+
* Bits 19-31: reserved
256+
*/
257+
u32 type;
258+
#define GSC_BPDT_ENTRY_TYPE_MASK GENMASK(15, 0)
259+
#define GSC_BPDT_ENTRY_TYPE_GSC_RBE 0x1
260+
261+
u32 sub_partition_offset; /* from the base of the BPDT header */
262+
u32 sub_partition_size;
263+
} __packed;
264+
152265
/* Code partition directory (CPD) structures */
153266
struct gsc_cpd_header_v2 {
154267
u32 header_marker;

0 commit comments

Comments
 (0)