+ return -EINVAL;
+ }
+
+ if (size < sizeof(*header)) {
+ huc_err(huc, "MEU FW too small! %zu < %zu\n", size, min_size);
+ return -ENODATA;
+ }
+
+ /*
+ * The meu HuC binary starts with a directory header, followed by a
+ * series of entries. Each entry is identified by a name and
points to
+ * a specific section of the binary containing the relevant data.
+ * The entries we're interested in are
+ * - "HUCP.man": points to the GSC manifest header for the HuC,
which
+ * contains the version info.
+ * - "huc_fw": points to the legacy-style binary that can be
used for
+ * load via the DMA. This entry only contains a
valid CSS
+ * on binaries for platforms that support 2-step HuC
load
+ * via dma and auth via GSC (like MTL).
+ *
+ * --------------------------------------------------
+ * [ intel_gsc_cpd_header_v2 ]
+ * --------------------------------------------------
+ * [ intel_gsc_cpd_entry[] ]
+ * [ entry1 ]
+ * [ ... ]
+ * [ entryX ]
+ * [ "HUCP.man" ]
+ * [ ... ]
+ * [ offset >----------------------------]------o
+ * [ ... ] |
+ * [ entryY ] |
+ * [ "huc_fw" ] |
+ * [ ... ] |
+ * [ offset >----------------------------]----------o
+ * -------------------------------------------------- | |
+ * | |
+ * -------------------------------------------------- | |
+ * [ intel_gsc_manifest_header ]<-----o |
+ * [ ... ] |
+ * [ intel_gsc_meu_version fw_version ] |
+ * [ ... ] |
+ * -------------------------------------------------- |
+ * |
+ * -------------------------------------------------- |
+ * [ data[] ]<---------o
+ * [ ... ]
+ * [ ... ]
+ * --------------------------------------------------
+ */
+
+ if (header->header_marker != INTEL_GSC_CPD_HEADER_MARKER) {
+ huc_err(huc, "invalid marker for meu CPD header: 0x%08x!\n",
+ header->header_marker);
+ return -EINVAL;
+ }
+
+ /* we only have binaries with header v2 and entry v1 for now */
+ if (header->header_version != 2 || header->entry_version != 1) {
+ huc_err(huc, "invalid meu CPD header/entry version %u:%u!\n",
+ header->header_version, header->entry_version);
+ return -EINVAL;
+ }
+
+ if (header->header_length < sizeof(struct
intel_gsc_cpd_header_v2)) {
+ huc_err(huc, "invalid meu CPD header length %u!\n",
+ header->header_length);
+ return -EINVAL;
+ }
+
+ min_size = header->header_length + sizeof(*entry) *
header->num_of_entries;
+ if (size < min_size) {
+ huc_err(huc, "MEU FW too small! %zu < %zu\n", size, min_size);
+ return -ENODATA;
+ }
+
+ entry = data + header->header_length;
+
+ for (i = 0; i < header->num_of_entries; i++, entry++) {
+ if (strcmp(entry->name, "HUCP.man") == 0)
+ get_version_from_meu_manifest(&huc_fw->file_selected.ver,
+ data + entry_offset(entry));
+
+ if (strcmp(entry->name, "huc_fw") == 0) {
+ u32 offset = entry_offset(entry);
+ if (offset < size && css_valid(data + offset, size -
offset))
+ huc_fw->dma_start_offset = offset;
+ }
+ }
+
+ return 0;
+}
+
int intel_huc_fw_load_and_auth_via_gsc(struct intel_huc *huc)
{
int ret;
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_huc_fw.h
b/drivers/gpu/drm/i915/gt/uc/intel_huc_fw.h
index db42e238b45f..0999ffe6f962 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_huc_fw.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_huc_fw.h
@@ -7,8 +7,11 @@
#define _INTEL_HUC_FW_H_
struct intel_huc;
+struct intel_uc_fw;
+
+#include <linux/types.h>
int intel_huc_fw_load_and_auth_via_gsc(struct intel_huc *huc);
int intel_huc_fw_upload(struct intel_huc *huc);
-
+int intel_huc_fw_get_binary_info(struct intel_uc_fw *huc_fw, const
void *data, size_t size);
#endif
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_huc_print.h
b/drivers/gpu/drm/i915/gt/uc/intel_huc_print.h
new file mode 100644
index 000000000000..915d310ee1df
--- /dev/null
+++ b/drivers/gpu/drm/i915/gt/uc/intel_huc_print.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#ifndef __INTEL_HUC_PRINT__
+#define __INTEL_HUC_PRINT__
+
+#include "gt/intel_gt.h"
+#include "gt/intel_gt_print.h"
+
+#define huc_printk(_huc, _level, _fmt, ...) \
+ gt_##_level(huc_to_gt(_huc), "HuC: " _fmt, ##__VA_ARGS__)
+#define huc_err(_huc, _fmt, ...) huc_printk((_huc), err, _fmt,
##__VA_ARGS__)
+#define huc_warn(_huc, _fmt, ...) huc_printk((_huc), warn, _fmt,
##__VA_ARGS__)
+#define huc_notice(_huc, _fmt, ...) huc_printk((_huc), notice,
_fmt, ##__VA_ARGS__)
+#define huc_info(_huc, _fmt, ...) huc_printk((_huc), info, _fmt,
##__VA_ARGS__)
+#define huc_dbg(_huc, _fmt, ...) huc_printk((_huc), dbg, _fmt,
##__VA_ARGS__)
+#define huc_probe_error(_huc, _fmt, ...) huc_printk((_huc),
probe_error, _fmt, ##__VA_ARGS__)
+
+#endif /* __INTEL_HUC_PRINT__ */
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c
b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c
index 03f0b258aea7..da6fcfe1d80a 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c
@@ -492,33 +492,6 @@ static void __force_fw_fetch_failures(struct
intel_uc_fw *uc_fw, int e)
}
}
-static int check_gsc_manifest(struct intel_gt *gt,
- const struct firmware *fw,
- struct intel_uc_fw *uc_fw)
-{
- u32 *dw = (u32 *)fw->data;
- u32 version_hi, version_lo;
- size_t min_size;
-
- /* Check the size of the blob before examining buffer contents */
- min_size = sizeof(u32) * (HUC_GSC_VERSION_LO_DW + 1);
- if (unlikely(fw->size < min_size)) {
- gt_warn(gt, "%s firmware %s: invalid size: %zu < %zu\n",
- intel_uc_fw_type_repr(uc_fw->type),
uc_fw->file_selected.path,
- fw->size, min_size);
- return -ENODATA;
- }
-
- version_hi = dw[HUC_GSC_VERSION_HI_DW];
- version_lo = dw[HUC_GSC_VERSION_LO_DW];
-
- uc_fw->file_selected.ver.major =
FIELD_GET(HUC_GSC_MAJOR_VER_HI_MASK, version_hi);
- uc_fw->file_selected.ver.minor =
FIELD_GET(HUC_GSC_MINOR_VER_HI_MASK, version_hi);
- uc_fw->file_selected.ver.patch =
FIELD_GET(HUC_GSC_PATCH_VER_LO_MASK, version_lo);
-
- return 0;
-}
-
static void uc_unpack_css_version(struct intel_uc_fw_ver *ver, u32
css_value)
{
/* Get version numbers from the CSS header */
@@ -575,22 +548,22 @@ static void guc_read_css_info(struct
intel_uc_fw *uc_fw, struct uc_css_header *c
uc_fw->private_data_size = css->private_data_size;
}
-static int check_ccs_header(struct intel_gt *gt,
- const struct firmware *fw,
- struct intel_uc_fw *uc_fw)
+static int __check_ccs_header(struct intel_gt *gt,
+ const void *fw_data, size_t fw_size,
+ struct intel_uc_fw *uc_fw)
{
struct uc_css_header *css;
size_t size;
/* Check the size of the blob before examining buffer
contents */
- if (unlikely(fw->size < sizeof(struct uc_css_header))) {
+ if (unlikely(fw_size < sizeof(struct uc_css_header))) {
gt_warn(gt, "%s firmware %s: invalid size: %zu < %zu\n",
intel_uc_fw_type_repr(uc_fw->type),
uc_fw->file_selected.path,
- fw->size, sizeof(struct uc_css_header));
+ fw_size, sizeof(struct uc_css_header));
return -ENODATA;
}
- css = (struct uc_css_header *)fw->data;
+ css = (struct uc_css_header *)fw_data;
/* Check integrity of size values inside CSS header */
size = (css->header_size_dw - css->key_size_dw -
css->modulus_size_dw -
@@ -598,7 +571,7 @@ static int check_ccs_header(struct intel_gt *gt,
if (unlikely(size != sizeof(struct uc_css_header))) {
gt_warn(gt, "%s firmware %s: unexpected header size: %zu !=
%zu\n",
intel_uc_fw_type_repr(uc_fw->type),
uc_fw->file_selected.path,
- fw->size, sizeof(struct uc_css_header));
+ fw_size, sizeof(struct uc_css_header));
return -EPROTO;
}
@@ -610,10 +583,10 @@ static int check_ccs_header(struct intel_gt *gt,
/* At least, it should have header, uCode and RSA. Size of
all three. */
size = sizeof(struct uc_css_header) + uc_fw->ucode_size +
uc_fw->rsa_size;
- if (unlikely(fw->size < size)) {
+ if (unlikely(fw_size < size)) {
gt_warn(gt, "%s firmware %s: invalid size: %zu < %zu\n",
intel_uc_fw_type_repr(uc_fw->type),
uc_fw->file_selected.path,
- fw->size, size);
+ fw_size, size);
return -ENOEXEC;
}
@@ -634,6 +607,32 @@ static int check_ccs_header(struct intel_gt *gt,
return 0;
}
+static int check_gsc_manifest(struct intel_gt *gt,
+ const struct firmware *fw,
+ struct intel_uc_fw *uc_fw)
+{
+ if (uc_fw->type != INTEL_UC_FW_TYPE_HUC) {
+ gt_err(gt, "trying to MEU-parse a non-HuC binary");
+ return -EINVAL;
+ }
+
+ intel_huc_fw_get_binary_info(uc_fw, fw->data, fw->size);
+
+ if (uc_fw->dma_start_offset) {
+ u32 delta = uc_fw->dma_start_offset;
+ __check_ccs_header(gt, fw->data + delta, fw->size - delta,
uc_fw);
+ }
+
+ return 0;
+}
+
+static int check_ccs_header(struct intel_gt *gt,
+ const struct firmware *fw,
+ struct intel_uc_fw *uc_fw)
+{
+ return __check_ccs_header(gt, fw->data, fw->size, uc_fw);
+}
+
static bool is_ver_8bit(struct intel_uc_fw_ver *ver)
{
return ver->major < 0xFF && ver->minor < 0xFF && ver->patch <
0xFF;
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h
b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h
index 26a9d6e0dc00..2691bb6bde48 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h
@@ -113,6 +113,8 @@ struct intel_uc_fw {
u32 ucode_size;
u32 private_data_size;
+ u32 dma_start_offset;
+
bool loaded_via_gsc;
};
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw_abi.h
b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw_abi.h
index 646fa8aa6cf1..7fe405126249 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw_abi.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw_abi.h
@@ -84,10 +84,4 @@ struct uc_css_header {
} __packed;
static_assert(sizeof(struct uc_css_header) == 128);
-#define HUC_GSC_VERSION_HI_DW 44
-#define HUC_GSC_MAJOR_VER_HI_MASK (0xFF << 0)
-#define HUC_GSC_MINOR_VER_HI_MASK (0xFF << 16)
-#define HUC_GSC_VERSION_LO_DW 45
-#define HUC_GSC_PATCH_VER_LO_MASK (0xFF << 0)
-
#endif /* _INTEL_UC_FW_ABI_H */